Simplify metatile attribute layouts
This commit is contained in:
parent
9cd8777246
commit
577dc2fce2
5 changed files with 145 additions and 134 deletions
|
@ -30,6 +30,29 @@ enum {
|
||||||
NUM_METATILE_TERRAIN_TYPES
|
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
|
class Metatile
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -47,30 +70,23 @@ public:
|
||||||
uint32_t unusedAttributes;
|
uint32_t unusedAttributes;
|
||||||
QString label;
|
QString label;
|
||||||
|
|
||||||
enum Attr {
|
|
||||||
Behavior,
|
|
||||||
TerrainType,
|
|
||||||
EncounterType,
|
|
||||||
LayerType,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct AttrLayout {
|
|
||||||
uint32_t mask;
|
|
||||||
int shift;
|
|
||||||
};
|
|
||||||
|
|
||||||
static const QHash<Metatile::Attr, Metatile::AttrLayout> defaultLayoutFRLG;
|
|
||||||
static const QHash<Metatile::Attr, Metatile::AttrLayout> defaultLayoutRSE;
|
|
||||||
static QHash<Metatile::Attr, Metatile::AttrLayout> customLayout;
|
|
||||||
|
|
||||||
uint32_t getAttributes();
|
uint32_t getAttributes();
|
||||||
void setAttributes(uint32_t data);
|
void setAttributes(uint32_t data);
|
||||||
void convertAttributes(uint32_t data, BaseGameVersion version);
|
void setAttributes(uint32_t data, BaseGameVersion version);
|
||||||
|
|
||||||
void setBehavior(uint32_t);
|
void setBehavior(int value) { this->behavior = behaviorAttr.getClamped(value); }
|
||||||
void setTerrainType(uint32_t);
|
void setTerrainType(int value) { this->terrainType = terrainTypeAttr.getClamped(value); }
|
||||||
void setEncounterType(uint32_t);
|
void setEncounterType(int value) { this->encounterType = encounterTypeAttr.getClamped(value); }
|
||||||
void setLayerType(uint32_t);
|
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 int getIndexInTileset(int);
|
||||||
static QPoint coordFromPixmapCoord(const QPointF &pixelCoord);
|
static QPoint coordFromPixmapCoord(const QPointF &pixelCoord);
|
||||||
|
@ -78,11 +94,22 @@ public:
|
||||||
static void setCustomLayout();
|
static void setCustomLayout();
|
||||||
|
|
||||||
private:
|
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;
|
static uint32_t unusedAttrMask;
|
||||||
|
|
||||||
void setAttributes(uint32_t, const QHash<Metatile::Attr, Metatile::AttrLayout>*);
|
// Stores how each attribute should be laid out for all metatiles, according to the vanilla games
|
||||||
static void setCustomAttributeLayout(Metatile::AttrLayout *, uint32_t, uint32_t);
|
// Used to set default config values and import maps with AdvanceMap
|
||||||
static bool isMaskTooSmall(Metatile::AttrLayout * layout, int n);
|
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>);
|
static bool doMasksOverlap(QList<uint32_t>);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -627,11 +627,10 @@ void ProjectConfig::setUnreadKeys() {
|
||||||
if (!readKeys.contains("new_map_border_metatiles")) this->newMapBorderMetatileIds = isPokefirered ? DEFAULT_BORDER_FRLG : DEFAULT_BORDER_RSE;
|
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("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_attributes_size")) this->metatileAttributesSize = Metatile::getDefaultAttributesSize(this->baseGameVersion);
|
||||||
const QHash<Metatile::Attr, Metatile::AttrLayout> layout = isPokefirered ? Metatile::defaultLayoutFRLG : Metatile::defaultLayoutRSE;
|
if (!readKeys.contains("metatile_behavior_mask")) this->metatileBehaviorMask = Metatile::getBehaviorMask(this->baseGameVersion);
|
||||||
if (!readKeys.contains("metatile_behavior_mask")) this->metatileBehaviorMask = layout[Metatile::Attr::Behavior].mask;
|
if (!readKeys.contains("metatile_terrain_type_mask")) this->metatileTerrainTypeMask = Metatile::getTerrainTypeMask(this->baseGameVersion);
|
||||||
if (!readKeys.contains("metatile_terrain_type_mask")) this->metatileTerrainTypeMask = layout[Metatile::Attr::TerrainType].mask;
|
if (!readKeys.contains("metatile_encounter_type_mask")) this->metatileEncounterTypeMask = Metatile::getEncounterTypeMask(this->baseGameVersion);
|
||||||
if (!readKeys.contains("metatile_encounter_type_mask")) this->metatileEncounterTypeMask = layout[Metatile::Attr::EncounterType].mask;
|
if (!readKeys.contains("metatile_layer_type_mask")) this-> metatileLayerTypeMask = Metatile::getLayerTypeMask(this->baseGameVersion);
|
||||||
if (!readKeys.contains("metatile_layer_type_mask")) this-> metatileLayerTypeMask = layout[Metatile::Attr::LayerType].mask;
|
|
||||||
if (!readKeys.contains("enable_map_allow_flags")) this->enableMapAllowFlags = (this->baseGameVersion != BaseGameVersion::pokeruby);
|
if (!readKeys.contains("enable_map_allow_flags")) this->enableMapAllowFlags = (this->baseGameVersion != BaseGameVersion::pokeruby);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,22 +2,42 @@
|
||||||
#include "tileset.h"
|
#include "tileset.h"
|
||||||
#include "project.h"
|
#include "project.h"
|
||||||
|
|
||||||
QHash<Metatile::Attr, Metatile::AttrLayout> Metatile::customLayout = {};
|
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;
|
uint32_t Metatile::unusedAttrMask = 0;
|
||||||
|
|
||||||
const QHash<Metatile::Attr, Metatile::AttrLayout> Metatile::defaultLayoutFRLG = {
|
MetatileAttr::MetatileAttr() :
|
||||||
{Metatile::Attr::Behavior, { .mask = 0x000001FF, .shift = 0} },
|
mask(0),
|
||||||
{Metatile::Attr::TerrainType, { .mask = 0x00003E00, .shift = 9} },
|
shift(0)
|
||||||
{Metatile::Attr::EncounterType, { .mask = 0x07000000, .shift = 24} },
|
{ }
|
||||||
{Metatile::Attr::LayerType, { .mask = 0x60000000, .shift = 29} },
|
|
||||||
};
|
|
||||||
|
|
||||||
const QHash<Metatile::Attr, Metatile::AttrLayout> Metatile::defaultLayoutRSE = {
|
MetatileAttr::MetatileAttr(uint32_t mask, int shift) :
|
||||||
{Metatile::Attr::Behavior, { .mask = 0x000000FF, .shift = 0} },
|
mask(mask),
|
||||||
{Metatile::Attr::TerrainType, { .mask = 0x00000000, .shift = 0} },
|
shift(shift)
|
||||||
{Metatile::Attr::EncounterType, { .mask = 0x00000000, .shift = 0} },
|
{ }
|
||||||
{Metatile::Attr::LayerType, { .mask = 0x0000F000, .shift = 12} },
|
|
||||||
};
|
|
||||||
|
|
||||||
Metatile::Metatile() :
|
Metatile::Metatile() :
|
||||||
behavior(0),
|
behavior(0),
|
||||||
|
@ -48,19 +68,14 @@ int Metatile::getIndexInTileset(int metatileId) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the vanilla attribute sizes based on version.
|
|
||||||
// Used as a default in the config and for AdvanceMap import.
|
|
||||||
int Metatile::getDefaultAttributesSize(BaseGameVersion version) {
|
|
||||||
return (version == BaseGameVersion::pokefirered) ? 4 : 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPoint Metatile::coordFromPixmapCoord(const QPointF &pixelCoord) {
|
QPoint Metatile::coordFromPixmapCoord(const QPointF &pixelCoord) {
|
||||||
int x = static_cast<int>(pixelCoord.x()) / 16;
|
int x = static_cast<int>(pixelCoord.x()) / 16;
|
||||||
int y = static_cast<int>(pixelCoord.y()) / 16;
|
int y = static_cast<int>(pixelCoord.y()) / 16;
|
||||||
return QPoint(x, y);
|
return QPoint(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Metatile::setCustomAttributeLayout(Metatile::AttrLayout * layout, uint32_t mask, uint32_t max) {
|
// 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) {
|
if (mask > max) {
|
||||||
uint32_t oldMask = mask;
|
uint32_t oldMask = mask;
|
||||||
mask &= max;
|
mask &= max;
|
||||||
|
@ -68,15 +83,22 @@ void Metatile::setCustomAttributeLayout(Metatile::AttrLayout * layout, uint32_t
|
||||||
.arg(QString::number(oldMask, 16).toUpper())
|
.arg(QString::number(oldMask, 16).toUpper())
|
||||||
.arg(QString::number(mask, 16).toUpper()));
|
.arg(QString::number(mask, 16).toUpper()));
|
||||||
}
|
}
|
||||||
layout->mask = mask;
|
attr->mask = mask;
|
||||||
layout->shift = log2(mask & ~(mask - 1)); // Get the position of the rightmost set bit
|
attr->shift = mask ? log2(mask & ~(mask - 1)) : 0; // Get position of the least significant set bit
|
||||||
}
|
}
|
||||||
|
|
||||||
// For checking whether a metatile attribute mask can contain all the hard-coded values
|
// For checking whether a metatile attribute mask can contain all the available hard-coded options
|
||||||
bool Metatile::isMaskTooSmall(Metatile::AttrLayout * layout, int n) {
|
bool Metatile::isMaskTooSmall(MetatileAttr * attr, int max) {
|
||||||
if (!layout->mask) return false;
|
if (attr->mask == 0 || max <= 0) return false;
|
||||||
uint32_t maxValue = n - 1;
|
|
||||||
return (maxValue & (layout->mask >> layout->shift)) != maxValue;
|
// Get position of the most significant set bit
|
||||||
|
uint32_t n = log2(max);
|
||||||
|
|
||||||
|
// Get a mask for all values 0 to max.
|
||||||
|
// This may fail for n=31, but that's not a concern here.
|
||||||
|
uint32_t rangeMask = (1 << (n + 1)) - 1;
|
||||||
|
|
||||||
|
return attr->getClamped(rangeMask) != rangeMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Metatile::doMasksOverlap(QList<uint32_t> masks) {
|
bool Metatile::doMasksOverlap(QList<uint32_t> masks) {
|
||||||
|
@ -98,107 +120,70 @@ void Metatile::setCustomLayout() {
|
||||||
const uint32_t maxMask = maxMasks.value(projectConfig.getMetatileAttributesSize(), 0);
|
const uint32_t maxMask = maxMasks.value(projectConfig.getMetatileAttributesSize(), 0);
|
||||||
|
|
||||||
// Set custom attribute masks from the config file
|
// Set custom attribute masks from the config file
|
||||||
setCustomAttributeLayout(&customLayout[Attr::Behavior], projectConfig.getMetatileBehaviorMask(), maxMask);
|
setCustomAttributeLayout(&Metatile::behaviorAttr, projectConfig.getMetatileBehaviorMask(), maxMask);
|
||||||
setCustomAttributeLayout(&customLayout[Attr::TerrainType], projectConfig.getMetatileTerrainTypeMask(), maxMask);
|
setCustomAttributeLayout(&Metatile::terrainTypeAttr, projectConfig.getMetatileTerrainTypeMask(), maxMask);
|
||||||
setCustomAttributeLayout(&customLayout[Attr::EncounterType], projectConfig.getMetatileEncounterTypeMask(), maxMask);
|
setCustomAttributeLayout(&Metatile::encounterTypeAttr, projectConfig.getMetatileEncounterTypeMask(), maxMask);
|
||||||
setCustomAttributeLayout(&customLayout[Attr::LayerType], projectConfig.getMetatileLayerTypeMask(), maxMask);
|
setCustomAttributeLayout(&Metatile::layerTypeAttr, projectConfig.getMetatileLayerTypeMask(), maxMask);
|
||||||
|
|
||||||
// Set mask for preserving any attribute bits not used by Porymap
|
// Set mask for preserving any attribute bits not used by Porymap
|
||||||
Metatile::unusedAttrMask = ~(customLayout[Attr::Behavior].mask
|
Metatile::unusedAttrMask = ~(getBehaviorMask() | getTerrainTypeMask() | getEncounterTypeMask() | getLayerTypeMask());
|
||||||
| customLayout[Attr::TerrainType].mask
|
|
||||||
| customLayout[Attr::EncounterType].mask
|
|
||||||
| customLayout[Attr::LayerType].mask);
|
|
||||||
Metatile::unusedAttrMask &= maxMask;
|
Metatile::unusedAttrMask &= maxMask;
|
||||||
|
|
||||||
// Overlapping masks are technically ok, but probably not intended.
|
// Overlapping masks are technically ok, but probably not intended.
|
||||||
// Additionally, Porymap will not properly reflect that the values are linked.
|
// Additionally, Porymap will not properly reflect that the values are linked.
|
||||||
if (doMasksOverlap({customLayout[Attr::Behavior].mask,
|
if (doMasksOverlap({getBehaviorMask(), getTerrainTypeMask(), getEncounterTypeMask(), getLayerTypeMask()})) {
|
||||||
customLayout[Attr::TerrainType].mask,
|
logWarn("Metatile attribute masks are overlapping. This may result in unexpected attribute values.");
|
||||||
customLayout[Attr::EncounterType].mask,
|
|
||||||
customLayout[Attr::LayerType].mask})) {
|
|
||||||
logWarn("Metatile attribute masks are overlapping.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The available options in the Tileset Editor for Terrain Type, Encounter Type, and Layer Type are hard-coded.
|
// The available options in the Tileset Editor for Terrain Type, Encounter Type, and Layer Type are hard-coded.
|
||||||
// Warn the user if they have set a nonzero mask that is too small to contain these options.
|
// Warn the user if they have set a nonzero mask that is too small to contain these options.
|
||||||
// They'll be allowed to select them, but they'll be truncated to a different value when revisited.
|
// They'll be allowed to select them, but they'll be truncated to a different value when revisited.
|
||||||
if (isMaskTooSmall(&customLayout[Attr::TerrainType], NUM_METATILE_TERRAIN_TYPES))
|
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));
|
logWarn(QString("Metatile Terrain Type mask is too small to contain all %1 available options.").arg(NUM_METATILE_TERRAIN_TYPES));
|
||||||
if (isMaskTooSmall(&customLayout[Attr::EncounterType], NUM_METATILE_ENCOUNTER_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));
|
logWarn(QString("Metatile Encounter Type mask is too small to contain all %1 available options.").arg(NUM_METATILE_ENCOUNTER_TYPES));
|
||||||
if (isMaskTooSmall(&customLayout[Attr::LayerType], NUM_METATILE_LAYER_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));
|
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 Metatile::getAttributes() {
|
||||||
uint32_t attributes = this->unusedAttributes & Metatile::unusedAttrMask;
|
uint32_t attributes = this->unusedAttributes & Metatile::unusedAttrMask;
|
||||||
|
attributes |= Metatile::behaviorAttr.toRaw(this->behavior);
|
||||||
// Behavior
|
attributes |= Metatile::terrainTypeAttr.toRaw(this->terrainType);
|
||||||
Metatile::AttrLayout attr = Metatile::customLayout[Attr::Behavior];
|
attributes |= Metatile::encounterTypeAttr.toRaw(this->encounterType);
|
||||||
attributes |= (this->behavior << attr.shift) & attr.mask;
|
attributes |= Metatile::layerTypeAttr.toRaw(this->layerType);
|
||||||
|
|
||||||
// Terrain Type
|
|
||||||
attr = Metatile::customLayout[Attr::TerrainType];
|
|
||||||
attributes |= (this->terrainType << attr.shift) & attr.mask;
|
|
||||||
|
|
||||||
// Encounter Type
|
|
||||||
attr = Metatile::customLayout[Attr::EncounterType];
|
|
||||||
attributes |= (this->encounterType << attr.shift) & attr.mask;
|
|
||||||
|
|
||||||
// Layer Type
|
|
||||||
attr = Metatile::customLayout[Attr::LayerType];
|
|
||||||
attributes |= (this->layerType << attr.shift) & attr.mask;
|
|
||||||
|
|
||||||
return attributes;
|
return attributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Metatile::setAttributes(uint32_t data, const QHash<Metatile::Attr, Metatile::AttrLayout> * layout) {
|
void Metatile::setAttributes(uint32_t data) {
|
||||||
// Behavior
|
this->behavior = Metatile::behaviorAttr.fromRaw(data);
|
||||||
Metatile::AttrLayout attr = layout->value(Attr::Behavior);
|
this->terrainType = Metatile::terrainTypeAttr.fromRaw(data);
|
||||||
this->behavior = (data & attr.mask) >> attr.shift;
|
this->encounterType = Metatile::encounterTypeAttr.fromRaw(data);
|
||||||
|
this->layerType = Metatile::layerTypeAttr.fromRaw(data);
|
||||||
// Terrain Type
|
|
||||||
attr = layout->value(Attr::TerrainType);
|
|
||||||
this->terrainType = (data & attr.mask) >> attr.shift;
|
|
||||||
|
|
||||||
// Encounter Type
|
|
||||||
attr = layout->value(Attr::EncounterType);
|
|
||||||
this->encounterType = (data & attr.mask) >> attr.shift;
|
|
||||||
|
|
||||||
// Layer Type
|
|
||||||
attr = layout->value(Attr::LayerType);
|
|
||||||
this->layerType = (data & attr.mask) >> attr.shift;
|
|
||||||
|
|
||||||
this->unusedAttributes = data & Metatile::unusedAttrMask;
|
this->unusedAttributes = data & Metatile::unusedAttrMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Metatile::setAttributes(uint32_t data) {
|
|
||||||
this->setAttributes(data, &Metatile::customLayout);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read attributes using a vanilla layout, then set them using the user's layout. For AdvanceMap import
|
// Read attributes using a vanilla layout, then set them using the user's layout. For AdvanceMap import
|
||||||
void Metatile::convertAttributes(uint32_t data, BaseGameVersion version) {
|
void Metatile::setAttributes(uint32_t data, BaseGameVersion version) {
|
||||||
if (version == BaseGameVersion::pokefirered) {
|
const auto defaultLayout = Metatile::defaultLayouts.value(version);
|
||||||
this->setAttributes(data, &Metatile::defaultLayoutFRLG);
|
this->setBehavior(defaultLayout->value("behavior").fromRaw(data));
|
||||||
} else {
|
this->setTerrainType(defaultLayout->value("terrainType").fromRaw(data));
|
||||||
this->setAttributes(data, &Metatile::defaultLayoutRSE);
|
this->setEncounterType(defaultLayout->value("encounterType").fromRaw(data));
|
||||||
}
|
this->setLayerType(defaultLayout->value("layerType").fromRaw(data));
|
||||||
// Clean data to fit the user's custom masks
|
|
||||||
this->setAttributes(this->getAttributes());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Metatile::setBehavior(uint32_t value) {
|
int Metatile::getDefaultAttributesSize(BaseGameVersion version) {
|
||||||
this->behavior = value & Metatile::customLayout[Attr::Behavior].mask;
|
return (version == BaseGameVersion::pokefirered) ? 4 : 2;
|
||||||
}
|
}
|
||||||
|
uint32_t Metatile::getBehaviorMask(BaseGameVersion version) {
|
||||||
void Metatile::setTerrainType(uint32_t value) {
|
return Metatile::defaultLayouts.value(version)->value("behavior").mask;
|
||||||
this->terrainType = value & Metatile::customLayout[Attr::TerrainType].mask;
|
|
||||||
}
|
}
|
||||||
|
uint32_t Metatile::getTerrainTypeMask(BaseGameVersion version) {
|
||||||
void Metatile::setEncounterType(uint32_t value) {
|
return Metatile::defaultLayouts.value(version)->value("terrainType").mask;
|
||||||
this->encounterType = value & Metatile::customLayout[Attr::EncounterType].mask;
|
|
||||||
}
|
}
|
||||||
|
uint32_t Metatile::getEncounterTypeMask(BaseGameVersion version) {
|
||||||
void Metatile::setLayerType(uint32_t value) {
|
return Metatile::defaultLayouts.value(version)->value("encounterType").mask;
|
||||||
this->layerType = value & Metatile::customLayout[Attr::LayerType].mask;
|
}
|
||||||
|
uint32_t Metatile::getLayerTypeMask(BaseGameVersion version) {
|
||||||
|
return Metatile::defaultLayouts.value(version)->value("layerType").mask;
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,7 @@ QList<Metatile*> MetatileParser::parse(QString filepath, bool *error, bool prima
|
||||||
uint32_t attributes = 0;
|
uint32_t attributes = 0;
|
||||||
for (int j = 0; j < attrSize; j++)
|
for (int j = 0; j < attrSize; j++)
|
||||||
attributes |= static_cast<unsigned char>(in.at(attrOffset + j)) << (8 * j);
|
attributes |= static_cast<unsigned char>(in.at(attrOffset + j)) << (8 * j);
|
||||||
metatile->convertAttributes(attributes, version);
|
metatile->setAttributes(attributes, version);
|
||||||
metatile->tiles = tiles;
|
metatile->tiles = tiles;
|
||||||
metatiles.append(metatile);
|
metatiles.append(metatile);
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,7 @@ void TilesetEditor::initUi() {
|
||||||
|
|
||||||
void TilesetEditor::setAttributesUi() {
|
void TilesetEditor::setAttributesUi() {
|
||||||
// Behavior
|
// Behavior
|
||||||
if (Metatile::customLayout[Metatile::Attr::Behavior].mask) {
|
if (Metatile::getBehaviorMask()) {
|
||||||
for (int num : project->metatileBehaviorMapInverse.keys()) {
|
for (int num : project->metatileBehaviorMapInverse.keys()) {
|
||||||
this->ui->comboBox_metatileBehaviors->addItem(project->metatileBehaviorMapInverse[num], num);
|
this->ui->comboBox_metatileBehaviors->addItem(project->metatileBehaviorMapInverse[num], num);
|
||||||
}
|
}
|
||||||
|
@ -123,7 +123,7 @@ void TilesetEditor::setAttributesUi() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Terrain Type
|
// Terrain Type
|
||||||
if (Metatile::customLayout[Metatile::Attr::TerrainType].mask) {
|
if (Metatile::getTerrainTypeMask()) {
|
||||||
this->ui->comboBox_terrainType->addItem("Normal", TERRAIN_NONE);
|
this->ui->comboBox_terrainType->addItem("Normal", TERRAIN_NONE);
|
||||||
this->ui->comboBox_terrainType->addItem("Grass", TERRAIN_GRASS);
|
this->ui->comboBox_terrainType->addItem("Grass", TERRAIN_GRASS);
|
||||||
this->ui->comboBox_terrainType->addItem("Water", TERRAIN_WATER);
|
this->ui->comboBox_terrainType->addItem("Water", TERRAIN_WATER);
|
||||||
|
@ -134,7 +134,7 @@ void TilesetEditor::setAttributesUi() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encounter Type
|
// Encounter Type
|
||||||
if (Metatile::customLayout[Metatile::Attr::EncounterType].mask) {
|
if (Metatile::getEncounterTypeMask()) {
|
||||||
this->ui->comboBox_encounterType->addItem("None", ENCOUNTER_NONE);
|
this->ui->comboBox_encounterType->addItem("None", ENCOUNTER_NONE);
|
||||||
this->ui->comboBox_encounterType->addItem("Land", ENCOUNTER_LAND);
|
this->ui->comboBox_encounterType->addItem("Land", ENCOUNTER_LAND);
|
||||||
this->ui->comboBox_encounterType->addItem("Water", ENCOUNTER_WATER);
|
this->ui->comboBox_encounterType->addItem("Water", ENCOUNTER_WATER);
|
||||||
|
@ -148,7 +148,7 @@ void TilesetEditor::setAttributesUi() {
|
||||||
this->ui->comboBox_layerType->addItem("Normal - Middle/Top", METATILE_LAYER_MIDDLE_TOP);
|
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("Covered - Bottom/Middle", METATILE_LAYER_BOTTOM_MIDDLE);
|
||||||
this->ui->comboBox_layerType->addItem("Split - Bottom/Top", METATILE_LAYER_BOTTOM_TOP);
|
this->ui->comboBox_layerType->addItem("Split - Bottom/Top", METATILE_LAYER_BOTTOM_TOP);
|
||||||
if (!Metatile::customLayout[Metatile::Attr::LayerType].mask) {
|
if (!Metatile::getLayerTypeMask()) {
|
||||||
// User doesn't have triple layer metatiles, but has no layer type attribute.
|
// 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
|
// 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
|
// no mask set every metatile will be "Middle/Top", so just display the combo
|
||||||
|
|
Loading…
Reference in a new issue