Merge pull request #485 from GriffinRichards/metatile-attr
Allow reorganization of metatile attributes
This commit is contained in:
commit
ab6d035ad8
16 changed files with 389 additions and 188 deletions
|
@ -8,6 +8,7 @@ The **"Breaking Changes"** listed below are changes that have been made in the d
|
|||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- Add new config options for reorganizing metatile attributes.
|
||||
- Add `setScale` to the scripting API.
|
||||
- Add option to turn off the checkerboard fill for new tilesets.
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ your project root as ``porymap.user.cfg``. You should add this file to your giti
|
|||
``enable_hidden_item_requires_itemfinder``, 1 if ``pokefirered``, project, yes, Adds ``Requires Itemfinder`` to Hidden Item events
|
||||
``enable_heal_location_respawn_data``, 1 if ``pokefirered``, project, yes, Adds ``Respawn Map`` and ``Respawn NPC`` to Heal Location events
|
||||
``enable_floor_number``, 1 if ``pokefirered``, project, yes, Adds ``Floor Number`` to map headers
|
||||
``enable_map_allow_flags``, 1 if not ``pokeruby``, project, yes, "Adds ``Allow Running``, ``Allow Biking``, and ``Allow Dig & Escape Rope`` to map headers"
|
||||
``create_map_text_file``, 1 if not ``pokeemerald``, project, yes, A ``text.inc`` or ``text.pory`` file will be created for any new map
|
||||
``enable_triple_layer_metatiles``, 0, project, yes, Enables triple-layer metatiles (See https://github.com/pret/pokeemerald/wiki/Triple-layer-metatiles)
|
||||
``new_map_metatile``, 1, project, yes, The metatile id that will be used to fill new maps
|
||||
|
@ -60,5 +61,10 @@ your project root as ``porymap.user.cfg``. You should add this file to your giti
|
|||
``prefabs_import_prompted``, 0, project, no, Keeps track of whether or not the project was prompted for importing default prefabs
|
||||
``tilesets_have_callback``, 1, project, yes, Whether new tileset headers should have the ``callback`` field
|
||||
``tilesets_have_is_compressed``, 1, project, yes, Whether new tileset headers should have the ``isCompressed`` field
|
||||
``metatile_attributes_size``, 2 or 4, project, yes, The number of attribute bytes each metatile has
|
||||
``metatile_behavior_mask``, ``0xFF`` or ``0x1FF``, project, yes, The mask for the metatile Behavior attribute
|
||||
``metatile_encounter_type_mask``, ``0x0`` or ``0x7000000``, project, yes, The mask for the metatile Encounter Type attribute
|
||||
``metatile_layer_type_mask``, ``0xF000`` or ``0x60000000``, project, yes, The mask for the metatile Layer Type attribute
|
||||
``metatile_terrain_type_mask``, ``0x0`` or ``0x3E00``, project, yes, The mask for the metatile Terrain Type attribute
|
||||
|
||||
Some of these settings can be toggled manually in porymap via the *Options* menu.
|
||||
|
|
|
@ -36,6 +36,7 @@ protected:
|
|||
virtual void setUnreadKeys() = 0;
|
||||
bool getConfigBool(QString key, QString value);
|
||||
int getConfigInteger(QString key, QString value, int min, int max, int defaultValue);
|
||||
long getConfigLong(QString key, QString value, long min, long max, long defaultValue);
|
||||
};
|
||||
|
||||
class PorymapConfig: public KeyValueConfigBase
|
||||
|
@ -268,6 +269,12 @@ public:
|
|||
bool getTilesetsHaveCallback();
|
||||
void setTilesetsHaveIsCompressed(bool has);
|
||||
bool getTilesetsHaveIsCompressed();
|
||||
int getMetatileAttributesSize();
|
||||
uint32_t getMetatileBehaviorMask();
|
||||
uint32_t getMetatileTerrainTypeMask();
|
||||
uint32_t getMetatileEncounterTypeMask();
|
||||
uint32_t getMetatileLayerTypeMask();
|
||||
bool getMapAllowFlagsEnabled();
|
||||
protected:
|
||||
virtual QString getConfigFilepath() override;
|
||||
virtual void parseConfigKeyValue(QString key, QString value) override;
|
||||
|
@ -299,6 +306,12 @@ private:
|
|||
bool prefabImportPrompted;
|
||||
bool tilesetsHaveCallback;
|
||||
bool tilesetsHaveIsCompressed;
|
||||
int metatileAttributesSize;
|
||||
uint32_t metatileBehaviorMask;
|
||||
uint32_t metatileTerrainTypeMask;
|
||||
uint32_t metatileEncounterTypeMask;
|
||||
uint32_t metatileLayerTypeMask;
|
||||
bool enableMapAllowFlags;
|
||||
};
|
||||
|
||||
extern ProjectConfig projectConfig;
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include <QPoint>
|
||||
#include <QString>
|
||||
|
||||
class Project;
|
||||
|
||||
enum {
|
||||
METATILE_LAYER_MIDDLE_TOP,
|
||||
METATILE_LAYER_BOTTOM_MIDDLE,
|
||||
|
@ -30,6 +32,29 @@ enum {
|
|||
NUM_METATILE_TERRAIN_TYPES
|
||||
};
|
||||
|
||||
class MetatileAttr
|
||||
{
|
||||
public:
|
||||
MetatileAttr();
|
||||
MetatileAttr(uint32_t mask, int shift);
|
||||
|
||||
public:
|
||||
uint32_t mask;
|
||||
int shift;
|
||||
|
||||
// Given the raw value for all attributes of a metatile
|
||||
// Returns the extracted value for this attribute
|
||||
uint32_t fromRaw(uint32_t raw) const { return (raw & this->mask) >> this->shift; }
|
||||
|
||||
// Given a value for this attribute
|
||||
// Returns the raw value to OR together with the other attributes
|
||||
uint32_t toRaw(uint32_t value) const { return (value << this->shift) & this->mask; }
|
||||
|
||||
// Given an arbitrary value to set for an attribute
|
||||
// Returns a bounded value for that attribute
|
||||
uint32_t getClamped(int value) const { return static_cast<uint32_t>(value) & (this->mask >> this->shift); }
|
||||
};
|
||||
|
||||
class Metatile
|
||||
{
|
||||
public:
|
||||
|
@ -40,19 +65,54 @@ public:
|
|||
|
||||
public:
|
||||
QList<Tile> tiles;
|
||||
uint16_t behavior; // 8 bits RSE, 9 bits FRLG
|
||||
uint8_t layerType;
|
||||
uint8_t encounterType; // FRLG only
|
||||
uint8_t terrainType; // FRLG only
|
||||
uint32_t behavior;
|
||||
uint32_t terrainType;
|
||||
uint32_t encounterType;
|
||||
uint32_t layerType;
|
||||
uint32_t unusedAttributes;
|
||||
QString label;
|
||||
|
||||
uint32_t getAttributes();
|
||||
void setAttributes(uint32_t data);
|
||||
void setAttributes(uint32_t data, BaseGameVersion version);
|
||||
uint32_t getAttributes(BaseGameVersion version);
|
||||
|
||||
void setBehavior(int value) { this->behavior = behaviorAttr.getClamped(value); }
|
||||
void setTerrainType(int value) { this->terrainType = terrainTypeAttr.getClamped(value); }
|
||||
void setEncounterType(int value) { this->encounterType = encounterTypeAttr.getClamped(value); }
|
||||
void setLayerType(int value) { this->layerType = layerTypeAttr.getClamped(value); }
|
||||
|
||||
static uint32_t getBehaviorMask() { return behaviorAttr.mask; }
|
||||
static uint32_t getTerrainTypeMask() { return terrainTypeAttr.mask; }
|
||||
static uint32_t getEncounterTypeMask() { return encounterTypeAttr.mask; }
|
||||
static uint32_t getLayerTypeMask() { return layerTypeAttr.mask; }
|
||||
static uint32_t getBehaviorMask(BaseGameVersion version);
|
||||
static uint32_t getTerrainTypeMask(BaseGameVersion version);
|
||||
static uint32_t getEncounterTypeMask(BaseGameVersion version);
|
||||
static uint32_t getLayerTypeMask(BaseGameVersion version);
|
||||
|
||||
static int getIndexInTileset(int);
|
||||
static QPoint coordFromPixmapCoord(const QPointF &pixelCoord);
|
||||
static int getAttributesSize(BaseGameVersion version);
|
||||
static int getDefaultAttributesSize(BaseGameVersion version);
|
||||
static void setCustomLayout(Project*);
|
||||
|
||||
private:
|
||||
// Stores how each attribute should be laid out for all metatiles, according to the user's config
|
||||
static MetatileAttr behaviorAttr;
|
||||
static MetatileAttr terrainTypeAttr;
|
||||
static MetatileAttr encounterTypeAttr;
|
||||
static MetatileAttr layerTypeAttr;
|
||||
|
||||
static uint32_t unusedAttrMask;
|
||||
|
||||
// Stores how each attribute should be laid out for all metatiles, according to the vanilla games
|
||||
// Used to set default config values and import maps with AdvanceMap
|
||||
static const QHash<QString, MetatileAttr> defaultLayoutFRLG;
|
||||
static const QHash<QString, MetatileAttr> defaultLayoutRSE;
|
||||
static const QHash<BaseGameVersion, const QHash<QString, MetatileAttr>*> defaultLayouts;
|
||||
|
||||
static void setCustomAttributeLayout(MetatileAttr *, uint32_t, uint32_t);
|
||||
static bool isMaskTooSmall(MetatileAttr *, int);
|
||||
static bool doMasksOverlap(QList<uint32_t>);
|
||||
};
|
||||
|
||||
inline bool operator==(const Metatile &a, const Metatile &b) {
|
||||
|
|
|
@ -231,7 +231,6 @@ public:
|
|||
private:
|
||||
void updateMapLayout(Map*);
|
||||
|
||||
void setNewMapHeader(Map* map, int mapIndex);
|
||||
void setNewMapBlockdata(Map* map);
|
||||
void setNewMapBorder(Map *map);
|
||||
void setNewMapEvents(Map *map);
|
||||
|
|
|
@ -111,9 +111,7 @@ private slots:
|
|||
|
||||
private:
|
||||
void initUi();
|
||||
void setMetatileBehaviors();
|
||||
void setMetatileLayersUi();
|
||||
void setVersionSpecificUi();
|
||||
void setAttributesUi();
|
||||
void setMetatileLabelValidator();
|
||||
void initMetatileSelector();
|
||||
void initTileSelector();
|
||||
|
|
|
@ -136,7 +136,7 @@ void KeyValueConfigBase::save() {
|
|||
|
||||
bool KeyValueConfigBase::getConfigBool(QString key, QString value) {
|
||||
bool ok;
|
||||
int result = value.toInt(&ok);
|
||||
int result = value.toInt(&ok, 0);
|
||||
if (!ok || (result != 0 && result != 1)) {
|
||||
logWarn(QString("Invalid config value for %1: '%2'. Must be 0 or 1.").arg(key).arg(value));
|
||||
}
|
||||
|
@ -145,7 +145,17 @@ bool KeyValueConfigBase::getConfigBool(QString key, QString value) {
|
|||
|
||||
int KeyValueConfigBase::getConfigInteger(QString key, QString value, int min, int max, int defaultValue) {
|
||||
bool ok;
|
||||
int result = value.toInt(&ok);
|
||||
int result = value.toInt(&ok, 0);
|
||||
if (!ok) {
|
||||
logWarn(QString("Invalid config value for %1: '%2'. Must be an integer.").arg(key).arg(value));
|
||||
return defaultValue;
|
||||
}
|
||||
return qMin(max, qMax(min, result));
|
||||
}
|
||||
|
||||
long KeyValueConfigBase::getConfigLong(QString key, QString value, long min, long max, long defaultValue) {
|
||||
bool ok;
|
||||
long result = value.toLong(&ok, 0);
|
||||
if (!ok) {
|
||||
logWarn(QString("Invalid config value for %1: '%2'. Must be an integer.").arg(key).arg(value));
|
||||
return defaultValue;
|
||||
|
@ -561,6 +571,23 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) {
|
|||
this->defaultPrimaryTileset = value;
|
||||
} else if (key == "default_secondary_tileset") {
|
||||
this->defaultSecondaryTileset = value;
|
||||
} else if (key == "metatile_attributes_size") {
|
||||
int size = getConfigInteger(key, value, 1, 4, 2);
|
||||
if (size & (size - 1)) {
|
||||
logWarn(QString("Invalid config value for %1: must be 1, 2, or 4").arg(key));
|
||||
return; // Don't set a default now, it will be set later based on the base game version
|
||||
}
|
||||
this->metatileAttributesSize = size;
|
||||
} else if (key == "metatile_behavior_mask") {
|
||||
this->metatileBehaviorMask = getConfigLong(key, value, 0, 0xFFFFFFFF, 0);
|
||||
} else if (key == "metatile_terrain_type_mask") {
|
||||
this->metatileTerrainTypeMask = getConfigLong(key, value, 0, 0xFFFFFFFF, 0);
|
||||
} else if (key == "metatile_encounter_type_mask") {
|
||||
this->metatileEncounterTypeMask = getConfigLong(key, value, 0, 0xFFFFFFFF, 0);
|
||||
} else if (key == "metatile_layer_type_mask") {
|
||||
this->metatileLayerTypeMask = getConfigLong(key, value, 0, 0xFFFFFFFF, 0);
|
||||
} else if (key == "enable_map_allow_flags") {
|
||||
this->enableMapAllowFlags = getConfigBool(key, value);
|
||||
#ifdef CONFIG_BACKWARDS_COMPATABILITY
|
||||
} else if (key == "recent_map") {
|
||||
userConfig.setRecentMap(value);
|
||||
|
@ -611,6 +638,12 @@ void ProjectConfig::setUnreadKeys() {
|
|||
if (!readKeys.contains("create_map_text_file")) this->createMapTextFile = (this->baseGameVersion != BaseGameVersion::pokeemerald);
|
||||
if (!readKeys.contains("new_map_border_metatiles")) this->newMapBorderMetatileIds = isPokefirered ? DEFAULT_BORDER_FRLG : DEFAULT_BORDER_RSE;
|
||||
if (!readKeys.contains("default_secondary_tileset")) this->defaultSecondaryTileset = isPokefirered ? "gTileset_PalletTown" : "gTileset_Petalburg";
|
||||
if (!readKeys.contains("metatile_attributes_size")) this->metatileAttributesSize = Metatile::getDefaultAttributesSize(this->baseGameVersion);
|
||||
if (!readKeys.contains("metatile_behavior_mask")) this->metatileBehaviorMask = Metatile::getBehaviorMask(this->baseGameVersion);
|
||||
if (!readKeys.contains("metatile_terrain_type_mask")) this->metatileTerrainTypeMask = Metatile::getTerrainTypeMask(this->baseGameVersion);
|
||||
if (!readKeys.contains("metatile_encounter_type_mask")) this->metatileEncounterTypeMask = Metatile::getEncounterTypeMask(this->baseGameVersion);
|
||||
if (!readKeys.contains("metatile_layer_type_mask")) this-> metatileLayerTypeMask = Metatile::getLayerTypeMask(this->baseGameVersion);
|
||||
if (!readKeys.contains("enable_map_allow_flags")) this->enableMapAllowFlags = (this->baseGameVersion != BaseGameVersion::pokeruby);
|
||||
}
|
||||
|
||||
QMap<QString, QString> ProjectConfig::getKeyValueMap() {
|
||||
|
@ -642,6 +675,12 @@ QMap<QString, QString> ProjectConfig::getKeyValueMap() {
|
|||
}
|
||||
map.insert("tilesets_have_callback", QString::number(this->tilesetsHaveCallback));
|
||||
map.insert("tilesets_have_is_compressed", QString::number(this->tilesetsHaveIsCompressed));
|
||||
map.insert("metatile_attributes_size", QString::number(this->metatileAttributesSize));
|
||||
map.insert("metatile_behavior_mask", "0x" + QString::number(this->metatileBehaviorMask, 16).toUpper());
|
||||
map.insert("metatile_terrain_type_mask", "0x" + QString::number(this->metatileTerrainTypeMask, 16).toUpper());
|
||||
map.insert("metatile_encounter_type_mask", "0x" + QString::number(this->metatileEncounterTypeMask, 16).toUpper());
|
||||
map.insert("metatile_layer_type_mask", "0x" + QString::number(this->metatileLayerTypeMask, 16).toUpper());
|
||||
map.insert("enable_map_allow_flags", QString::number(this->enableMapAllowFlags));
|
||||
return map;
|
||||
}
|
||||
|
||||
|
@ -891,6 +930,30 @@ bool ProjectConfig::getTilesetsHaveIsCompressed() {
|
|||
return this->tilesetsHaveIsCompressed;
|
||||
}
|
||||
|
||||
int ProjectConfig::getMetatileAttributesSize() {
|
||||
return this->metatileAttributesSize;
|
||||
}
|
||||
|
||||
uint32_t ProjectConfig::getMetatileBehaviorMask() {
|
||||
return this->metatileBehaviorMask;
|
||||
}
|
||||
|
||||
uint32_t ProjectConfig::getMetatileTerrainTypeMask() {
|
||||
return this->metatileTerrainTypeMask;
|
||||
}
|
||||
|
||||
uint32_t ProjectConfig::getMetatileEncounterTypeMask() {
|
||||
return this->metatileEncounterTypeMask;
|
||||
}
|
||||
|
||||
uint32_t ProjectConfig::getMetatileLayerTypeMask() {
|
||||
return this->metatileLayerTypeMask;
|
||||
}
|
||||
|
||||
bool ProjectConfig::getMapAllowFlagsEnabled() {
|
||||
return this->enableMapAllowFlags;
|
||||
}
|
||||
|
||||
|
||||
UserConfig userConfig;
|
||||
|
||||
|
|
|
@ -2,19 +2,56 @@
|
|||
#include "tileset.h"
|
||||
#include "project.h"
|
||||
|
||||
const QHash<QString, MetatileAttr> Metatile::defaultLayoutFRLG = {
|
||||
{"behavior", MetatileAttr(0x000001FF, 0) },
|
||||
{"terrainType", MetatileAttr(0x00003E00, 9) },
|
||||
{"encounterType", MetatileAttr(0x07000000, 24) },
|
||||
{"layerType", MetatileAttr(0x60000000, 29) },
|
||||
};
|
||||
|
||||
const QHash<QString, MetatileAttr> Metatile::defaultLayoutRSE = {
|
||||
{"behavior", MetatileAttr(0x00FF, 0) },
|
||||
{"terrainType", MetatileAttr() },
|
||||
{"encounterType", MetatileAttr() },
|
||||
{"layerType", MetatileAttr(0xF000, 12) },
|
||||
};
|
||||
|
||||
const QHash<BaseGameVersion, const QHash<QString, MetatileAttr>*> Metatile::defaultLayouts = {
|
||||
{ BaseGameVersion::pokeruby, &defaultLayoutRSE },
|
||||
{ BaseGameVersion::pokefirered, &defaultLayoutFRLG },
|
||||
{ BaseGameVersion::pokeemerald, &defaultLayoutRSE },
|
||||
};
|
||||
|
||||
MetatileAttr Metatile::behaviorAttr;
|
||||
MetatileAttr Metatile::terrainTypeAttr;
|
||||
MetatileAttr Metatile::encounterTypeAttr;
|
||||
MetatileAttr Metatile::layerTypeAttr;
|
||||
|
||||
uint32_t Metatile::unusedAttrMask = 0;
|
||||
|
||||
MetatileAttr::MetatileAttr() :
|
||||
mask(0),
|
||||
shift(0)
|
||||
{ }
|
||||
|
||||
MetatileAttr::MetatileAttr(uint32_t mask, int shift) :
|
||||
mask(mask),
|
||||
shift(shift)
|
||||
{ }
|
||||
|
||||
Metatile::Metatile() :
|
||||
behavior(0),
|
||||
layerType(0),
|
||||
encounterType(0),
|
||||
terrainType(0),
|
||||
encounterType(0),
|
||||
layerType(0),
|
||||
unusedAttributes(0)
|
||||
{ }
|
||||
|
||||
Metatile::Metatile(const int numTiles) :
|
||||
behavior(0),
|
||||
layerType(0),
|
||||
encounterType(0),
|
||||
terrainType(0),
|
||||
encounterType(0),
|
||||
layerType(0),
|
||||
unusedAttributes(0)
|
||||
{
|
||||
Tile tile = Tile();
|
||||
|
@ -37,50 +74,120 @@ QPoint Metatile::coordFromPixmapCoord(const QPointF &pixelCoord) {
|
|||
return QPoint(x, y);
|
||||
}
|
||||
|
||||
int Metatile::getAttributesSize(BaseGameVersion version) {
|
||||
return (version == BaseGameVersion::pokefirered) ? 4 : 2;
|
||||
// Set the layout of a metatile attribute using the mask read from the config file
|
||||
void Metatile::setCustomAttributeLayout(MetatileAttr * attr, uint32_t mask, uint32_t max) {
|
||||
if (mask > max) {
|
||||
uint32_t oldMask = mask;
|
||||
mask &= max;
|
||||
logWarn(QString("Metatile attribute mask '0x%1' has been truncated to '0x%2'")
|
||||
.arg(QString::number(oldMask, 16).toUpper())
|
||||
.arg(QString::number(mask, 16).toUpper()));
|
||||
}
|
||||
attr->mask = mask;
|
||||
attr->shift = mask ? log2(mask & ~(mask - 1)) : 0; // Get position of the least significant set bit
|
||||
}
|
||||
|
||||
// RSE attributes
|
||||
const uint16_t behaviorMask_RSE = 0x00FF;
|
||||
const uint16_t layerTypeMask_RSE = 0xF000;
|
||||
const int behaviorShift_RSE = 0;
|
||||
const int layerTypeShift_RSE = 12;
|
||||
// For checking whether a metatile attribute mask can contain all the available hard-coded options
|
||||
bool Metatile::isMaskTooSmall(MetatileAttr * attr, int max) {
|
||||
if (attr->mask == 0 || max <= 0) return false;
|
||||
|
||||
// FRLG attributes
|
||||
const uint32_t behaviorMask_FRLG = 0x000001FF;
|
||||
const uint32_t terrainTypeMask = 0x00003E00;
|
||||
const uint32_t encounterTypeMask = 0x07000000;
|
||||
const uint32_t layerTypeMask_FRLG = 0x60000000;
|
||||
const int behaviorShift_FRLG = 0;
|
||||
const int terrainTypeShift = 9;
|
||||
const int encounterTypeShift = 24;
|
||||
const int layerTypeShift_FRLG = 29;
|
||||
// Get position of the most significant set bit
|
||||
uint32_t n = log2(max);
|
||||
|
||||
uint32_t Metatile::getAttributes(BaseGameVersion version) {
|
||||
uint32_t attributes = this->unusedAttributes;
|
||||
if (version == BaseGameVersion::pokefirered) {
|
||||
attributes |= (behavior << behaviorShift_FRLG) & behaviorMask_FRLG;
|
||||
attributes |= (terrainType << terrainTypeShift) & terrainTypeMask;
|
||||
attributes |= (encounterType << encounterTypeShift) & encounterTypeMask;
|
||||
attributes |= (layerType << layerTypeShift_FRLG) & layerTypeMask_FRLG;
|
||||
} else {
|
||||
attributes |= (behavior << behaviorShift_RSE) & behaviorMask_RSE;
|
||||
attributes |= (layerType << layerTypeShift_RSE) & layerTypeMask_RSE;
|
||||
// Get a mask for all values 0 to max.
|
||||
// This may fail for n > 30, but that's not possible here.
|
||||
uint32_t rangeMask = (1 << (n + 1)) - 1;
|
||||
|
||||
return attr->getClamped(rangeMask) != rangeMask;
|
||||
}
|
||||
|
||||
bool Metatile::doMasksOverlap(QList<uint32_t> masks) {
|
||||
for (int i = 0; i < masks.length(); i++)
|
||||
for (int j = i + 1; j < masks.length(); j++) {
|
||||
if (masks.at(i) & masks.at(j))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Metatile::setCustomLayout(Project * project) {
|
||||
// Get the maximum size of any attribute mask
|
||||
const QHash<int, uint32_t> maxMasks = {
|
||||
{1, 0xFF},
|
||||
{2, 0xFFFF},
|
||||
{4, 0xFFFFFFFF},
|
||||
};
|
||||
const uint32_t maxMask = maxMasks.value(projectConfig.getMetatileAttributesSize(), 0);
|
||||
|
||||
// Set custom attribute masks from the config file
|
||||
setCustomAttributeLayout(&Metatile::behaviorAttr, projectConfig.getMetatileBehaviorMask(), maxMask);
|
||||
setCustomAttributeLayout(&Metatile::terrainTypeAttr, projectConfig.getMetatileTerrainTypeMask(), maxMask);
|
||||
setCustomAttributeLayout(&Metatile::encounterTypeAttr, projectConfig.getMetatileEncounterTypeMask(), maxMask);
|
||||
setCustomAttributeLayout(&Metatile::layerTypeAttr, projectConfig.getMetatileLayerTypeMask(), maxMask);
|
||||
|
||||
// Set mask for preserving any attribute bits not used by Porymap
|
||||
Metatile::unusedAttrMask = ~(getBehaviorMask() | getTerrainTypeMask() | getEncounterTypeMask() | getLayerTypeMask());
|
||||
Metatile::unusedAttrMask &= maxMask;
|
||||
|
||||
// Overlapping masks are technically ok, but probably not intended.
|
||||
// Additionally, Porymap will not properly reflect that the values are linked.
|
||||
if (doMasksOverlap({getBehaviorMask(), getTerrainTypeMask(), getEncounterTypeMask(), getLayerTypeMask()})) {
|
||||
logWarn("Metatile attribute masks are overlapping. This may result in unexpected attribute values.");
|
||||
}
|
||||
|
||||
// Warn the user if they have set a nonzero mask that is too small to contain its available options.
|
||||
// They'll be allowed to select the options, but they'll be truncated to a different value when revisited.
|
||||
if (!project->metatileBehaviorMapInverse.isEmpty()) {
|
||||
int maxBehavior = project->metatileBehaviorMapInverse.lastKey();
|
||||
if (isMaskTooSmall(&Metatile::behaviorAttr, maxBehavior))
|
||||
logWarn(QString("Metatile Behavior mask is too small to contain all %1 available options.").arg(maxBehavior));
|
||||
}
|
||||
if (isMaskTooSmall(&Metatile::terrainTypeAttr, NUM_METATILE_TERRAIN_TYPES - 1))
|
||||
logWarn(QString("Metatile Terrain Type mask is too small to contain all %1 available options.").arg(NUM_METATILE_TERRAIN_TYPES));
|
||||
if (isMaskTooSmall(&Metatile::encounterTypeAttr, NUM_METATILE_ENCOUNTER_TYPES - 1))
|
||||
logWarn(QString("Metatile Encounter Type mask is too small to contain all %1 available options.").arg(NUM_METATILE_ENCOUNTER_TYPES));
|
||||
if (isMaskTooSmall(&Metatile::layerTypeAttr, NUM_METATILE_LAYER_TYPES - 1))
|
||||
logWarn(QString("Metatile Layer Type mask is too small to contain all %1 available options.").arg(NUM_METATILE_LAYER_TYPES));
|
||||
}
|
||||
|
||||
uint32_t Metatile::getAttributes() {
|
||||
uint32_t attributes = this->unusedAttributes & Metatile::unusedAttrMask;
|
||||
attributes |= Metatile::behaviorAttr.toRaw(this->behavior);
|
||||
attributes |= Metatile::terrainTypeAttr.toRaw(this->terrainType);
|
||||
attributes |= Metatile::encounterTypeAttr.toRaw(this->encounterType);
|
||||
attributes |= Metatile::layerTypeAttr.toRaw(this->layerType);
|
||||
return attributes;
|
||||
}
|
||||
|
||||
void Metatile::setAttributes(uint32_t data, BaseGameVersion version) {
|
||||
if (version == BaseGameVersion::pokefirered) {
|
||||
this->behavior = (data & behaviorMask_FRLG) >> behaviorShift_FRLG;
|
||||
this->terrainType = (data & terrainTypeMask) >> terrainTypeShift;
|
||||
this->encounterType = (data & encounterTypeMask) >> encounterTypeShift;
|
||||
this->layerType = (data & layerTypeMask_FRLG) >> layerTypeShift_FRLG;
|
||||
this->unusedAttributes = data & ~(behaviorMask_FRLG | terrainTypeMask | layerTypeMask_FRLG | encounterTypeMask);
|
||||
} else {
|
||||
this->behavior = (data & behaviorMask_RSE) >> behaviorShift_RSE;
|
||||
this->layerType = (data & layerTypeMask_RSE) >> layerTypeShift_RSE;
|
||||
this->unusedAttributes = data & ~(behaviorMask_RSE | layerTypeMask_RSE);
|
||||
}
|
||||
void Metatile::setAttributes(uint32_t data) {
|
||||
this->behavior = Metatile::behaviorAttr.fromRaw(data);
|
||||
this->terrainType = Metatile::terrainTypeAttr.fromRaw(data);
|
||||
this->encounterType = Metatile::encounterTypeAttr.fromRaw(data);
|
||||
this->layerType = Metatile::layerTypeAttr.fromRaw(data);
|
||||
this->unusedAttributes = data & Metatile::unusedAttrMask;
|
||||
}
|
||||
|
||||
// Read attributes using a vanilla layout, then set them using the user's layout. For AdvanceMap import
|
||||
void Metatile::setAttributes(uint32_t data, BaseGameVersion version) {
|
||||
const auto defaultLayout = Metatile::defaultLayouts.value(version);
|
||||
this->setBehavior(defaultLayout->value("behavior").fromRaw(data));
|
||||
this->setTerrainType(defaultLayout->value("terrainType").fromRaw(data));
|
||||
this->setEncounterType(defaultLayout->value("encounterType").fromRaw(data));
|
||||
this->setLayerType(defaultLayout->value("layerType").fromRaw(data));
|
||||
}
|
||||
|
||||
int Metatile::getDefaultAttributesSize(BaseGameVersion version) {
|
||||
return (version == BaseGameVersion::pokefirered) ? 4 : 2;
|
||||
}
|
||||
uint32_t Metatile::getBehaviorMask(BaseGameVersion version) {
|
||||
return Metatile::defaultLayouts.value(version)->value("behavior").mask;
|
||||
}
|
||||
uint32_t Metatile::getTerrainTypeMask(BaseGameVersion version) {
|
||||
return Metatile::defaultLayouts.value(version)->value("terrainType").mask;
|
||||
}
|
||||
uint32_t Metatile::getEncounterTypeMask(BaseGameVersion version) {
|
||||
return Metatile::defaultLayouts.value(version)->value("encounterType").mask;
|
||||
}
|
||||
uint32_t Metatile::getLayerTypeMask(BaseGameVersion version) {
|
||||
return Metatile::defaultLayouts.value(version)->value("layerType").mask;
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ QList<Metatile*> MetatileParser::parse(QString filepath, bool *error, bool prima
|
|||
return { };
|
||||
}
|
||||
|
||||
int attrSize = Metatile::getAttributesSize(version);
|
||||
int attrSize = Metatile::getDefaultAttributesSize(version);
|
||||
int maxMetatiles = primaryTileset ? Project::getNumMetatilesPrimary() : Project::getNumMetatilesTotal() - Project::getNumMetatilesPrimary();
|
||||
int numMetatiles = static_cast<unsigned char>(in.at(0)) |
|
||||
(static_cast<unsigned char>(in.at(1)) << 8) |
|
||||
|
|
|
@ -410,7 +410,7 @@ int ParseUtil::gameStringToInt(QString gameString, bool * ok) {
|
|||
return 1;
|
||||
if (QString::compare(gameString, "FALSE", Qt::CaseInsensitive) == 0)
|
||||
return 0;
|
||||
return gameString.toInt(ok);
|
||||
return gameString.toInt(ok, 0);
|
||||
}
|
||||
|
||||
bool ParseUtil::gameStringToBool(QString gameString, bool * ok) {
|
||||
|
|
|
@ -240,8 +240,8 @@ bool Tileset::appendToMetatiles(QString root, QString friendlyName, bool usingAs
|
|||
} else {
|
||||
// Append to C file
|
||||
dataString.append(QString("const u16 gMetatiles_%1[] = INCBIN_U16(\"%2\");\n").arg(friendlyName, metatilesPath));
|
||||
QString attrSize = (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) ? "32" : "16";
|
||||
dataString.append(QString("const u%1 gMetatileAttributes_%2[] = INCBIN_U%1(\"%3\");\n").arg(attrSize, friendlyName, metatileAttrsPath));
|
||||
QString numBits = QString::number(projectConfig.getMetatileAttributesSize() * 8);
|
||||
dataString.append(QString("const u%1 gMetatileAttributes_%2[] = INCBIN_U%1(\"%3\");\n").arg(numBits, friendlyName, metatileAttrsPath));
|
||||
}
|
||||
file.write(dataString.toUtf8());
|
||||
file.flush();
|
||||
|
|
|
@ -376,36 +376,13 @@ void MainWindow::setProjectSpecificUIVisibility()
|
|||
ui->actionUse_Poryscript->setChecked(projectConfig.getUsePoryScript());
|
||||
this->setWildEncountersUIEnabled(userConfig.getEncounterJsonActive());
|
||||
|
||||
switch (projectConfig.getBaseGameVersion())
|
||||
{
|
||||
case BaseGameVersion::pokeruby:
|
||||
ui->checkBox_AllowRunning->setVisible(false);
|
||||
ui->checkBox_AllowBiking->setVisible(false);
|
||||
ui->checkBox_AllowEscaping->setVisible(false);
|
||||
ui->label_AllowRunning->setVisible(false);
|
||||
ui->label_AllowBiking->setVisible(false);
|
||||
ui->label_AllowEscaping->setVisible(false);
|
||||
ui->actionRegion_Map_Editor->setVisible(true);
|
||||
break;
|
||||
case BaseGameVersion::pokeemerald:
|
||||
ui->checkBox_AllowRunning->setVisible(true);
|
||||
ui->checkBox_AllowBiking->setVisible(true);
|
||||
ui->checkBox_AllowEscaping->setVisible(true);
|
||||
ui->label_AllowRunning->setVisible(true);
|
||||
ui->label_AllowBiking->setVisible(true);
|
||||
ui->label_AllowEscaping->setVisible(true);
|
||||
ui->actionRegion_Map_Editor->setVisible(true);
|
||||
break;
|
||||
case BaseGameVersion::pokefirered:
|
||||
ui->checkBox_AllowRunning->setVisible(true);
|
||||
ui->checkBox_AllowBiking->setVisible(true);
|
||||
ui->checkBox_AllowEscaping->setVisible(true);
|
||||
ui->label_AllowRunning->setVisible(true);
|
||||
ui->label_AllowBiking->setVisible(true);
|
||||
ui->label_AllowEscaping->setVisible(true);
|
||||
ui->actionRegion_Map_Editor->setVisible(true);
|
||||
break;
|
||||
}
|
||||
bool hasFlags = projectConfig.getMapAllowFlagsEnabled();
|
||||
ui->checkBox_AllowRunning->setVisible(hasFlags);
|
||||
ui->checkBox_AllowBiking->setVisible(hasFlags);
|
||||
ui->checkBox_AllowEscaping->setVisible(hasFlags);
|
||||
ui->label_AllowRunning->setVisible(hasFlags);
|
||||
ui->label_AllowBiking->setVisible(hasFlags);
|
||||
ui->label_AllowEscaping->setVisible(hasFlags);
|
||||
|
||||
ui->newEventToolButton->newWeatherTriggerAction->setVisible(projectConfig.getEventWeatherTriggerEnabled());
|
||||
ui->newEventToolButton->newSecretBaseAction->setVisible(projectConfig.getEventSecretBaseEnabled());
|
||||
|
@ -807,11 +784,9 @@ void MainWindow::displayMapProperties() {
|
|||
ui->comboBox_Type->setCurrentText(map->type);
|
||||
ui->comboBox_BattleScene->setCurrentText(map->battle_scene);
|
||||
ui->checkBox_ShowLocation->setChecked(map->show_location);
|
||||
if (projectConfig.getBaseGameVersion() != BaseGameVersion::pokeruby) {
|
||||
ui->checkBox_AllowRunning->setChecked(map->allowRunning);
|
||||
ui->checkBox_AllowBiking->setChecked(map->allowBiking);
|
||||
ui->checkBox_AllowEscaping->setChecked(map->allowEscaping);
|
||||
}
|
||||
ui->checkBox_AllowRunning->setChecked(map->allowRunning);
|
||||
ui->checkBox_AllowBiking->setChecked(map->allowBiking);
|
||||
ui->checkBox_AllowEscaping->setChecked(map->allowEscaping);
|
||||
ui->spinBox_FloorNumber->setValue(map->floorNumber);
|
||||
|
||||
// Custom fields table.
|
||||
|
@ -940,6 +915,7 @@ bool MainWindow::loadDataStructures() {
|
|||
&& project->readEventGraphics()
|
||||
&& project->readSongNames();
|
||||
|
||||
Metatile::setCustomLayout(project);
|
||||
Scripting::populateGlobalObject(this);
|
||||
|
||||
return success && loadProjectCombos();
|
||||
|
|
|
@ -165,7 +165,7 @@ const QSet<QString> defaultTopLevelMapFields = {
|
|||
|
||||
QSet<QString> Project::getTopLevelMapFields() {
|
||||
QSet<QString> topLevelMapFields = defaultTopLevelMapFields;
|
||||
if (projectConfig.getBaseGameVersion() != BaseGameVersion::pokeruby) {
|
||||
if (projectConfig.getMapAllowFlagsEnabled()) {
|
||||
topLevelMapFields.insert("allow_cycling");
|
||||
topLevelMapFields.insert("allow_escaping");
|
||||
topLevelMapFields.insert("allow_running");
|
||||
|
@ -200,7 +200,7 @@ bool Project::loadMapData(Map* map) {
|
|||
map->show_location = ParseUtil::jsonToBool(mapObj["show_map_name"]);
|
||||
map->battle_scene = ParseUtil::jsonToQString(mapObj["battle_scene"]);
|
||||
|
||||
if (projectConfig.getBaseGameVersion() != BaseGameVersion::pokeruby) {
|
||||
if (projectConfig.getMapAllowFlagsEnabled()) {
|
||||
map->allowBiking = ParseUtil::jsonToBool(mapObj["allow_cycling"]);
|
||||
map->allowEscaping = ParseUtil::jsonToBool(mapObj["allow_escaping"]);
|
||||
map->allowRunning = ParseUtil::jsonToBool(mapObj["allow_running"]);
|
||||
|
@ -375,26 +375,6 @@ QString Project::readMapLocation(QString map_name) {
|
|||
return ParseUtil::jsonToQString(mapObj["region_map_section"]);
|
||||
}
|
||||
|
||||
void Project::setNewMapHeader(Map* map, int mapIndex) {
|
||||
map->layoutId = QString("%1").arg(mapIndex);
|
||||
map->location = mapSectionValueToName.value(0);
|
||||
map->requiresFlash = false;
|
||||
map->weather = weatherNames.value(0, "WEATHER_NONE");
|
||||
map->type = mapTypes.value(0, "MAP_TYPE_NONE");
|
||||
map->song = defaultSong;
|
||||
map->show_location = true;
|
||||
if (projectConfig.getBaseGameVersion() != BaseGameVersion::pokeruby) {
|
||||
map->allowBiking = true;
|
||||
map->allowEscaping = false;
|
||||
map->allowRunning = true;
|
||||
}
|
||||
if (projectConfig.getFloorNumberEnabled()) {
|
||||
map->floorNumber = 0;
|
||||
}
|
||||
|
||||
map->battle_scene = mapBattleScenes.value(0, "MAP_BATTLE_SCENE_NORMAL");
|
||||
}
|
||||
|
||||
bool Project::loadLayout(MapLayout *layout) {
|
||||
// Force these to run even if one fails
|
||||
bool loadedTilesets = loadLayoutTilesets(layout);
|
||||
|
@ -981,10 +961,9 @@ void Project::saveTilesetMetatileAttributes(Tileset *tileset) {
|
|||
QFile attrs_file(tileset->metatile_attrs_path);
|
||||
if (attrs_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||
QByteArray data;
|
||||
BaseGameVersion version = projectConfig.getBaseGameVersion();
|
||||
int attrSize = Metatile::getAttributesSize(version);
|
||||
int attrSize = projectConfig.getMetatileAttributesSize();
|
||||
for (Metatile *metatile : tileset->metatiles) {
|
||||
uint32_t attributes = metatile->getAttributes(version);
|
||||
uint32_t attributes = metatile->getAttributes();
|
||||
for (int i = 0; i < attrSize; i++)
|
||||
data.append(static_cast<char>(attributes >> (8 * i)));
|
||||
}
|
||||
|
@ -1265,7 +1244,7 @@ void Project::saveMap(Map *map) {
|
|||
mapObj["requires_flash"] = map->requiresFlash;
|
||||
mapObj["weather"] = map->weather;
|
||||
mapObj["map_type"] = map->type;
|
||||
if (projectConfig.getBaseGameVersion() != BaseGameVersion::pokeruby) {
|
||||
if (projectConfig.getMapAllowFlagsEnabled()) {
|
||||
mapObj["allow_cycling"] = map->allowBiking;
|
||||
mapObj["allow_escaping"] = map->allowEscaping;
|
||||
mapObj["allow_running"] = map->allowRunning;
|
||||
|
@ -1539,9 +1518,7 @@ void Project::loadTilesetMetatiles(Tileset* tileset) {
|
|||
if (attrs_file.open(QIODevice::ReadOnly)) {
|
||||
QByteArray data = attrs_file.readAll();
|
||||
int num_metatiles = tileset->metatiles.count();
|
||||
|
||||
BaseGameVersion version = projectConfig.getBaseGameVersion();
|
||||
int attrSize = Metatile::getAttributesSize(version);
|
||||
int attrSize = projectConfig.getMetatileAttributesSize();
|
||||
int num_metatileAttrs = data.length() / attrSize;
|
||||
if (num_metatiles != num_metatileAttrs) {
|
||||
logWarn(QString("Metatile count %1 does not match metatile attribute count %2 in %3").arg(num_metatiles).arg(num_metatileAttrs).arg(tileset->name));
|
||||
|
@ -1553,7 +1530,7 @@ void Project::loadTilesetMetatiles(Tileset* tileset) {
|
|||
uint32_t attributes = 0;
|
||||
for (int j = 0; j < attrSize; j++)
|
||||
attributes |= static_cast<unsigned char>(data.at(i * attrSize + j)) << (8 * j);
|
||||
tileset->metatiles.at(i)->setAttributes(attributes, version);
|
||||
tileset->metatiles.at(i)->setAttributes(attributes);
|
||||
}
|
||||
} else {
|
||||
logError(QString("Could not open tileset metatile attributes file '%1'").arg(tileset->metatile_attrs_path));
|
||||
|
@ -2079,8 +2056,8 @@ bool Project::readHealLocations() {
|
|||
HealLocation healLocation;
|
||||
if (match.hasMatch()) {
|
||||
QString mapName = match.captured("map");
|
||||
int x = match.captured("x").toInt();
|
||||
int y = match.captured("y").toInt();
|
||||
int x = match.captured("x").toInt(nullptr, 0);
|
||||
int y = match.captured("y").toInt(nullptr, 0);
|
||||
healLocation = HealLocation(idName, mapName, this->healLocations.size() + 1, x, y);
|
||||
} else {
|
||||
// This heal location has data, but is missing from the location table and won't be displayed by Porymap.
|
||||
|
@ -2100,7 +2077,7 @@ bool Project::readHealLocations() {
|
|||
QRegularExpression respawnNPCRegex(QString("%1(?<npc>[0-9]+)").arg(initializerPattern));
|
||||
match = respawnNPCRegex.match(text);
|
||||
if (match.hasMatch())
|
||||
healLocation.respawnNPC = match.captured("npc").toInt();
|
||||
healLocation.respawnNPC = match.captured("npc").toInt(nullptr, 0);
|
||||
}
|
||||
|
||||
this->healLocations.append(healLocation);
|
||||
|
@ -2483,11 +2460,11 @@ bool Project::readEventGraphics() {
|
|||
QRegularExpressionMatch dimensionMatch = re.match(dimensions_label);
|
||||
QRegularExpressionMatch oamTablesMatch = re.match(subsprites_label);
|
||||
if (oamTablesMatch.hasMatch()) {
|
||||
eventGraphics->spriteWidth = oamTablesMatch.captured(1).toInt();
|
||||
eventGraphics->spriteHeight = oamTablesMatch.captured(2).toInt();
|
||||
eventGraphics->spriteWidth = oamTablesMatch.captured(1).toInt(nullptr, 0);
|
||||
eventGraphics->spriteHeight = oamTablesMatch.captured(2).toInt(nullptr, 0);
|
||||
} else if (dimensionMatch.hasMatch()) {
|
||||
eventGraphics->spriteWidth = dimensionMatch.captured(1).toInt();
|
||||
eventGraphics->spriteHeight = dimensionMatch.captured(2).toInt();
|
||||
eventGraphics->spriteWidth = dimensionMatch.captured(1).toInt(nullptr, 0);
|
||||
eventGraphics->spriteHeight = dimensionMatch.captured(2).toInt(nullptr, 0);
|
||||
} else {
|
||||
eventGraphics->spriteWidth = eventGraphics->spritesheet.width();
|
||||
eventGraphics->spriteHeight = eventGraphics->spritesheet.height();
|
||||
|
|
|
@ -635,10 +635,9 @@ int MainWindow::getMetatileLayerType(int metatileId) {
|
|||
|
||||
void MainWindow::setMetatileLayerType(int metatileId, int layerType) {
|
||||
Metatile * metatile = this->getMetatile(metatileId);
|
||||
uint8_t u_layerType = static_cast<uint8_t>(layerType);
|
||||
if (!metatile || metatile->layerType == u_layerType || u_layerType >= NUM_METATILE_LAYER_TYPES)
|
||||
if (!metatile)
|
||||
return;
|
||||
metatile->layerType = u_layerType;
|
||||
metatile->setLayerType(layerType);
|
||||
this->saveMetatileAttributesByMetatileId(metatileId);
|
||||
}
|
||||
|
||||
|
@ -651,10 +650,9 @@ int MainWindow::getMetatileEncounterType(int metatileId) {
|
|||
|
||||
void MainWindow::setMetatileEncounterType(int metatileId, int encounterType) {
|
||||
Metatile * metatile = this->getMetatile(metatileId);
|
||||
uint8_t u_encounterType = static_cast<uint8_t>(encounterType);
|
||||
if (!metatile || metatile->encounterType == u_encounterType || u_encounterType >= NUM_METATILE_ENCOUNTER_TYPES)
|
||||
if (!metatile)
|
||||
return;
|
||||
metatile->encounterType = u_encounterType;
|
||||
metatile->setEncounterType(encounterType);
|
||||
this->saveMetatileAttributesByMetatileId(metatileId);
|
||||
}
|
||||
|
||||
|
@ -667,10 +665,9 @@ int MainWindow::getMetatileTerrainType(int metatileId) {
|
|||
|
||||
void MainWindow::setMetatileTerrainType(int metatileId, int terrainType) {
|
||||
Metatile * metatile = this->getMetatile(metatileId);
|
||||
uint8_t u_terrainType = static_cast<uint8_t>(terrainType);
|
||||
if (!metatile || metatile->terrainType == u_terrainType || u_terrainType >= NUM_METATILE_TERRAIN_TYPES)
|
||||
if (!metatile)
|
||||
return;
|
||||
metatile->terrainType = u_terrainType;
|
||||
metatile->setTerrainType(terrainType);
|
||||
this->saveMetatileAttributesByMetatileId(metatileId);
|
||||
}
|
||||
|
||||
|
@ -683,10 +680,9 @@ int MainWindow::getMetatileBehavior(int metatileId) {
|
|||
|
||||
void MainWindow::setMetatileBehavior(int metatileId, int behavior) {
|
||||
Metatile * metatile = this->getMetatile(metatileId);
|
||||
uint16_t u_behavior = static_cast<uint16_t>(behavior);
|
||||
if (!metatile || metatile->behavior == u_behavior)
|
||||
if (!metatile)
|
||||
return;
|
||||
metatile->behavior = u_behavior;
|
||||
metatile->setBehavior(behavior);
|
||||
this->saveMetatileAttributesByMetatileId(metatileId);
|
||||
}
|
||||
|
||||
|
@ -694,15 +690,14 @@ int MainWindow::getMetatileAttributes(int metatileId) {
|
|||
Metatile * metatile = this->getMetatile(metatileId);
|
||||
if (!metatile)
|
||||
return -1;
|
||||
return metatile->getAttributes(projectConfig.getBaseGameVersion());
|
||||
return metatile->getAttributes();
|
||||
}
|
||||
|
||||
void MainWindow::setMetatileAttributes(int metatileId, int attributes) {
|
||||
Metatile * metatile = this->getMetatile(metatileId);
|
||||
uint32_t u_attributes = static_cast<uint32_t>(attributes);
|
||||
if (!metatile)
|
||||
return;
|
||||
metatile->setAttributes(u_attributes, projectConfig.getBaseGameVersion());
|
||||
metatile->setAttributes(attributes);
|
||||
this->saveMetatileAttributesByMetatileId(metatileId);
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ void NewMapPopup::init() {
|
|||
ui->spinBox_NewMap_Floor_Number->setMaximum(127);
|
||||
|
||||
// Hide config specific ui elements
|
||||
bool hasFlags = (projectConfig.getBaseGameVersion() != BaseGameVersion::pokeruby);
|
||||
bool hasFlags = projectConfig.getMapAllowFlagsEnabled();
|
||||
ui->checkBox_NewMap_Allow_Running->setVisible(hasFlags);
|
||||
ui->checkBox_NewMap_Allow_Biking->setVisible(hasFlags);
|
||||
ui->checkBox_NewMap_Allow_Escape_Rope->setVisible(hasFlags);
|
||||
|
@ -293,7 +293,7 @@ void NewMapPopup::on_pushButton_NewMap_Accept_clicked() {
|
|||
newMap->needsHealLocation = true;
|
||||
}
|
||||
|
||||
if (projectConfig.getBaseGameVersion() != BaseGameVersion::pokeruby) {
|
||||
if (projectConfig.getMapAllowFlagsEnabled()) {
|
||||
newMap->allowRunning = this->ui->checkBox_NewMap_Allow_Running->isChecked();
|
||||
newMap->allowBiking = this->ui->checkBox_NewMap_Allow_Biking->isChecked();
|
||||
newMap->allowEscaping = this->ui->checkBox_NewMap_Allow_Escape_Rope->isChecked();
|
||||
|
|
|
@ -99,9 +99,7 @@ void TilesetEditor::initUi() {
|
|||
this->ui->spinBox_paletteSelector->setMinimum(0);
|
||||
this->ui->spinBox_paletteSelector->setMaximum(Project::getNumPalettesTotal() - 1);
|
||||
|
||||
this->setMetatileBehaviors();
|
||||
this->setMetatileLayersUi();
|
||||
this->setVersionSpecificUi();
|
||||
this->setAttributesUi();
|
||||
this->setMetatileLabelValidator();
|
||||
|
||||
this->initMetatileSelector();
|
||||
|
@ -113,43 +111,55 @@ void TilesetEditor::initUi() {
|
|||
this->restoreWindowState();
|
||||
}
|
||||
|
||||
void TilesetEditor::setMetatileBehaviors() {
|
||||
for (int num : project->metatileBehaviorMapInverse.keys()) {
|
||||
this->ui->comboBox_metatileBehaviors->addItem(project->metatileBehaviorMapInverse[num], num);
|
||||
}
|
||||
}
|
||||
|
||||
void TilesetEditor::setMetatileLayersUi() {
|
||||
if (!projectConfig.getTripleLayerMetatilesEnabled()) {
|
||||
this->ui->comboBox_layerType->addItem("Normal - Middle/Top", METATILE_LAYER_MIDDLE_TOP);
|
||||
this->ui->comboBox_layerType->addItem("Covered - Bottom/Middle", METATILE_LAYER_BOTTOM_MIDDLE);
|
||||
this->ui->comboBox_layerType->addItem("Split - Bottom/Top", METATILE_LAYER_BOTTOM_TOP);
|
||||
void TilesetEditor::setAttributesUi() {
|
||||
// Behavior
|
||||
if (Metatile::getBehaviorMask()) {
|
||||
for (int num : project->metatileBehaviorMapInverse.keys()) {
|
||||
this->ui->comboBox_metatileBehaviors->addItem(project->metatileBehaviorMapInverse[num], num);
|
||||
}
|
||||
} else {
|
||||
this->ui->comboBox_layerType->setVisible(false);
|
||||
this->ui->label_layerType->setVisible(false);
|
||||
this->ui->label_BottomTop->setText("Bottom/Middle/Top");
|
||||
this->ui->comboBox_metatileBehaviors->setVisible(false);
|
||||
this->ui->label_metatileBehavior->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
void TilesetEditor::setVersionSpecificUi() {
|
||||
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
|
||||
this->ui->comboBox_encounterType->setVisible(true);
|
||||
this->ui->label_encounterType->setVisible(true);
|
||||
this->ui->comboBox_encounterType->addItem("None", ENCOUNTER_NONE);
|
||||
this->ui->comboBox_encounterType->addItem("Land", ENCOUNTER_LAND);
|
||||
this->ui->comboBox_encounterType->addItem("Water", ENCOUNTER_WATER);
|
||||
this->ui->comboBox_terrainType->setVisible(true);
|
||||
this->ui->label_terrainType->setVisible(true);
|
||||
// Terrain Type
|
||||
if (Metatile::getTerrainTypeMask()) {
|
||||
this->ui->comboBox_terrainType->addItem("Normal", TERRAIN_NONE);
|
||||
this->ui->comboBox_terrainType->addItem("Grass", TERRAIN_GRASS);
|
||||
this->ui->comboBox_terrainType->addItem("Water", TERRAIN_WATER);
|
||||
this->ui->comboBox_terrainType->addItem("Waterfall", TERRAIN_WATERFALL);
|
||||
} else {
|
||||
this->ui->comboBox_encounterType->setVisible(false);
|
||||
this->ui->label_encounterType->setVisible(false);
|
||||
this->ui->comboBox_terrainType->setVisible(false);
|
||||
this->ui->label_terrainType->setVisible(false);
|
||||
}
|
||||
|
||||
// Encounter Type
|
||||
if (Metatile::getEncounterTypeMask()) {
|
||||
this->ui->comboBox_encounterType->addItem("None", ENCOUNTER_NONE);
|
||||
this->ui->comboBox_encounterType->addItem("Land", ENCOUNTER_LAND);
|
||||
this->ui->comboBox_encounterType->addItem("Water", ENCOUNTER_WATER);
|
||||
} else {
|
||||
this->ui->comboBox_encounterType->setVisible(false);
|
||||
this->ui->label_encounterType->setVisible(false);
|
||||
}
|
||||
|
||||
// Layer Type
|
||||
if (!projectConfig.getTripleLayerMetatilesEnabled()) {
|
||||
this->ui->comboBox_layerType->addItem("Normal - Middle/Top", METATILE_LAYER_MIDDLE_TOP);
|
||||
this->ui->comboBox_layerType->addItem("Covered - Bottom/Middle", METATILE_LAYER_BOTTOM_MIDDLE);
|
||||
this->ui->comboBox_layerType->addItem("Split - Bottom/Top", METATILE_LAYER_BOTTOM_TOP);
|
||||
if (!Metatile::getLayerTypeMask()) {
|
||||
// User doesn't have triple layer metatiles, but has no layer type attribute.
|
||||
// Porymap is still using the layer type value to render metatiles, and with
|
||||
// no mask set every metatile will be "Middle/Top", so just display the combo
|
||||
// box but prevent the user from changing the value.
|
||||
this->ui->comboBox_layerType->setEnabled(false);
|
||||
}
|
||||
} else {
|
||||
this->ui->comboBox_layerType->setVisible(false);
|
||||
this->ui->label_layerType->setVisible(false);
|
||||
this->ui->label_BottomTop->setText("Bottom/Middle/Top");
|
||||
}
|
||||
}
|
||||
|
||||
void TilesetEditor::setMetatileLabelValidator() {
|
||||
|
@ -373,13 +383,9 @@ void TilesetEditor::onSelectedMetatileChanged(uint16_t metatileId) {
|
|||
this->ui->graphicsView_metatileLayers->setFixedSize(this->metatileLayersItem->pixmap().width() + 2, this->metatileLayersItem->pixmap().height() + 2);
|
||||
this->ui->lineEdit_metatileLabel->setText(this->metatile->label);
|
||||
setComboValue(this->ui->comboBox_metatileBehaviors, this->metatile->behavior);
|
||||
if (!projectConfig.getTripleLayerMetatilesEnabled()) {
|
||||
setComboValue(this->ui->comboBox_layerType, this->metatile->layerType);
|
||||
}
|
||||
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
|
||||
setComboValue(this->ui->comboBox_encounterType, this->metatile->encounterType);
|
||||
setComboValue(this->ui->comboBox_terrainType, this->metatile->terrainType);
|
||||
}
|
||||
setComboValue(this->ui->comboBox_layerType, this->metatile->layerType);
|
||||
setComboValue(this->ui->comboBox_encounterType, this->metatile->encounterType);
|
||||
setComboValue(this->ui->comboBox_terrainType, this->metatile->terrainType);
|
||||
}
|
||||
|
||||
void TilesetEditor::onHoveredTileChanged(uint16_t tile) {
|
||||
|
@ -512,11 +518,11 @@ void TilesetEditor::on_comboBox_metatileBehaviors_currentTextChanged(const QStri
|
|||
|
||||
// This function can also be called when the user selects
|
||||
// a different metatile. Stop this from being considered a change.
|
||||
if (this->metatile->behavior == static_cast<uint16_t>(behavior))
|
||||
if (this->metatile->behavior == static_cast<uint32_t>(behavior))
|
||||
return;
|
||||
|
||||
Metatile *prevMetatile = new Metatile(*this->metatile);
|
||||
this->metatile->behavior = behavior;
|
||||
this->metatile->setBehavior(behavior);
|
||||
MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatileId(),
|
||||
prevMetatile, new Metatile(*this->metatile));
|
||||
metatileHistory.push(commit);
|
||||
|
@ -552,7 +558,7 @@ void TilesetEditor::on_comboBox_layerType_activated(int layerType)
|
|||
{
|
||||
if (this->metatile) {
|
||||
Metatile *prevMetatile = new Metatile(*this->metatile);
|
||||
this->metatile->layerType = static_cast<uint8_t>(layerType);
|
||||
this->metatile->setLayerType(layerType);
|
||||
MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatileId(),
|
||||
prevMetatile, new Metatile(*this->metatile));
|
||||
metatileHistory.push(commit);
|
||||
|
@ -565,7 +571,7 @@ void TilesetEditor::on_comboBox_encounterType_activated(int encounterType)
|
|||
{
|
||||
if (this->metatile) {
|
||||
Metatile *prevMetatile = new Metatile(*this->metatile);
|
||||
this->metatile->encounterType = static_cast<uint8_t>(encounterType);
|
||||
this->metatile->setEncounterType(encounterType);
|
||||
MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatileId(),
|
||||
prevMetatile, new Metatile(*this->metatile));
|
||||
metatileHistory.push(commit);
|
||||
|
@ -577,7 +583,7 @@ void TilesetEditor::on_comboBox_terrainType_activated(int terrainType)
|
|||
{
|
||||
if (this->metatile) {
|
||||
Metatile *prevMetatile = new Metatile(*this->metatile);
|
||||
this->metatile->terrainType = static_cast<uint8_t>(terrainType);
|
||||
this->metatile->setTerrainType(terrainType);
|
||||
MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatileId(),
|
||||
prevMetatile, new Metatile(*this->metatile));
|
||||
metatileHistory.push(commit);
|
||||
|
|
Loading…
Reference in a new issue