mirror of
https://github.com/huderlem/porymap.git
synced 2026-08-12 03:45:51 -05:00
Use custom attribute masks in API and Tileset Editor
This commit is contained in:
@@ -21,17 +21,17 @@ const QHash<Metatile::Attr, Metatile::AttrLayout> Metatile::defaultLayoutRSE = {
|
||||
|
||||
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();
|
||||
@@ -60,15 +60,25 @@ QPoint Metatile::coordFromPixmapCoord(const QPointF &pixelCoord) {
|
||||
return QPoint(x, y);
|
||||
}
|
||||
|
||||
void Metatile::setCustomAttributeLayout(Metatile::AttrLayout * layout, uint32_t mask, uint32_t max, QString errName) {
|
||||
void Metatile::setCustomAttributeLayout(Metatile::AttrLayout * layout, uint32_t mask, uint32_t max) {
|
||||
if (mask > max) {
|
||||
logWarn(QString("Metatile %1 mask '%2' exceeds maximum size '%3'").arg(errName).arg(mask).arg(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()));
|
||||
}
|
||||
layout->mask = mask;
|
||||
layout->shift = log2(mask & ~(mask - 1)); // Get the position of the rightmost set bit
|
||||
}
|
||||
|
||||
// For checking whether a metatile attribute mask can contain all the hard-coded values
|
||||
bool Metatile::isMaskTooSmall(Metatile::AttrLayout * layout, int n) {
|
||||
if (!layout->mask) return false;
|
||||
uint32_t maxValue = n - 1;
|
||||
return (maxValue & (layout->mask >> layout->shift)) != maxValue;
|
||||
}
|
||||
|
||||
bool Metatile::doMasksOverlap(QList<uint32_t> masks) {
|
||||
for (int i = 0; i < masks.length(); i++)
|
||||
for (int j = i + 1; j < masks.length(); j++) {
|
||||
@@ -88,10 +98,10 @@ void Metatile::setCustomLayout() {
|
||||
const uint32_t maxMask = maxMasks.value(projectConfig.getMetatileAttributesSize(), 0);
|
||||
|
||||
// Set custom attribute masks from the config file
|
||||
setCustomAttributeLayout(&customLayout[Attr::Behavior], projectConfig.getMetatileBehaviorMask(), maxMask, "behavior");
|
||||
setCustomAttributeLayout(&customLayout[Attr::TerrainType], projectConfig.getMetatileTerrainTypeMask(), maxMask, "terrain type");
|
||||
setCustomAttributeLayout(&customLayout[Attr::EncounterType], projectConfig.getMetatileEncounterTypeMask(), maxMask, "encounter type");
|
||||
setCustomAttributeLayout(&customLayout[Attr::LayerType], projectConfig.getMetatileLayerTypeMask(), maxMask, "layer type");
|
||||
setCustomAttributeLayout(&customLayout[Attr::Behavior], projectConfig.getMetatileBehaviorMask(), maxMask);
|
||||
setCustomAttributeLayout(&customLayout[Attr::TerrainType], projectConfig.getMetatileTerrainTypeMask(), maxMask);
|
||||
setCustomAttributeLayout(&customLayout[Attr::EncounterType], projectConfig.getMetatileEncounterTypeMask(), maxMask);
|
||||
setCustomAttributeLayout(&customLayout[Attr::LayerType], projectConfig.getMetatileLayerTypeMask(), maxMask);
|
||||
|
||||
// Set mask for preserving any attribute bits not used by Porymap
|
||||
Metatile::unusedAttrMask = ~(customLayout[Attr::Behavior].mask
|
||||
@@ -100,13 +110,24 @@ void Metatile::setCustomLayout() {
|
||||
| customLayout[Attr::LayerType].mask);
|
||||
Metatile::unusedAttrMask &= maxMask;
|
||||
|
||||
// Overlapping masks are legal, but probably not intended
|
||||
// Overlapping masks are technically ok, but probably not intended.
|
||||
// Additionally, Porymap will not properly reflect that the values are linked.
|
||||
if (doMasksOverlap({customLayout[Attr::Behavior].mask,
|
||||
customLayout[Attr::TerrainType].mask,
|
||||
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.
|
||||
// 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.
|
||||
if (isMaskTooSmall(&customLayout[Attr::TerrainType], 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))
|
||||
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))
|
||||
logWarn(QString("Metatile Layer Type mask is too small to contain all %1 available options.").arg(NUM_METATILE_LAYER_TYPES));
|
||||
}
|
||||
|
||||
uint32_t Metatile::getAttributes() {
|
||||
@@ -165,3 +186,19 @@ void Metatile::convertAttributes(uint32_t data, BaseGameVersion version) {
|
||||
// Clean data to fit the user's custom masks
|
||||
this->setAttributes(this->getAttributes());
|
||||
}
|
||||
|
||||
void Metatile::setBehavior(uint32_t value) {
|
||||
this->behavior = value & Metatile::customLayout[Attr::Behavior].mask;
|
||||
}
|
||||
|
||||
void Metatile::setTerrainType(uint32_t value) {
|
||||
this->terrainType = value & Metatile::customLayout[Attr::TerrainType].mask;
|
||||
}
|
||||
|
||||
void Metatile::setEncounterType(uint32_t value) {
|
||||
this->encounterType = value & Metatile::customLayout[Attr::EncounterType].mask;
|
||||
}
|
||||
|
||||
void Metatile::setLayerType(uint32_t value) {
|
||||
this->layerType = value & Metatile::customLayout[Attr::LayerType].mask;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user