Merge branch 'master' into label-copy

This commit is contained in:
GriffinR
2022-06-30 00:41:10 -04:00
committed by GitHub
61 changed files with 5372 additions and 2763 deletions

View File

@@ -522,11 +522,11 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) {
if (!ok) {
logWarn(QString("Invalid config value for enable_heal_location_respawn_data: '%1'. Must be 0 or 1.").arg(value));
}
} else if (key == "enable_object_event_in_connection") {
} else if (key == "enable_event_clone_object") {
bool ok;
this->enableObjectEventInConnection = value.toInt(&ok);
this->enableEventCloneObject = value.toInt(&ok);
if (!ok) {
logWarn(QString("Invalid config value for enable_object_event_in_connection: '%1'. Must be 0 or 1.").arg(value));
logWarn(QString("Invalid config value for enable_event_clone_object: '%1'. Must be 0 or 1.").arg(value));
}
} else if (key == "enable_floor_number") {
bool ok;
@@ -570,7 +570,7 @@ void ProjectConfig::setUnreadKeys() {
if (!readKeys.contains("enable_hidden_item_quantity")) this->enableHiddenItemQuantity = isPokefirered;
if (!readKeys.contains("enable_hidden_item_requires_itemfinder")) this->enableHiddenItemRequiresItemfinder = isPokefirered;
if (!readKeys.contains("enable_heal_location_respawn_data")) this->enableHealLocationRespawnData = isPokefirered;
if (!readKeys.contains("enable_object_event_in_connection")) this->enableObjectEventInConnection = isPokefirered;
if (!readKeys.contains("enable_event_clone_object")) this->enableEventCloneObject = isPokefirered;
if (!readKeys.contains("enable_floor_number")) this->enableFloorNumber = isPokefirered;
if (!readKeys.contains("create_map_text_file")) this->createMapTextFile = (this->baseGameVersion != BaseGameVersion::pokeemerald);
}
@@ -587,7 +587,7 @@ QMap<QString, QString> ProjectConfig::getKeyValueMap() {
map.insert("enable_hidden_item_quantity", QString::number(this->enableHiddenItemQuantity));
map.insert("enable_hidden_item_requires_itemfinder", QString::number(this->enableHiddenItemRequiresItemfinder));
map.insert("enable_heal_location_respawn_data", QString::number(this->enableHealLocationRespawnData));
map.insert("enable_object_event_in_connection", QString::number(this->enableObjectEventInConnection));
map.insert("enable_event_clone_object", QString::number(this->enableEventCloneObject));
map.insert("enable_floor_number", QString::number(this->enableFloorNumber));
map.insert("create_map_text_file", QString::number(this->createMapTextFile));
map.insert("enable_triple_layer_metatiles", QString::number(this->enableTripleLayerMetatiles));
@@ -628,7 +628,7 @@ void ProjectConfig::onNewConfigFileCreated() {
this->enableHiddenItemQuantity = isPokefirered;
this->enableHiddenItemRequiresItemfinder = isPokefirered;
this->enableHealLocationRespawnData = isPokefirered;
this->enableObjectEventInConnection = isPokefirered;
this->enableEventCloneObject = isPokefirered;
this->enableFloorNumber = isPokefirered;
this->createMapTextFile = (this->baseGameVersion != BaseGameVersion::pokeemerald);
this->useEncounterJson = true;
@@ -739,13 +739,13 @@ bool ProjectConfig::getHealLocationRespawnDataEnabled() {
return this->enableHealLocationRespawnData;
}
void ProjectConfig::setObjectEventInConnectionEnabled(bool enable) {
this->enableObjectEventInConnection = enable;
void ProjectConfig::setEventCloneObjectEnabled(bool enable) {
this->enableEventCloneObject = enable;
this->save();
}
bool ProjectConfig::getObjectEventInConnectionEnabled() {
return this->enableObjectEventInConnection;
bool ProjectConfig::getEventCloneObjectEnabled() {
return this->enableEventCloneObject;
}
void ProjectConfig::setFloorNumberEnabled(bool enable) {

View File

@@ -9,18 +9,16 @@
int getEventTypeMask(QList<Event *> events) {
int eventTypeMask = 0;
for (auto event : events) {
if (event->get("event_type") == EventType::Object) {
QString groupType = event->get("event_group_type");
if (groupType == EventGroup::Object) {
eventTypeMask |= IDMask_EventType_Object;
} else if (event->get("event_type") == EventType::Warp) {
} else if (groupType == EventGroup::Warp) {
eventTypeMask |= IDMask_EventType_Warp;
} else if (event->get("event_type") == EventType::Trigger ||
event->get("event_type") == EventType::WeatherTrigger) {
} else if (groupType == EventGroup::Coord) {
eventTypeMask |= IDMask_EventType_Trigger;
} else if (event->get("event_type") == EventType::Sign ||
event->get("event_type") == EventType::HiddenItem ||
event->get("event_type") == EventType::SecretBase) {
} else if (groupType == EventGroup::Bg) {
eventTypeMask |= IDMask_EventType_BG;
} else if (event->get("event_type") == EventType::HealLocation) {
} else if (groupType == EventGroup::Heal) {
eventTypeMask |= IDMask_EventType_Heal;
}
}

View File

@@ -3,14 +3,33 @@
#include "project.h"
#include "config.h"
QString EventGroup::Object = "object_event_group";
QString EventGroup::Warp = "warp_event_group";
QString EventGroup::Heal = "heal_event_group";
QString EventGroup::Coord = "coord_event_group";
QString EventGroup::Bg = "bg_event_group";
QString EventType::Object = "event_object";
QString EventType::CloneObject = "event_clone_object";
QString EventType::Warp = "event_warp";
QString EventType::Trigger = "event_trigger";
QString EventType::WeatherTrigger = "event_weather_trigger";
QString EventType::Sign = "event_sign";
QString EventType::HiddenItem = "event_hidden_item";
QString EventType::SecretBase = "event_secret_base";
QString EventType::HealLocation = "event_heal_location";
QString EventType::HealLocation = "event_healspot";
const QMap<QString, QString> EventTypeTable = {
{EventType::Object, EventGroup::Object},
{EventType::CloneObject, EventGroup::Object},
{EventType::Warp, EventGroup::Warp},
{EventType::Trigger, EventGroup::Coord},
{EventType::WeatherTrigger, EventGroup::Coord},
{EventType::Sign, EventGroup::Bg},
{EventType::HiddenItem, EventGroup::Bg},
{EventType::SecretBase, EventGroup::Bg},
{EventType::HealLocation, EventGroup::Heal},
};
Event::Event() :
spriteWidth(16),
@@ -41,6 +60,8 @@ Event* Event::createNewEvent(QString event_type, QString map_name, Project *proj
if (event_type == EventType::Object) {
event = createNewObjectEvent(project);
event->setFrameFromMovement(event->get("movement_type"));
} else if (event_type == EventType::CloneObject) {
event = createNewCloneObjectEvent(project, map_name);
} else if (event_type == EventType::Warp) {
event = createNewWarpEvent(map_name);
} else if (event_type == EventType::HealLocation) {
@@ -60,6 +81,8 @@ Event* Event::createNewEvent(QString event_type, QString map_name, Project *proj
event = new Event;
}
event->put("event_type", event_type);
event->put("event_group_type", typeToGroup(event_type));
event->setX(0);
event->setY(0);
return event;
@@ -68,13 +91,8 @@ Event* Event::createNewEvent(QString event_type, QString map_name, Project *proj
Event* Event::createNewObjectEvent(Project *project)
{
Event *event = new Event;
event->put("event_group_type", "object_event_group");
event->put("event_type", EventType::Object);
event->put("sprite", project->gfxNames.first());
event->put("sprite", project->gfxDefines.keys().first());
event->put("movement_type", project->movementTypes.first());
if (projectConfig.getObjectEventInConnectionEnabled()) {
event->put("in_connection", false);
}
event->put("radius_x", 0);
event->put("radius_y", 0);
event->put("script_label", "NULL");
@@ -86,11 +104,18 @@ Event* Event::createNewObjectEvent(Project *project)
return event;
}
Event* Event::createNewCloneObjectEvent(Project *project, QString map_name)
{
Event *event = new Event;
event->put("sprite", project->gfxDefines.keys().first());
event->put("target_local_id", 1);
event->put("target_map", map_name);
return event;
}
Event* Event::createNewWarpEvent(QString map_name)
{
Event *event = new Event;
event->put("event_group_type", "warp_event_group");
event->put("event_type", EventType::Warp);
event->put("destination_warp", 0);
event->put("destination_map_name", map_name);
event->put("elevation", 0);
@@ -100,8 +125,6 @@ Event* Event::createNewWarpEvent(QString map_name)
Event* Event::createNewHealLocationEvent(QString map_name)
{
Event *event = new Event;
event->put("event_group_type", "heal_event_group");
event->put("event_type", EventType::HealLocation);
event->put("loc_name", QString(Map::mapConstantFromName(map_name)).remove(0,4));
event->put("id_name", map_name.replace(QRegularExpression("([a-z])([A-Z])"), "\\1_\\2").toUpper());
event->put("elevation", 3);
@@ -115,8 +138,6 @@ Event* Event::createNewHealLocationEvent(QString map_name)
Event* Event::createNewTriggerEvent(Project *project)
{
Event *event = new Event;
event->put("event_group_type", "coord_event_group");
event->put("event_type", EventType::Trigger);
event->put("script_label", "NULL");
event->put("script_var", project->varNames.first());
event->put("script_var_value", "0");
@@ -127,8 +148,6 @@ Event* Event::createNewTriggerEvent(Project *project)
Event* Event::createNewWeatherTriggerEvent(Project *project)
{
Event *event = new Event;
event->put("event_group_type", "coord_event_group");
event->put("event_type", EventType::WeatherTrigger);
event->put("weather", project->coordEventWeatherNames.first());
event->put("elevation", 0);
return event;
@@ -137,8 +156,6 @@ Event* Event::createNewWeatherTriggerEvent(Project *project)
Event* Event::createNewSignEvent(Project *project)
{
Event *event = new Event;
event->put("event_group_type", "bg_event_group");
event->put("event_type", EventType::Sign);
event->put("player_facing_direction", project->bgEventFacingDirections.first());
event->put("script_label", "NULL");
event->put("elevation", 0);
@@ -148,8 +165,6 @@ Event* Event::createNewSignEvent(Project *project)
Event* Event::createNewHiddenItemEvent(Project *project)
{
Event *event = new Event;
event->put("event_group_type", "bg_event_group");
event->put("event_type", EventType::HiddenItem);
event->put("item", project->itemNames.first());
event->put("flag", project->flagNames.first());
event->put("elevation", 3);
@@ -165,8 +180,6 @@ Event* Event::createNewHiddenItemEvent(Project *project)
Event* Event::createNewSecretBaseEvent(Project *project)
{
Event *event = new Event;
event->put("event_group_type", "bg_event_group");
event->put("event_type", EventType::SecretBase);
event->put("secret_base_id", project->secretBaseIds.first());
event->put("elevation", 0);
return event;
@@ -182,81 +195,76 @@ int Event::getPixelY()
return (this->y() * 16) - qMax(0, this->spriteHeight - 16);
}
static QMap<QString, bool> expectedObjectFields {
{"graphics_id", true},
{"x", true},
{"y", true},
{"elevation", true},
{"movement_type", true},
{"movement_range_x", true},
{"movement_range_y", true},
{"trainer_type", true},
{"trainer_sight_or_berry_tree_id", true},
{"script", true},
{"flag", true},
const QSet<QString> expectedObjectFields = {
"graphics_id",
"elevation",
"movement_type",
"movement_range_x",
"movement_range_y",
"trainer_type",
"trainer_sight_or_berry_tree_id",
"script",
"flag",
};
static QMap<QString, bool> expectedWarpFields {
{"x", true},
{"y", true},
{"elevation", true},
{"dest_map", true},
{"dest_warp_id", true},
const QSet<QString> expectedCloneObjectFields = {
"type",
"graphics_id",
"target_local_id",
"target_map",
};
static QMap<QString, bool> expectedTriggerFields {
{"type", true},
{"x", true},
{"y", true},
{"elevation", true},
{"var", true},
{"var_value", true},
{"script", true},
const QSet<QString> expectedWarpFields = {
"elevation",
"dest_map",
"dest_warp_id",
};
static QMap<QString, bool> expectedWeatherTriggerFields {
{"type", true},
{"x", true},
{"y", true},
{"elevation", true},
{"weather", true},
const QSet<QString> expectedTriggerFields = {
"type",
"elevation",
"var",
"var_value",
"script",
};
static QMap<QString, bool> expectedSignFields {
{"type", true},
{"x", true},
{"y", true},
{"elevation", true},
{"player_facing_dir", true},
{"script", true},
const QSet<QString> expectedWeatherTriggerFields = {
"type",
"elevation",
"weather",
};
static QMap<QString, bool> expectedHiddenItemFields {
{"type", true},
{"x", true},
{"y", true},
{"elevation", true},
{"item", true},
{"flag", true},
const QSet<QString> expectedSignFields = {
"type",
"elevation",
"player_facing_dir",
"script",
};
static QMap<QString, bool> expectedSecretBaseFields {
{"type", true},
{"x", true},
{"y", true},
{"elevation", true},
{"secret_base_id", true},
const QSet<QString> expectedHiddenItemFields = {
"type",
"elevation",
"item",
"flag",
};
QMap<QString, bool> Event::getExpectedFields()
const QSet<QString> expectedSecretBaseFields = {
"type",
"elevation",
"secret_base_id",
};
QSet<QString> Event::getExpectedFields()
{
QString type = this->get("event_type");
QMap<QString, bool> expectedFields = QMap<QString, bool>();
QSet<QString> expectedFields = QSet<QString>();
if (type == EventType::Object) {
expectedFields = expectedObjectFields;
if (projectConfig.getObjectEventInConnectionEnabled()) {
expectedFields.insert("in_connection", true);
if (projectConfig.getEventCloneObjectEnabled()) {
expectedFields.insert("type");
}
} else if (type == EventType::CloneObject) {
expectedFields = expectedCloneObjectFields;
} else if (type == EventType::Warp) {
expectedFields = expectedWarpFields;
} else if (type == EventType::Trigger) {
@@ -268,23 +276,24 @@ QMap<QString, bool> Event::getExpectedFields()
} else if (type == EventType::HiddenItem) {
expectedFields = expectedHiddenItemFields;
if (projectConfig.getHiddenItemQuantityEnabled()) {
expectedFields.insert("quantity", true);
expectedFields.insert("quantity");
}
if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) {
expectedFields.insert("underfoot", true);
expectedFields.insert("underfoot");
}
} else if (type == EventType::SecretBase) {
expectedFields = expectedSecretBaseFields;
}
expectedFields << "x" << "y";
return expectedFields;
};
void Event::readCustomValues(QJsonObject values)
{
this->customValues.clear();
QMap<QString, bool> expectedValues = this->getExpectedFields();
QSet<QString> expectedFields = this->getExpectedFields();
for (QString key : values.keys()) {
if (!expectedValues.contains(key)) {
if (!expectedFields.contains(key)) {
this->customValues[key] = values[key].toString();
}
}
@@ -301,24 +310,38 @@ void Event::addCustomValuesTo(OrderedJson::object *obj)
OrderedJson::object Event::buildObjectEventJSON()
{
OrderedJson::object eventObj;
eventObj["graphics_id"] = this->get("sprite");
if (projectConfig.getObjectEventInConnectionEnabled()) {
eventObj["in_connection"] = this->getInt("in_connection") > 0 || this->get("in_connection") == "TRUE";
OrderedJson::object objectObj;
if (projectConfig.getEventCloneObjectEnabled()) {
objectObj["type"] = "object";
}
eventObj["x"] = this->getS16("x");
eventObj["y"] = this->getS16("y");
eventObj["elevation"] = this->getInt("elevation");
eventObj["movement_type"] = this->get("movement_type");
eventObj["movement_range_x"] = this->getInt("radius_x");
eventObj["movement_range_y"] = this->getInt("radius_y");
eventObj["trainer_type"] = this->get("trainer_type");
eventObj["trainer_sight_or_berry_tree_id"] = this->get("sight_radius_tree_id");
eventObj["script"] = this->get("script_label");
eventObj["flag"] = this->get("event_flag");
this->addCustomValuesTo(&eventObj);
objectObj["graphics_id"] = this->get("sprite");
objectObj["x"] = this->getS16("x");
objectObj["y"] = this->getS16("y");
objectObj["elevation"] = this->getInt("elevation");
objectObj["movement_type"] = this->get("movement_type");
objectObj["movement_range_x"] = this->getInt("radius_x");
objectObj["movement_range_y"] = this->getInt("radius_y");
objectObj["trainer_type"] = this->get("trainer_type");
objectObj["trainer_sight_or_berry_tree_id"] = this->get("sight_radius_tree_id");
objectObj["script"] = this->get("script_label");
objectObj["flag"] = this->get("event_flag");
this->addCustomValuesTo(&objectObj);
return eventObj;
return objectObj;
}
OrderedJson::object Event::buildCloneObjectEventJSON(const QMap<QString, QString> &mapNamesToMapConstants)
{
OrderedJson::object cloneObj;
cloneObj["type"] = "clone";
cloneObj["graphics_id"] = this->get("sprite");
cloneObj["x"] = this->getS16("x");
cloneObj["y"] = this->getS16("y");
cloneObj["target_local_id"] = this->getInt("target_local_id");
cloneObj["target_map"] = mapNamesToMapConstants.value(this->get("target_map"));
this->addCustomValuesTo(&cloneObj);
return cloneObj;
}
OrderedJson::object Event::buildWarpEventJSON(const QMap<QString, QString> &mapNamesToMapConstants)
@@ -442,3 +465,16 @@ void Event::setFrameFromMovement(QString facingDir) {
this->hFlip = true;
}
}
// All event groups excepts warps have IDs that start at 1
int Event::getIndexOffset(QString group_type) {
return (group_type == EventGroup::Warp) ? 0 : 1;
}
bool Event::isValidType(QString event_type) {
return EventTypeTable.contains(event_type);
}
QString Event::typeToGroup(QString event_type) {
return EventTypeTable.value(event_type, QString());
}

View File

@@ -34,6 +34,9 @@ QString ParseUtil::readTextFile(const QString &path) {
return QString();
}
QTextStream in(&file);
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
in.setCodec("UTF-8");
#endif // Qt6 defaults to UTF-8, but setCodec is renamed to setEncoding
QString text = "";
while (!in.atEnd()) {
text += in.readLine() + '\n';

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,286 @@
#include "regionmapeditcommands.h"
EditTilemap::EditTilemap(RegionMap *map, QByteArray oldTilemap, QByteArray newTilemap, unsigned actionId, QUndoCommand *parent)
: QUndoCommand(parent) {
setText("Edit Tilemap");
this->map = map;
this->oldTilemap = oldTilemap;
this->newTilemap = newTilemap;
this->actionId = actionId;
}
void EditTilemap::redo() {
QUndoCommand::redo();
if (!map) return;
map->setTilemap(this->newTilemap);
}
void EditTilemap::undo() {
if (!map) return;
map->setTilemap(this->oldTilemap);
QUndoCommand::undo();
}
bool EditTilemap::mergeWith(const QUndoCommand *command) {
const EditTilemap *other = static_cast<const EditTilemap *>(command);
if (this->map != other->map)
return false;
if (this->actionId != other->actionId)
return false;
newTilemap = other->newTilemap;
return true;
}
///
EditLayout::EditLayout(RegionMap *map, QString layer, int index, QList<LayoutSquare> oldLayout, QList<LayoutSquare> newLayout, QUndoCommand *parent)
: QUndoCommand(parent) {
setText("Edit Layout");
this->map = map;
this->layer = layer;
this->index = index;
this->oldLayout = oldLayout;
this->newLayout = newLayout;
}
void EditLayout::redo() {
QUndoCommand::redo();
if (!map) return;
map->setLayout(this->layer, this->newLayout);
}
void EditLayout::undo() {
if (!map) return;
map->setLayout(this->layer, this->oldLayout);
QUndoCommand::undo();
}
bool EditLayout::mergeWith(const QUndoCommand *command) {
const EditLayout *other = static_cast<const EditLayout *>(command);
if (this->map != other->map)
return false;
if (this->text() != other->text())
return false;
if (this->index != other->index)
return false;
this->newLayout = other->newLayout;
return true;
}
///
ResizeLayout::ResizeLayout(RegionMap *map, int oldWidth, int oldHeight, int newWidth, int newHeight,
QMap<QString, QList<LayoutSquare>> oldLayouts, QMap<QString, QList<LayoutSquare>> newLayouts, QUndoCommand *parent)
: QUndoCommand(parent) {
setText("Change Layout Dimensions");
this->map = map;
this->oldWidth = oldWidth;
this->oldHeight = oldHeight;
this->newWidth = newWidth;
this->newHeight = newHeight;
this->oldLayouts = oldLayouts;
this->newLayouts = newLayouts;
}
void ResizeLayout::redo() {
QUndoCommand::redo();
if (!map) return;
map->setLayoutDimensions(newWidth, newHeight, false);
map->setAllLayouts(this->newLayouts);
}
void ResizeLayout::undo() {
if (!map) return;
map->setLayoutDimensions(oldWidth, oldHeight, false);
map->setAllLayouts(this->oldLayouts);
QUndoCommand::undo();
}
bool ResizeLayout::mergeWith(const QUndoCommand *command) {
const ResizeLayout *other = static_cast<const ResizeLayout *>(command);
if (this->map != other->map)
return false;
// always allow consecutive dimension changes to merge
this->newWidth = other->newWidth;
this->newHeight = other->newHeight;
this->newLayouts = other->newLayouts;
return true;
}
///
EditEntry::EditEntry(RegionMap *map, QString section, MapSectionEntry oldEntry, MapSectionEntry newEntry, QUndoCommand *parent)
: QUndoCommand(parent) {
setText("Change Entry for " + section);
this->map = map;
this->section = section;
this->oldEntry = oldEntry;
this->newEntry = newEntry;
}
void EditEntry::redo() {
QUndoCommand::redo();
if (!map) return;
map->setEntry(section, newEntry);
}
void EditEntry::undo() {
if (!map) return;
map->setEntry(section, oldEntry);
QUndoCommand::undo();
}
bool EditEntry::mergeWith(const QUndoCommand *command) {
const EditEntry *other = static_cast<const EditEntry *>(command);
if (this->map != other->map)
return false;
if (this->section != other->section)
return false;
this->newEntry = other->newEntry;
return true;
}
///
AddEntry::AddEntry(RegionMap *map, QString section, MapSectionEntry oldEntry, MapSectionEntry newEntry, QUndoCommand *parent)
: EditEntry(map, section, oldEntry, newEntry, parent) {
setText("Add Entry for " + section);
}
void AddEntry::redo() {
QUndoCommand::redo();
if (!map) return;
map->setEntry(section, newEntry);
}
void AddEntry::undo() {
if (!map) return;
map->removeEntry(section);
QUndoCommand::undo();
}
///
RemoveEntry::RemoveEntry(RegionMap *map, QString section, MapSectionEntry oldEntry, MapSectionEntry newEntry, QUndoCommand *parent)
: EditEntry(map, section, oldEntry, newEntry, parent) {
setText("Remove Entry for " + section);
}
void RemoveEntry::redo() {
QUndoCommand::redo();
if (!map) return;
map->removeEntry(section);
}
void RemoveEntry::undo() {
if (!map) return;
map->setEntry(section, oldEntry);
QUndoCommand::undo();
}
///
ResizeTilemap::ResizeTilemap(RegionMap *map, QByteArray oldTilemap, QByteArray newTilemap,
int oldWidth, int oldHeight, int newWidth, int newHeight, QUndoCommand *parent)
: EditTilemap(map, oldTilemap, newTilemap, -1, parent) {
setText("Resize Tilemap");
this->oldWidth = oldWidth;
this->oldHeight = oldHeight;
this->newWidth = newWidth;
this->newHeight = newHeight;
}
void ResizeTilemap::redo() {
QUndoCommand::redo();
if (!map) return;
map->resizeTilemap(this->newWidth, this->newHeight, false);
map->setTilemap(this->newTilemap);
map->emitDisplay();
}
void ResizeTilemap::undo() {
if (!map) return;
map->resizeTilemap(this->oldWidth, this->oldHeight, false);
map->setTilemap(this->oldTilemap);
map->emitDisplay();
QUndoCommand::undo();
}
///
ClearEntries::ClearEntries(RegionMap *map, tsl::ordered_map<QString, MapSectionEntry> entries, QUndoCommand *parent) {
setText("Clear Entries");
this->map = map;
this->entries = entries;
}
void ClearEntries::redo() {
QUndoCommand::redo();
if (!map) return;
map->clearEntries();
}
void ClearEntries::undo() {
if (!map) return;
map->setEntries(entries);
QUndoCommand::undo();
}

View File

@@ -188,7 +188,7 @@ bool Tileset::appendToMetatiles(QString metatileFile, QString friendlyName, bool
dataString.append(QString("\t.incbin \"data/tilesets/%1/%2/metatiles.bin\"\n").arg(primaryString, friendlyName.toLower()));
dataString.append(QString("\n\t.align 1\n"));
dataString.append(QString("gMetatileAttributes_%1::\n").arg(friendlyName));
dataString.append(QString("\t.incbin \"data/tilesets/%1/%2/metatile_attributes.bin\"").arg(primaryString, friendlyName.toLower()));
dataString.append(QString("\t.incbin \"data/tilesets/%1/%2/metatile_attributes.bin\"\n").arg(primaryString, friendlyName.toLower()));
file.write(dataString.toUtf8());
file.flush();
file.close();

View File

@@ -2064,8 +2064,8 @@ DraggablePixmapItem* Editor::addNewEvent(QString event_type) {
bool Editor::eventLimitReached(Map *map, QString event_type)
{
if (project && map && !event_type.isEmpty()) {
if (event_type == EventType::Object)
return map->events.value("object_event_group").length() >= project->getMaxObjectEvents();
if (Event::typeToGroup(event_type) == EventGroup::Object)
return map->events.value(EventGroup::Object).length() >= project->getMaxObjectEvents();
}
return false;
}

View File

@@ -349,12 +349,15 @@ void MainWindow::markMapEdited() {
}
}
void MainWindow::setWildEncountersUIEnabled(bool enabled) {
ui->actionUse_Encounter_Json->setChecked(enabled);
ui->mainTabBar->setTabEnabled(4, enabled);
}
void MainWindow::setProjectSpecificUIVisibility()
{
ui->actionUse_Encounter_Json->setChecked(projectConfig.getEncounterJsonActive());
ui->actionUse_Poryscript->setChecked(projectConfig.getUsePoryScript());
ui->mainTabBar->setTabEnabled(4, projectConfig.getEncounterJsonActive());
this->setWildEncountersUIEnabled(projectConfig.getEncounterJsonActive());
switch (projectConfig.getBaseGameVersion())
{
@@ -385,27 +388,17 @@ void MainWindow::setProjectSpecificUIVisibility()
ui->label_AllowEscapeRope->setVisible(true);
// TODO: pokefirered is not set up for the Region Map Editor and vice versa.
// porymap will crash on attempt. Remove below once resolved
ui->actionRegion_Map_Editor->setVisible(false);
ui->actionRegion_Map_Editor->setVisible(true);
break;
}
if (projectConfig.getEventWeatherTriggerEnabled()) {
ui->newEventToolButton->newWeatherTriggerAction->setVisible(true);
} else {
ui->newEventToolButton->newWeatherTriggerAction->setVisible(false);
}
if (projectConfig.getEventSecretBaseEnabled()) {
ui->newEventToolButton->newSecretBaseAction->setVisible(true);
} else {
ui->newEventToolButton->newSecretBaseAction->setVisible(false);
}
if (projectConfig.getFloorNumberEnabled()) {
ui->spinBox_FloorNumber->setVisible(true);
ui->label_FloorNumber->setVisible(true);
} else {
ui->spinBox_FloorNumber->setVisible(false);
ui->label_FloorNumber->setVisible(false);
}
ui->newEventToolButton->newWeatherTriggerAction->setVisible(projectConfig.getEventWeatherTriggerEnabled());
ui->newEventToolButton->newSecretBaseAction->setVisible(projectConfig.getEventSecretBaseEnabled());
ui->newEventToolButton->newCloneObjectAction->setVisible(projectConfig.getEventCloneObjectEnabled());
bool floorNumEnabled = projectConfig.getFloorNumberEnabled();
ui->spinBox_FloorNumber->setVisible(floorNumEnabled);
ui->label_FloorNumber->setVisible(floorNumEnabled);
}
void MainWindow::mapSortOrder_changed(QAction *action)
@@ -525,6 +518,7 @@ bool MainWindow::openProject(QString dir) {
editor->project = new Project(this);
QObject::connect(editor->project, &Project::reloadProject, this, &MainWindow::on_action_Reload_Project_triggered);
QObject::connect(editor->project, &Project::mapCacheCleared, this, &MainWindow::onMapCacheCleared);
QObject::connect(editor->project, &Project::disableWildEncountersUI, [this]() { this->setWildEncountersUIEnabled(false); });
QObject::connect(editor->project, &Project::uncheckMonitorFilesAction, [this]() { ui->actionMonitor_Project_Files->setChecked(false); });
on_actionMonitor_Project_Files_triggered(porymapConfig.getMonitorFiles());
editor->project->set_root(dir);
@@ -702,22 +696,22 @@ void MainWindow::refreshMapScene()
on_horizontalSlider_MetatileZoom_valueChanged(ui->horizontalSlider_MetatileZoom->value());
}
void MainWindow::openWarpMap(QString map_name, QString warp_num) {
void MainWindow::openWarpMap(QString map_name, QString event_id, QString event_group) {
// Ensure valid destination map name.
if (!editor->project->mapNames.contains(map_name)) {
logError(QString("Invalid warp destination map name '%1'").arg(map_name));
logError(QString("Invalid map name '%1'").arg(map_name));
return;
}
// Ensure valid destination warp number.
// Ensure valid event number.
bool ok;
int warpNum = warp_num.toInt(&ok, 0);
int event_index = event_id.toInt(&ok, 0);
if (!ok) {
logError(QString("Invalid warp number '%1' for destination map '%2'").arg(warp_num).arg(map_name));
logError(QString("Invalid event number '%1' for map '%2'").arg(event_id).arg(map_name));
return;
}
// Open the destination map, and select the target warp event.
// Open the destination map.
if (!setMap(map_name, true)) {
QMessageBox msgBox(this);
QString errorMsg = QString("There was an error opening map %1. Please see %2 for full error details.\n\n%3")
@@ -728,11 +722,13 @@ void MainWindow::openWarpMap(QString map_name, QString warp_num) {
return;
}
QList<Event*> warp_events = editor->map->events["warp_event_group"];
if (warp_events.length() > warpNum) {
Event *warp_event = warp_events.at(warpNum);
// Select the target event.
event_index -= Event::getIndexOffset(event_group);
QList<Event*> events = editor->map->events[event_group];
if (event_index < events.length() && event_index >= 0) {
Event *event = events.at(event_index);
for (DraggablePixmapItem *item : editor->getObjects()) {
if (item->event == warp_event) {
if (item->event == event) {
editor->selected_events->clear();
editor->selected_events->append(item);
editor->updateSelectedEvents();
@@ -1170,11 +1166,11 @@ void MainWindow::onAddNewMapToLayoutClick(QAction* triggeredAction)
}
void MainWindow::onNewMapCreated() {
QString newMapName = this->newmapprompt->map->name;
int newMapGroup = this->newmapprompt->group;
Map *newMap = this->newmapprompt->map;
bool existingLayout = this->newmapprompt->existingLayout;
bool importedMap = this->newmapprompt->importedMap;
QString newMapName = this->newMapPrompt->map->name;
int newMapGroup = this->newMapPrompt->group;
Map *newMap = this->newMapPrompt->map;
bool existingLayout = this->newMapPrompt->existingLayout;
bool importedMap = this->newMapPrompt->importedMap;
newMap = editor->project->addNewMapToGroup(newMapName, newMapGroup, newMap, existingLayout, importedMap);
@@ -1199,52 +1195,52 @@ void MainWindow::onNewMapCreated() {
editor->save();// required
}
disconnect(this->newmapprompt, &NewMapPopup::applied, this, &MainWindow::onNewMapCreated);
disconnect(this->newMapPrompt, &NewMapPopup::applied, this, &MainWindow::onNewMapCreated);
delete newMap;
}
void MainWindow::openNewMapPopupWindow(int type, QVariant data) {
if (!this->newmapprompt) {
this->newmapprompt = new NewMapPopup(this, this->editor->project);
if (!this->newMapPrompt) {
this->newMapPrompt = new NewMapPopup(this, this->editor->project);
}
if (!this->newmapprompt->isVisible()) {
this->newmapprompt->show();
if (!this->newMapPrompt->isVisible()) {
this->newMapPrompt->show();
} else {
this->newmapprompt->raise();
this->newmapprompt->activateWindow();
this->newMapPrompt->raise();
this->newMapPrompt->activateWindow();
}
switch (type)
{
case MapSortOrder::Group:
this->newmapprompt->init(type, data.toInt(), QString(), QString());
this->newMapPrompt->init(type, data.toInt(), QString(), QString());
break;
case MapSortOrder::Area:
this->newmapprompt->init(type, 0, data.toString(), QString());
this->newMapPrompt->init(type, 0, data.toString(), QString());
break;
case MapSortOrder::Layout:
this->newmapprompt->init(type, 0, QString(), data.toString());
this->newMapPrompt->init(type, 0, QString(), data.toString());
break;
}
connect(this->newmapprompt, &NewMapPopup::applied, this, &MainWindow::onNewMapCreated);
this->newmapprompt->setAttribute(Qt::WA_DeleteOnClose);
connect(this->newMapPrompt, &NewMapPopup::applied, this, &MainWindow::onNewMapCreated);
this->newMapPrompt->setAttribute(Qt::WA_DeleteOnClose);
}
void MainWindow::openNewMapPopupWindowImportMap(MapLayout *mapLayout) {
if (!this->newmapprompt) {
this->newmapprompt = new NewMapPopup(this, this->editor->project);
if (!this->newMapPrompt) {
this->newMapPrompt = new NewMapPopup(this, this->editor->project);
}
if (!this->newmapprompt->isVisible()) {
this->newmapprompt->show();
if (!this->newMapPrompt->isVisible()) {
this->newMapPrompt->show();
} else {
this->newmapprompt->raise();
this->newmapprompt->activateWindow();
this->newMapPrompt->raise();
this->newMapPrompt->activateWindow();
}
this->newmapprompt->initImportMap(mapLayout);
this->newMapPrompt->initImportMap(mapLayout);
connect(this->newmapprompt, SIGNAL(applied()), this, SLOT(onNewMapCreated()));
connect(this->newmapprompt, &QObject::destroyed, [=](QObject *) { this->newmapprompt = nullptr; });
this->newmapprompt->setAttribute(Qt::WA_DeleteOnClose);
connect(this->newMapPrompt, SIGNAL(applied()), this, SLOT(onNewMapCreated()));
connect(this->newMapPrompt, &QObject::destroyed, [=](QObject *) { this->newMapPrompt = nullptr; });
this->newMapPrompt->setAttribute(Qt::WA_DeleteOnClose);
}
void MainWindow::on_action_NewMap_triggered() {
@@ -1802,14 +1798,11 @@ void MainWindow::connectSubEditorsToShortcutsEditor() {
connect(shortcutsEditor, &ShortcutsEditor::shortcutsSaved,
tilesetEditor, &TilesetEditor::applyUserShortcuts);
// TODO: Remove this check when the region map editor supports pokefirered.
if (projectConfig.getBaseGameVersion() != BaseGameVersion::pokefirered) {
if (!regionMapEditor)
initRegionMapEditor();
if (regionMapEditor)
connect(shortcutsEditor, &ShortcutsEditor::shortcutsSaved,
regionMapEditor, &RegionMapEditor::applyUserShortcuts);
}
if (!regionMapEditor)
initRegionMapEditor();
if (regionMapEditor)
connect(shortcutsEditor, &ShortcutsEditor::shortcutsSaved,
regionMapEditor, &RegionMapEditor::applyUserShortcuts);
}
void MainWindow::on_actionPencil_triggered()
@@ -1859,7 +1852,7 @@ void MainWindow::addNewEvent(QString event_type)
} else {
QMessageBox msgBox(this);
msgBox.setText("Failed to add new event");
if (event_type == EventType::Object) {
if (Event::typeToGroup(event_type) == EventGroup::Object) {
msgBox.setInformativeText(QString("The limit for object events (%1) has been reached.\n\n"
"This limit can be adjusted with OBJECT_EVENT_TEMPLATES_COUNT in 'include/constants/global.h'.")
.arg(editor->project->getMaxObjectEvents()));
@@ -1879,57 +1872,20 @@ void MainWindow::updateObjects() {
selectedHealspot = nullptr;
ui->tabWidget_EventType->clear();
bool hasObjects = false;
bool hasWarps = false;
bool hasTriggers = false;
bool hasBGs = false;
bool hasHealspots = false;
for (DraggablePixmapItem *item : editor->getObjects())
{
QString event_type = item->event->get("event_type");
if (event_type == EventType::Object) {
hasObjects = true;
}
else if (event_type == EventType::Warp) {
hasWarps = true;
}
else if (event_type == EventType::Trigger || event_type == EventType::WeatherTrigger) {
hasTriggers = true;
}
else if (event_type == EventType::Sign || event_type == EventType::HiddenItem || event_type == EventType::SecretBase) {
hasBGs = true;
}
else if (event_type == EventType::HealLocation) {
hasHealspots = true;
}
}
if (hasObjects)
{
if (editor->map->events.value(EventGroup::Object).length())
ui->tabWidget_EventType->addTab(eventTabObjectWidget, "Objects");
}
if (hasWarps)
{
if (editor->map->events.value(EventGroup::Warp).length())
ui->tabWidget_EventType->addTab(eventTabWarpWidget, "Warps");
}
if (hasTriggers)
{
if (editor->map->events.value(EventGroup::Coord).length())
ui->tabWidget_EventType->addTab(eventTabTriggerWidget, "Triggers");
}
if (hasBGs)
{
if (editor->map->events.value(EventGroup::Bg).length())
ui->tabWidget_EventType->addTab(eventTabBGWidget, "BGs");
}
if (hasHealspots)
{
if (editor->map->events.value(EventGroup::Heal).length())
ui->tabWidget_EventType->addTab(eventTabHealspotWidget, "Healspots");
}
updateSelectedObjects();
}
@@ -1956,7 +1912,6 @@ void MainWindow::updateSelectedObjects() {
QList<EventPropertiesFrame *> frames;
bool inConnectionEnabled = projectConfig.getObjectEventInConnectionEnabled();
bool quantityEnabled = projectConfig.getHiddenItemQuantityEnabled();
bool underfootEnabled = projectConfig.getHiddenItemRequiresItemfinderEnabled();
bool respawnDataEnabled = projectConfig.getHealLocationRespawnDataEnabled();
@@ -1991,9 +1946,7 @@ void MainWindow::updateSelectedObjects() {
QString event_type = item->event->get("event_type");
QString event_group_type = item->event->get("event_group_type");
QString map_name = item->event->get("map_name");
int event_offs;
if (event_type == EventType::Warp) { event_offs = 0; }
else { event_offs = 1; }
int event_offs = Event::getIndexOffset(event_group_type);
frame->ui->label_name->setText(QString("%1 Id").arg(event_type));
if (events.count() == 1)
@@ -2021,7 +1974,6 @@ void MainWindow::updateSelectedObjects() {
field_labels["radius_y"] = "Movement Radius Y";
field_labels["trainer_type"] = "Trainer Type";
field_labels["sight_radius_tree_id"] = "Sight Radius / Berry Tree ID";
field_labels["in_connection"] = "In Connection";
field_labels["destination_warp"] = "Destination Warp";
field_labels["destination_map_name"] = "Destination Map";
field_labels["script_var"] = "Var";
@@ -2035,13 +1987,15 @@ void MainWindow::updateSelectedObjects() {
field_labels["secret_base_id"] = "Secret Base Id";
field_labels["respawn_map"] = "Respawn Map";
field_labels["respawn_npc"] = "Respawn NPC";
field_labels["target_local_id"] = "Target Local Id";
field_labels["target_map"] = "Target Map";
QStringList fields;
if (event_type == EventType::Object) {
frame->ui->sprite->setVisible(true);
frame->ui->comboBox_sprite->addItems(editor->project->gfxNames);
frame->ui->comboBox_sprite->addItems(editor->project->gfxDefines.keys());
frame->ui->comboBox_sprite->setCurrentIndex(frame->ui->comboBox_sprite->findText(item->event->get("sprite")));
connect(frame->ui->comboBox_sprite, &QComboBox::currentTextChanged, item, &DraggablePixmapItem::set_sprite);
connect(frame->ui->comboBox_sprite, &QComboBox::currentTextChanged, this, &MainWindow::markMapEdited);
@@ -2063,7 +2017,17 @@ void MainWindow::updateSelectedObjects() {
fields << "event_flag";
fields << "trainer_type";
fields << "sight_radius_tree_id";
if (inConnectionEnabled) fields << "in_connection";
}
else if (event_type == EventType::CloneObject) {
frame->ui->sprite->setVisible(true);
frame->ui->comboBox_sprite->setEnabled(false);
frame->ui->comboBox_sprite->addItem(item->event->get("sprite"));
frame->ui->spinBox_z->setVisible(false);
frame->ui->label_z->setVisible(false);
fields << "target_local_id";
fields << "target_map";
}
else if (event_type == EventType::Warp) {
fields << "destination_map_name";
@@ -2101,8 +2065,8 @@ void MainWindow::updateSelectedObjects() {
}
// Some keys shouldn't use a combobox
QStringList spinKeys = {"quantity", "respawn_npc"};
QStringList checkKeys = {"underfoot", "in_connection"};
QStringList spinKeys = {"quantity", "respawn_npc", "target_local_id"};
QStringList checkKeys = {"underfoot"};
for (QString key : fields) {
QString value = item->event->get(key);
QWidget *widget = new QWidget(frame);
@@ -2226,8 +2190,6 @@ void MainWindow::updateSelectedObjects() {
combo->setToolTip("The maximum sight range of a trainer,\n"
"OR the unique id of the berry tree.");
combo->setMinimumContentsLength(4);
} else if (key == "in_connection") {
check->setToolTip("Check if object is positioned in the connection to another map.");
} else if (key == "respawn_map") {
if (!editor->project->mapNames.contains(value)) {
combo->addItem(value);
@@ -2239,6 +2201,27 @@ void MainWindow::updateSelectedObjects() {
"upon respawning after whiteout.");
spin->setMinimum(1);
spin->setMaximum(126);
} else if (key == "target_local_id") {
spin->setToolTip("event_object ID of the object being cloned.");
spin->setMinimum(1);
spin->setMaximum(126);
connect(spin, QOverload<int>::of(&NoScrollSpinBox::valueChanged), [item, frame](int value) {
item->event->put("target_local_id", value);
item->updatePixmap();
frame->ui->comboBox_sprite->setItemText(0, item->event->get("sprite"));
});
} else if (key == "target_map") {
if (!editor->project->mapNames.contains(value)) {
combo->addItem(value);
}
combo->addItems(editor->project->mapNames);
combo->setCurrentIndex(combo->findText(value));
combo->setToolTip("The name of the map that the object being cloned is on.");
connect(combo, static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::currentTextChanged), this, [item, frame](QString value){
item->event->put("target_map", value);
item->updatePixmap();
frame->ui->comboBox_sprite->setItemText(0, item->event->get("sprite"));
});
} else {
combo->addItem(value);
}
@@ -2323,27 +2306,27 @@ void MainWindow::updateSelectedObjects() {
{
QString event_group_type = events[0]->event->get("event_group_type");
if (event_group_type == "object_event_group") {
if (event_group_type == EventGroup::Object) {
scrollTarget = ui->scrollArea_Objects;
target = ui->scrollAreaWidgetContents_Objects;
ui->tabWidget_EventType->setCurrentWidget(ui->tab_Objects);
}
else if (event_group_type == "warp_event_group") {
else if (event_group_type == EventGroup::Warp) {
scrollTarget = ui->scrollArea_Warps;
target = ui->scrollAreaWidgetContents_Warps;
ui->tabWidget_EventType->setCurrentWidget(ui->tab_Warps);
}
else if (event_group_type == "coord_event_group") {
else if (event_group_type == EventGroup::Coord) {
scrollTarget = ui->scrollArea_Triggers;
target = ui->scrollAreaWidgetContents_Triggers;
ui->tabWidget_EventType->setCurrentWidget(ui->tab_Triggers);
}
else if (event_group_type == "bg_event_group") {
else if (event_group_type == EventGroup::Bg) {
scrollTarget = ui->scrollArea_BGs;
target = ui->scrollAreaWidgetContents_BGs;
ui->tabWidget_EventType->setCurrentWidget(ui->tab_BGs);
}
else if (event_group_type == "heal_event_group") {
else if (event_group_type == EventGroup::Heal) {
scrollTarget = ui->scrollArea_Healspots;
target = ui->scrollAreaWidgetContents_Healspots;
ui->tabWidget_EventType->setCurrentWidget(ui->tab_Healspots);
@@ -2400,23 +2383,23 @@ QString MainWindow::getEventGroupFromTabWidget(QWidget *tab)
QString ret = "";
if (tab == eventTabObjectWidget)
{
ret = "object_event_group";
ret = EventGroup::Object;
}
else if (tab == eventTabWarpWidget)
{
ret = "warp_event_group";
ret = EventGroup::Warp;
}
else if (tab == eventTabTriggerWidget)
{
ret = "coord_event_group";
ret = EventGroup::Coord;
}
else if (tab == eventTabBGWidget)
{
ret = "bg_event_group";
ret = EventGroup::Bg;
}
else if (tab == eventTabHealspotWidget)
{
ret = "heal_event_group";
ret = EventGroup::Heal;
}
return ret;
}
@@ -2426,23 +2409,23 @@ void MainWindow::eventTabChanged(int index) {
QString group = getEventGroupFromTabWidget(ui->tabWidget_EventType->widget(index));
DraggablePixmapItem *selectedEvent = nullptr;
if (group == "object_event_group") {
if (group == EventGroup::Object) {
selectedEvent = selectedObject;
ui->newEventToolButton->setDefaultAction(ui->newEventToolButton->newObjectAction);
}
else if (group == "warp_event_group") {
else if (group == EventGroup::Warp) {
selectedEvent = selectedWarp;
ui->newEventToolButton->setDefaultAction(ui->newEventToolButton->newWarpAction);
}
else if (group == "coord_event_group") {
else if (group == EventGroup::Coord) {
selectedEvent = selectedTrigger;
ui->newEventToolButton->setDefaultAction(ui->newEventToolButton->newTriggerAction);
}
else if (group == "bg_event_group") {
else if (group == EventGroup::Bg) {
selectedEvent = selectedBG;
ui->newEventToolButton->setDefaultAction(ui->newEventToolButton->newSignAction);
}
else if (group == "heal_event_group") {
else if (group == EventGroup::Heal) {
selectedEvent = selectedHealspot;
}
@@ -2468,7 +2451,7 @@ void MainWindow::eventTabChanged(int index) {
void MainWindow::selectedEventIndexChanged(int index)
{
QString group = getEventGroupFromTabWidget(ui->tabWidget_EventType->currentWidget());
int event_offs = group == "warp_event_group" ? 0 : 1;
int event_offs = Event::getIndexOffset(group);
Event *event = editor->map->events.value(group).at(index - event_offs);
DraggablePixmapItem *selectedEvent = nullptr;
for (QGraphicsItem *child : editor->events_group->childItems()) {
@@ -2502,7 +2485,7 @@ void MainWindow::on_toolButton_deleteObject_clicked() {
int numDeleted = 0;
for (DraggablePixmapItem *item : *editor->selected_events) {
QString event_group = item->event->get("event_group_type");
if (event_group != "heal_event_group") {
if (event_group != EventGroup::Heal) {
// Get the index for the event that should be selected after this event has been deleted.
// If it's at the end of the list, select the previous event, otherwise select the next one.
// Don't bother getting the event to select if there are still more events to delete
@@ -3164,8 +3147,12 @@ void MainWindow::on_actionRegion_Map_Editor_triggered() {
bool MainWindow::initRegionMapEditor() {
this->regionMapEditor = new RegionMapEditor(this, this->editor->project);
bool success = this->regionMapEditor->loadRegionMapData()
&& this->regionMapEditor->loadCityMaps();
this->regionMapEditor->setAttribute(Qt::WA_DeleteOnClose);
connect(this->regionMapEditor, &QObject::destroyed, [this](){
this->regionMapEditor = nullptr;
});
bool success = this->regionMapEditor->load();
if (!success) {
delete this->regionMapEditor;
this->regionMapEditor = nullptr;
@@ -3182,16 +3169,26 @@ bool MainWindow::initRegionMapEditor() {
}
void MainWindow::closeSupplementaryWindows() {
if (this->tilesetEditor)
if (this->tilesetEditor) {
delete this->tilesetEditor;
if (this->regionMapEditor)
this->tilesetEditor = nullptr;
}
if (this->regionMapEditor) {
delete this->regionMapEditor;
if (this->mapImageExporter)
this->regionMapEditor = nullptr;
}
if (this->mapImageExporter) {
delete this->mapImageExporter;
if (this->newmapprompt)
delete this->newmapprompt;
if (this->shortcutsEditor)
this->mapImageExporter = nullptr;
}
if (this->newMapPrompt) {
delete this->newMapPrompt;
this->newMapPrompt = nullptr;
}
if (this->shortcutsEditor) {
delete this->shortcutsEditor;
this->shortcutsEditor = nullptr;
}
}
void MainWindow::closeEvent(QCloseEvent *event) {

View File

@@ -833,7 +833,7 @@ void MainWindow::saveMetatileAttributesByMetatileId(int metatileId) {
this->editor->project->saveTilesetMetatileAttributes(tileset);
// If the Tileset Editor is currently displaying the updated metatile, refresh it
if (this->tilesetEditor && this->tilesetEditor->getSelectedMetatile() == metatileId)
if (this->tilesetEditor && this->tilesetEditor->getSelectedMetatileId() == metatileId)
this->tilesetEditor->updateTilesets(this->editor->map->layout->tileset_primary_label, this->editor->map->layout->tileset_secondary_label);
}
@@ -863,7 +863,7 @@ void MainWindow::setMetatileLabel(int metatileId, QString label) {
return;
}
if (this->tilesetEditor && this->tilesetEditor->getSelectedMetatile() == metatileId) {
if (this->tilesetEditor && this->tilesetEditor->getSelectedMetatileId() == metatileId) {
this->tilesetEditor->setMetatileLabel(label);
} else if (metatile->label != label) {
metatile->label = label;

View File

@@ -211,31 +211,56 @@ bool Project::loadMapData(Map* map) {
map->sharedScriptsMap = mapObj["shared_scripts_map"].toString();
// Events
map->events["object_event_group"].clear();
map->events[EventGroup::Object].clear();
QJsonArray objectEventsArr = mapObj["object_events"].toArray();
bool hasCloneObjects = projectConfig.getEventCloneObjectEnabled();
for (int i = 0; i < objectEventsArr.size(); i++) {
QJsonObject event = objectEventsArr[i].toObject();
Event *object = new Event(event, EventType::Object);
object->put("map_name", map->name);
object->put("sprite", event["graphics_id"].toString());
if (projectConfig.getObjectEventInConnectionEnabled()) {
object->put("in_connection", event["in_connection"].toBool());
// If clone objects are not enabled then no type field is present
QString type = hasCloneObjects ? event["type"].toString() : "object";
if (type.isEmpty() || type == "object") {
Event *object = new Event(event, EventType::Object);
object->put("map_name", map->name);
object->put("sprite", event["graphics_id"].toString());
object->put("x", QString::number(event["x"].toInt()));
object->put("y", QString::number(event["y"].toInt()));
object->put("elevation", QString::number(event["elevation"].toInt()));
object->put("movement_type", event["movement_type"].toString());
object->put("radius_x", QString::number(event["movement_range_x"].toInt()));
object->put("radius_y", QString::number(event["movement_range_y"].toInt()));
object->put("trainer_type", event["trainer_type"].toString());
object->put("sight_radius_tree_id", event["trainer_sight_or_berry_tree_id"].toString());
object->put("script_label", event["script"].toString());
object->put("event_flag", event["flag"].toString());
object->put("event_group_type", EventGroup::Object);
map->events[EventGroup::Object].append(object);
} else if (type == "clone") {
Event *object = new Event(event, EventType::CloneObject);
object->put("map_name", map->name);
object->put("sprite", event["graphics_id"].toString());
object->put("x", QString::number(event["x"].toInt()));
object->put("y", QString::number(event["y"].toInt()));
object->put("target_local_id", QString::number(event["target_local_id"].toInt()));
// Ensure the target map constant is valid before adding it to the events.
QString mapConstant = event["target_map"].toString();
if (mapConstantsToMapNames.contains(mapConstant)) {
object->put("target_map", mapConstantsToMapNames.value(mapConstant));
object->put("event_group_type", EventGroup::Object);
map->events[EventGroup::Object].append(object);
} else if (mapConstant == NONE_MAP_CONSTANT) {
object->put("target_map", NONE_MAP_NAME);
object->put("event_group_type", EventGroup::Object);
map->events[EventGroup::Object].append(object);
} else {
logError(QString("Destination map constant '%1' is invalid").arg(mapConstant));
}
} else {
logError(QString("Map %1 object_event %2 has invalid type '%3'. Must be 'object' or 'clone'.").arg(map->name).arg(i).arg(type));
}
object->put("x", QString::number(event["x"].toInt()));
object->put("y", QString::number(event["y"].toInt()));
object->put("elevation", QString::number(event["elevation"].toInt()));
object->put("movement_type", event["movement_type"].toString());
object->put("radius_x", QString::number(event["movement_range_x"].toInt()));
object->put("radius_y", QString::number(event["movement_range_y"].toInt()));
object->put("trainer_type", event["trainer_type"].toString());
object->put("sight_radius_tree_id", event["trainer_sight_or_berry_tree_id"].toString());
object->put("script_label", event["script"].toString());
object->put("event_flag", event["flag"].toString());
object->put("event_group_type", "object_event_group");
map->events["object_event_group"].append(object);
}
map->events["warp_event_group"].clear();
map->events[EventGroup::Warp].clear();
QJsonArray warpEventsArr = mapObj["warp_events"].toArray();
for (int i = 0; i < warpEventsArr.size(); i++) {
QJsonObject event = warpEventsArr[i].toObject();
@@ -250,18 +275,18 @@ bool Project::loadMapData(Map* map) {
QString mapConstant = event["dest_map"].toString();
if (mapConstantsToMapNames.contains(mapConstant)) {
warp->put("destination_map_name", mapConstantsToMapNames.value(mapConstant));
warp->put("event_group_type", "warp_event_group");
map->events["warp_event_group"].append(warp);
warp->put("event_group_type", EventGroup::Warp);
map->events[EventGroup::Warp].append(warp);
} else if (mapConstant == NONE_MAP_CONSTANT) {
warp->put("destination_map_name", NONE_MAP_NAME);
warp->put("event_group_type", "warp_event_group");
map->events["warp_event_group"].append(warp);
warp->put("event_group_type", EventGroup::Warp);
map->events[EventGroup::Warp].append(warp);
} else {
logError(QString("Destination map constant '%1' is invalid for warp").arg(mapConstant));
}
}
map->events["heal_event_group"].clear();
map->events[EventGroup::Heal].clear();
for (auto it = healLocations.begin(); it != healLocations.end(); it++) {
HealLocation loc = *it;
@@ -277,18 +302,18 @@ bool Project::loadMapData(Map* map) {
heal->put("index", loc.index);
heal->put("elevation", 3); // TODO: change this?
heal->put("destination_map_name", mapConstantsToMapNames.value(map->name));
heal->put("event_group_type", "heal_event_group");
heal->put("event_group_type", EventGroup::Heal);
heal->put("event_type", EventType::HealLocation);
if (projectConfig.getHealLocationRespawnDataEnabled()) {
heal->put("respawn_map", mapConstantsToMapNames.value(QString("MAP_" + loc.respawnMap)));
heal->put("respawn_npc", loc.respawnNPC);
}
map->events["heal_event_group"].append(heal);
map->events[EventGroup::Heal].append(heal);
}
}
map->events["coord_event_group"].clear();
map->events[EventGroup::Coord].clear();
QJsonArray coordEventsArr = mapObj["coord_events"].toArray();
for (int i = 0; i < coordEventsArr.size(); i++) {
QJsonObject event = coordEventsArr[i].toObject();
@@ -302,8 +327,8 @@ bool Project::loadMapData(Map* map) {
coord->put("script_var", event["var"].toString());
coord->put("script_var_value", event["var_value"].toString());
coord->put("script_label", event["script"].toString());
coord->put("event_group_type", "coord_event_group");
map->events["coord_event_group"].append(coord);
coord->put("event_group_type", EventGroup::Coord);
map->events[EventGroup::Coord].append(coord);
} else if (type == "weather") {
Event *coord = new Event(event, EventType::WeatherTrigger);
coord->put("map_name", map->name);
@@ -311,15 +336,15 @@ bool Project::loadMapData(Map* map) {
coord->put("y", QString::number(event["y"].toInt()));
coord->put("elevation", QString::number(event["elevation"].toInt()));
coord->put("weather", event["weather"].toString());
coord->put("event_group_type", "coord_event_group");
coord->put("event_group_type", EventGroup::Coord);
coord->put("event_type", EventType::WeatherTrigger);
map->events["coord_event_group"].append(coord);
map->events[EventGroup::Coord].append(coord);
} else {
logError(QString("Map %1 coord_event %2 has invalid type '%3'. Must be 'trigger' or 'weather'.").arg(map->name).arg(i).arg(type));
}
}
map->events["bg_event_group"].clear();
map->events[EventGroup::Bg].clear();
QJsonArray bgEventsArr = mapObj["bg_events"].toArray();
for (int i = 0; i < bgEventsArr.size(); i++) {
QJsonObject event = bgEventsArr[i].toObject();
@@ -332,8 +357,8 @@ bool Project::loadMapData(Map* map) {
bg->put("elevation", QString::number(event["elevation"].toInt()));
bg->put("player_facing_direction", event["player_facing_dir"].toString());
bg->put("script_label", event["script"].toString());
bg->put("event_group_type", "bg_event_group");
map->events["bg_event_group"].append(bg);
bg->put("event_group_type", EventGroup::Bg);
map->events[EventGroup::Bg].append(bg);
} else if (type == "hidden_item") {
Event *bg = new Event(event, EventType::HiddenItem);
bg->put("map_name", map->name);
@@ -348,8 +373,8 @@ bool Project::loadMapData(Map* map) {
if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) {
bg->put("underfoot", event["underfoot"].toBool());
}
bg->put("event_group_type", "bg_event_group");
map->events["bg_event_group"].append(bg);
bg->put("event_group_type", EventGroup::Bg);
map->events[EventGroup::Bg].append(bg);
} else if (type == "secret_base") {
Event *bg = new Event(event, EventType::SecretBase);
bg->put("map_name", map->name);
@@ -357,8 +382,8 @@ bool Project::loadMapData(Map* map) {
bg->put("y", QString::number(event["y"].toInt()));
bg->put("elevation", QString::number(event["elevation"].toInt()));
bg->put("secret_base_id", event["secret_base_id"].toString());
bg->put("event_group_type", "bg_event_group");
map->events["bg_event_group"].append(bg);
bg->put("event_group_type", EventGroup::Bg);
map->events[EventGroup::Bg].append(bg);
} else {
logError(QString("Map %1 bg_event %2 has invalid type '%3'. Must be 'sign', 'hidden_item', or 'secret_base'.").arg(map->name).arg(i).arg(type));
}
@@ -861,8 +886,8 @@ void Project::saveHealLocationStruct(Map *map) {
}
// set new location in healLocations list
if (map->events["heal_event_group"].length() > 0) {
for (Event *healEvent : map->events["heal_event_group"]) {
if (map->events[EventGroup::Heal].length() > 0) {
for (Event *healEvent : map->events[EventGroup::Heal]) {
HealLocation hl = HealLocation::fromEvent(healEvent);
healLocations[hl.index - 1] = hl;
}
@@ -1333,17 +1358,23 @@ void Project::saveMap(Map *map) {
if (map->sharedEventsMap.isEmpty()) {
// Object events
OrderedJson::array objectEventsArr;
for (int i = 0; i < map->events["object_event_group"].length(); i++) {
Event *object_event = map->events["object_event_group"].value(i);
OrderedJson::object eventObj = object_event->buildObjectEventJSON();
objectEventsArr.push_back(eventObj);
for (int i = 0; i < map->events[EventGroup::Object].length(); i++) {
Event *event = map->events[EventGroup::Object].value(i);
QString event_type = event->get("event_type");
OrderedJson::object jsonObj;
if (event_type == EventType::Object) {
jsonObj = event->buildObjectEventJSON();
} else if (event_type == EventType::CloneObject) {
jsonObj = event->buildCloneObjectEventJSON(mapNamesToMapConstants);
}
objectEventsArr.push_back(jsonObj);
}
mapObj["object_events"] = objectEventsArr;
// Warp events
OrderedJson::array warpEventsArr;
for (int i = 0; i < map->events["warp_event_group"].length(); i++) {
Event *warp_event = map->events["warp_event_group"].value(i);
for (int i = 0; i < map->events[EventGroup::Warp].length(); i++) {
Event *warp_event = map->events[EventGroup::Warp].value(i);
OrderedJson::object warpObj = warp_event->buildWarpEventJSON(mapNamesToMapConstants);
warpEventsArr.append(warpObj);
}
@@ -1351,8 +1382,8 @@ void Project::saveMap(Map *map) {
// Coord events
OrderedJson::array coordEventsArr;
for (int i = 0; i < map->events["coord_event_group"].length(); i++) {
Event *event = map->events["coord_event_group"].value(i);
for (int i = 0; i < map->events[EventGroup::Coord].length(); i++) {
Event *event = map->events[EventGroup::Coord].value(i);
QString event_type = event->get("event_type");
if (event_type == EventType::Trigger) {
OrderedJson::object triggerObj = event->buildTriggerEventJSON();
@@ -1366,8 +1397,8 @@ void Project::saveMap(Map *map) {
// Bg Events
OrderedJson::array bgEventsArr;
for (int i = 0; i < map->events["bg_event_group"].length(); i++) {
Event *event = map->events["bg_event_group"].value(i);
for (int i = 0; i < map->events[EventGroup::Bg].length(); i++) {
Event *event = map->events[EventGroup::Bg].value(i);
QString event_type = event->get("event_type");
if (event_type == EventType::Sign) {
OrderedJson::object signObj = event->buildSignEventJSON();
@@ -1692,8 +1723,12 @@ bool Project::readWildMonData() {
OrderedJson::object wildMonObj;
if (!parser.tryParseOrderedJsonFile(&wildMonObj, wildMonJsonFilepath)) {
logError(QString("Failed to read wild encounters from %1").arg(wildMonJsonFilepath));
return false;
// Failing to read wild encounters data is not a critical error, just disable the
// encounter editor and log a warning in case the user intended to have this data.
projectConfig.setEncounterJsonActive(false);
emit disableWildEncountersUI();
logWarn(QString("Failed to read wild encounters from %1").arg(wildMonJsonFilepath));
return true;
}
for (OrderedJson subObjectRef : wildMonObj["wild_encounter_groups"].array_items()) {
@@ -2248,9 +2283,8 @@ bool Project::readObjEventGfxConstants() {
QStringList objEventGfxPrefixes("\\bOBJ_EVENT_GFX_");
QString filename = "include/constants/event_objects.h";
fileWatcher.addPath(root + "/" + filename);
QMap<QString, int> gfxDefines = parser.readCDefines(filename, objEventGfxPrefixes);
this->gfxNames = gfxDefines.keys();
if (this->gfxNames.isEmpty()) {
this->gfxDefines = parser.readCDefines(filename, objEventGfxPrefixes);
if (this->gfxDefines.isEmpty()) {
logError(QString("Failed to read object event graphics constants from %1.").arg(filename));
return false;
}
@@ -2380,25 +2414,48 @@ void Project::setEventPixmap(Event * event, bool forceLoad) {
event->spriteHeight = 16;
event->usingSprite = false;
QString event_type = event->get("event_type");
if (event_type == EventType::Object) {
QString gfxName = event->get("sprite");
QString group_type = event->get("event_group_type");
if (group_type == EventGroup::Object) {
QString gfxName;
QString movement;
QString event_type = event->get("event_type");
if (event_type == EventType::CloneObject) {
// Try to get the targeted object to clone
int eventIndex = event->getInt("target_local_id") - 1;
Map * clonedMap = getMap(event->get("target_map"));
Event * clonedEvent = clonedMap ? clonedMap->events[EventGroup::Object].value(eventIndex, nullptr) : nullptr;
if (clonedEvent && clonedEvent->get("event_type") == EventType::Object) {
// Get graphics data from cloned object
gfxName = clonedEvent->get("sprite");
movement = clonedEvent->get("movement_type");
} else {
// Invalid object specified, use default graphics data (as would be shown in-game)
gfxName = gfxDefines.key(0);
movement = movementTypes.first();
}
// Update clone object's sprite text to match target object
event->put("sprite", gfxName);
} else {
// Get graphics data of regular object
gfxName = event->get("sprite");
movement = event->get("movement_type");
}
EventGraphics * eventGfx = eventGraphicsMap.value(gfxName, nullptr);
if (!eventGfx || eventGfx->spritesheet.isNull()) {
// No sprite associated with this gfx constant.
// Use default sprite instead.
event->pixmap = QPixmap(":/images/Entities_16x16.png").copy(0, 0, 16, 16);
} else {
event->setFrameFromMovement(facingDirections.value(event->get("movement_type")));
event->setFrameFromMovement(facingDirections.value(movement));
event->setPixmapFromSpritesheet(eventGfx->spritesheet, eventGfx->spriteWidth, eventGfx->spriteHeight, eventGfx->inanimate);
}
} else if (event_type == EventType::Warp) {
} else if (group_type == EventGroup::Warp) {
event->pixmap = QPixmap(":/images/Entities_16x16.png").copy(16, 0, 16, 16);
} else if (event_type == EventType::Trigger || event_type == EventType::WeatherTrigger) {
} else if (group_type == EventGroup::Coord) {
event->pixmap = QPixmap(":/images/Entities_16x16.png").copy(32, 0, 16, 16);
} else if (event_type == EventType::Sign || event_type == EventType::HiddenItem || event_type == EventType::SecretBase) {
} else if (group_type == EventGroup::Bg) {
event->pixmap = QPixmap(":/images/Entities_16x16.png").copy(48, 0, 16, 16);
} else if (event_type == EventType::HealLocation) {
} else if (group_type == EventGroup::Heal) {
event->pixmap = QPixmap(":/images/Entities_16x16.png").copy(64, 0, 16, 16);
}
}
@@ -2413,7 +2470,8 @@ bool Project::readEventGraphics() {
qDeleteAll(eventGraphicsMap);
eventGraphicsMap.clear();
for (QString gfxName : this->gfxNames) {
QStringList gfxNames = gfxDefines.keys();
for (QString gfxName : gfxNames) {
EventGraphics * eventGraphics = new EventGraphics;
QString info_label = pointerHash[gfxName].replace("&", "");
@@ -2473,8 +2531,8 @@ bool Project::readSpeciesIconPaths() {
void Project::saveMapHealEvents(Map *map) {
// save heal event changes
if (map->events["heal_event_group"].length() > 0) {
for (Event *healEvent : map->events["heal_event_group"]) {
if (map->events[EventGroup::Heal].length() > 0) {
for (Event *healEvent : map->events[EventGroup::Heal]) {
HealLocation hl = HealLocation::fromEvent(healEvent);
healLocations[hl.index - 1] = hl;
}
@@ -2483,11 +2541,11 @@ void Project::saveMapHealEvents(Map *map) {
}
void Project::setNewMapEvents(Map *map) {
map->events["object_event_group"].clear();
map->events["warp_event_group"].clear();
map->events["heal_event_group"].clear();
map->events["coord_event_group"].clear();
map->events["bg_event_group"].clear();
map->events[EventGroup::Object].clear();
map->events[EventGroup::Warp].clear();
map->events[EventGroup::Heal].clear();
map->events[EventGroup::Coord].clear();
map->events[EventGroup::Bg].clear();
}
int Project::getNumTilesPrimary()

View File

@@ -26,15 +26,16 @@ void CityMapPixmapItem::init() {
void CityMapPixmapItem::draw() {
QImage image(width_ * 8, height_ * 8, QImage::Format_RGBA8888);
QPainter painter(&image);
for (int i = 0; i < data.size() / 2; i++) {
QImage img = this->tile_selector->tileImg(data[i * 2]);// need to skip every other tile
int x = i % width_;
int y = i / width_;
QPoint pos = QPoint(x * 8, y * 8);
painter.drawImage(pos, img);
}
painter.end();
// TODO: construct temporary tile from this based on the id?
// QPainter painter(&image);
// for (int i = 0; i < data.size() / 2; i++) {
// QImage img = this->tile_selector->tileImg(data[i * 2]);// need to skip every other tile
// int x = i % width_;
// int y = i / width_;
// QPoint pos = QPoint(x * 8, y * 8);
// painter.drawImage(pos, img);
// }
// painter.end();
this->setPixmap(QPixmap::fromImage(image));
}

View File

@@ -102,17 +102,24 @@ void DraggablePixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *) {
}
void DraggablePixmapItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *) {
if (this->event->get("event_type") == EventType::Warp) {
QString eventType = this->event->get("event_type");
if (eventType == EventType::Warp) {
QString destMap = this->event->get("destination_map_name");
if (destMap != NONE_MAP_NAME) {
emit editor->warpEventDoubleClicked(this->event->get("destination_map_name"), this->event->get("destination_warp"));
emit editor->warpEventDoubleClicked(destMap, this->event->get("destination_warp"), EventGroup::Warp);
}
}
else if (this->event->get("event_type") == EventType::SecretBase) {
else if (eventType == EventType::CloneObject) {
QString destMap = this->event->get("target_map");
if (destMap != NONE_MAP_NAME) {
emit editor->warpEventDoubleClicked(destMap, this->event->get("target_local_id"), EventGroup::Object);
}
}
else if (eventType == EventType::SecretBase) {
QString baseId = this->event->get("secret_base_id");
QString destMap = editor->project->mapConstantsToMapNames.value("MAP_" + baseId.left(baseId.lastIndexOf("_")));
if (destMap != NONE_MAP_NAME) {
emit editor->warpEventDoubleClicked(destMap, "0");
emit editor->warpEventDoubleClicked(destMap, "0", EventGroup::Warp);
}
}
}

View File

@@ -371,11 +371,11 @@ QPixmap MapImageExporter::getFormattedMapPixmap(Map *map, bool ignoreBorder) {
for (Event *event : events) {
editor->project->setEventPixmap(event);
QString group = event->get("event_group_type");
if ((showObjects && group == "object_event_group")
|| (showWarps && group == "warp_event_group")
|| (showBGs && group == "bg_event_group")
|| (showTriggers && group == "coord_event_group")
|| (showHealSpots && group == "heal_event_group"))
if ((showObjects && group == EventGroup::Object)
|| (showWarps && group == EventGroup::Warp)
|| (showBGs && group == EventGroup::Bg)
|| (showTriggers && group == EventGroup::Coord)
|| (showHealSpots && group == EventGroup::Heal))
eventPainter.drawImage(QPoint(event->getPixelX(), event->getPixelY()), event->pixmap.toImage());
}
eventPainter.end();

View File

@@ -18,6 +18,10 @@ void NewEventToolButton::init()
this->newObjectAction->setIcon(QIcon(":/icons/add.ico"));
connect(this->newObjectAction, &QAction::triggered, this, &NewEventToolButton::newObject);
this->newCloneObjectAction = new QAction("New Clone Object", this);
this->newCloneObjectAction->setIcon(QIcon(":/icons/add.ico"));
connect(this->newCloneObjectAction, &QAction::triggered, this, &NewEventToolButton::newCloneObject);
this->newWarpAction = new QAction("New Warp", this);
this->newWarpAction->setIcon(QIcon(":/icons/add.ico"));
connect(this->newWarpAction, &QAction::triggered, this, &NewEventToolButton::newWarp);
@@ -50,6 +54,7 @@ void NewEventToolButton::init()
QMenu *alignMenu = new QMenu();
alignMenu->addAction(this->newObjectAction);
alignMenu->addAction(this->newCloneObjectAction);
alignMenu->addAction(this->newWarpAction);
//alignMenu->addAction(this->newHealLocationAction);
alignMenu->addAction(this->newTriggerAction);
@@ -72,6 +77,12 @@ void NewEventToolButton::newObject()
emit newEventAdded(this->selectedEventType);
}
void NewEventToolButton::newCloneObject()
{
this->selectedEventType = EventType::CloneObject;
emit newEventAdded(this->selectedEventType);
}
void NewEventToolButton::newWarp()
{
this->selectedEventType = EventType::Warp;

View File

@@ -156,6 +156,8 @@ void NewMapPopup::setDefaultValuesImportMap(MapLayout *mapLayout) {
ui->comboBox_NewMap_Group->addItems(project->groupNames);
ui->comboBox_NewMap_Group->setCurrentText(project->groupNames.at(0));
ui->comboBox_Song->addItems(project->songNames);
ui->spinBox_NewMap_Width->setValue(mapLayout->width.toInt(nullptr, 0));
ui->spinBox_NewMap_Height->setValue(mapLayout->height.toInt(nullptr, 0));
ui->comboBox_NewMap_Primary_Tileset->setCurrentText(mapLayout->tileset_primary_label);

File diff suppressed because it is too large Load Diff

View File

@@ -3,12 +3,12 @@
void RegionMapEntriesPixmapItem::draw() {
if (!region_map) return;
RegionMapEntry entry = region_map->mapSecToMapEntry.value(currentSection);
MapSectionEntry entry = this->region_map->getEntry(currentSection);
bool selectingEntry = false;
int entry_x, entry_y, entry_w, entry_h;
if (entry.name.isEmpty() || entry.name == "MAPSEC_NONE") {
if (!entry.valid || entry.name == "MAPSEC_NONE") {
entry_x = entry_y = 0;
entry_w = entry_h = 1;
} else {
@@ -17,25 +17,25 @@ void RegionMapEntriesPixmapItem::draw() {
entry_w = entry.width, entry_h = entry.height;
}
QImage image(region_map->width() * 8, region_map->height() * 8, QImage::Format_RGBA8888);
QImage image(region_map->tilemapWidth() * 8, region_map->tilemapHeight() * 8, QImage::Format_RGBA8888);
QPainter painter(&image);
for (int i = 0; i < region_map->map_squares.size(); i++) {
QImage bottom_img = this->tile_selector->tileImg(region_map->map_squares[i].tile_img_id);
for (int i = 0; i < region_map->tilemapSize(); i++) {
QImage bottom_img = this->tile_selector->tileImg(region_map->getTile(i));
QImage top_img(8, 8, QImage::Format_RGBA8888);
int x = i % region_map->width();
int y = i / region_map->width();
int x = i % region_map->tilemapWidth();
int y = i / region_map->tilemapWidth();
bool insideEntry = false;
if (selectingEntry) {
if (x == entry_x + this->region_map->padLeft && y == entry_y + this->region_map->padTop)
if (x == entry_x + this->region_map->padLeft() && y == entry_y + this->region_map->padTop())
insideEntry = true;
else if (x - this->region_map->padLeft - entry_x < entry_w && x >= entry_x + this->region_map->padLeft
&& y - this->region_map->padTop - entry_y < entry_h && y >= entry_y + this->region_map->padTop)
else if (x - this->region_map->padLeft() - entry_x < entry_w && x >= entry_x + this->region_map->padLeft()
&& y - this->region_map->padTop() - entry_y < entry_h && y >= entry_y + this->region_map->padTop())
insideEntry = true;
}
if (insideEntry) {
top_img.fill(QColor(255, 68, 68));
} else if (region_map->map_squares[i].has_map) {
} else if (region_map->squareHasMap(i)) {
top_img.fill(Qt::gray);
} else {
top_img.fill(Qt::black);
@@ -44,7 +44,7 @@ void RegionMapEntriesPixmapItem::draw() {
painter.setOpacity(1);
painter.drawImage(pos, bottom_img);
painter.save();
painter.setOpacity(0.55);
painter.setOpacity(0.65);
painter.drawImage(pos, top_img);
painter.restore();
}
@@ -54,7 +54,8 @@ void RegionMapEntriesPixmapItem::draw() {
this->selectionOffsetY = entry_h - 1;
this->setPixmap(QPixmap::fromImage(image));
this->drawSelection();
if (selectingEntry) this->drawSelection();
}
void RegionMapEntriesPixmapItem::select(int x, int y) {
@@ -63,25 +64,25 @@ void RegionMapEntriesPixmapItem::select(int x, int y) {
this->selectedTile = index;
this->updateSelectedTile();
emit selectedTileChanged(this->region_map->map_squares[index].mapsec);
emit selectedTileChanged(this->region_map->squareMapSection(index));
}
void RegionMapEntriesPixmapItem::select(int index) {
int x = index % this->region_map->width();
int y = index / this->region_map->width();
int x = index % this->region_map->tilemapWidth();
int y = index / this->region_map->tilemapWidth();
SelectablePixmapItem::select(x, y, 0, 0);
this->selectedTile = index;
this->updateSelectedTile();
emit selectedTileChanged(this->region_map->map_squares[index].mapsec);
emit selectedTileChanged(this->region_map->squareMapSection(index));
}
void RegionMapEntriesPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
QPoint pos = this->getCellPos(event->pos());
int x = pos.x() - this->region_map->padLeft;
int y = pos.y() - this->region_map->padTop;
int x = pos.x() - this->region_map->padLeft();
int y = pos.y() - this->region_map->padTop();
RegionMapEntry entry = this->region_map->mapSecToMapEntry.value(currentSection);
MapSectionEntry entry = this->region_map->getEntry(currentSection);
pressedX = x - entry.x;
pressedY = y - entry.y;
if (entry.x == x && entry.y == y) {
@@ -92,6 +93,7 @@ void RegionMapEntriesPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event
}
}
// TODO: update this function, especially bounds check
void RegionMapEntriesPixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
if (!draggingEntry) {
event->ignore();
@@ -99,14 +101,14 @@ void RegionMapEntriesPixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
}
QPoint pos = this->getCellPos(event->pos());
int new_x = pos.x() - this->region_map->padLeft - pressedX;
int new_y = pos.y() - this->region_map->padTop - pressedY;
int new_x = pos.x() - this->region_map->padLeft() - pressedX;
int new_y = pos.y() - this->region_map->padTop() - pressedY;
RegionMapEntry entry = this->region_map->mapSecToMapEntry.value(currentSection);
MapSectionEntry entry = this->region_map->getEntry(currentSection);
// check to make sure not moving out of bounds
if (new_x + entry.width > this->region_map->width() - this->region_map->padLeft - this->region_map->padRight
|| new_y + entry.height > this->region_map->height() - this->region_map->padTop - this->region_map->padBottom
if (new_x + entry.width > this->region_map->tilemapWidth() - this->region_map->padLeft() //- this->region_map->padRight
|| new_y + entry.height > this->region_map->tilemapHeight() - this->region_map->padTop() //- this->region_map->padBottom
|| new_x < 0 || new_y < 0)
return;

View File

@@ -3,24 +3,29 @@
void RegionMapLayoutPixmapItem::draw() {
if (!region_map) return;
QImage image(region_map->width() * 8, region_map->height() * 8, QImage::Format_RGBA8888);
QImage image(region_map->pixelWidth(), region_map->pixelHeight(), QImage::Format_RGBA8888);
QPainter painter(&image);
for (int i = 0; i < region_map->map_squares.size(); i++) {
QImage bottom_img = this->tile_selector->tileImg(region_map->map_squares[i].tile_img_id);
for (int i = 0; i < region_map->tilemapSize(); i++) {
QImage bottom_img = this->tile_selector->tileImg(region_map->getTile(i));
QImage top_img(8, 8, QImage::Format_RGBA8888);
if (region_map->map_squares[i].has_map) {
if (region_map->squareHasMap(i)) {
top_img.fill(Qt::gray);
} else {
top_img.fill(Qt::black);
}
int x = i % region_map->width();
int y = i / region_map->width();
int x = i % region_map->tilemapWidth();
int y = i / region_map->tilemapWidth();
QPoint pos = QPoint(x * 8, y * 8);
painter.setOpacity(1);
painter.drawImage(pos, bottom_img);
painter.save();
painter.setOpacity(0.55);
if (region_map->squareInLayout(x, y)) {
painter.setOpacity(0.55);
} else {
painter.setOpacity(0.8);
}
painter.drawImage(pos, top_img);
painter.restore();
}
@@ -40,8 +45,8 @@ void RegionMapLayoutPixmapItem::select(int x, int y) {
}
void RegionMapLayoutPixmapItem::select(int index) {
int x = index % this->region_map->width();
int y = index / this->region_map->width();
int x = index % this->region_map->tilemapWidth();
int y = index / this->region_map->tilemapWidth();
SelectablePixmapItem::select(x, y, 0, 0);
this->selectedTile = index;
this->updateSelectedTile();
@@ -51,15 +56,13 @@ void RegionMapLayoutPixmapItem::select(int index) {
void RegionMapLayoutPixmapItem::highlight(int x, int y, int red) {
this->highlightedTile = red;
SelectablePixmapItem::select(x + this->region_map->padLeft, y + this->region_map->padTop, 0, 0);
SelectablePixmapItem::select(x + this->region_map->padLeft(), y + this->region_map->padTop(), 0, 0);
draw();
}
void RegionMapLayoutPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
QPoint pos = this->getCellPos(event->pos());
int index = this->region_map->getMapSquareIndex(pos.x(), pos.y());
if (this->region_map->map_squares[index].x >= 0
&& this->region_map->map_squares[index].y >= 0) {
if (this->region_map->squareInLayout(pos.x(), pos.y())) {
SelectablePixmapItem::mousePressEvent(event);
this->updateSelectedTile();
emit selectedTileChanged(this->selectedTile);

View File

@@ -1,15 +1,16 @@
#include "regionmappixmapitem.h"
#include "regionmapeditcommands.h"
void RegionMapPixmapItem::draw() {
if (!region_map) return;
QImage image(region_map->width() * 8, region_map->height() * 8, QImage::Format_RGBA8888);
QImage image(region_map->pixelWidth(), region_map->pixelHeight(), QImage::Format_RGBA8888);
QPainter painter(&image);
for (int i = 0; i < region_map->map_squares.size(); i++) {
QImage img = this->tile_selector->tileImg(region_map->map_squares[i].tile_img_id);
int x = i % region_map->width();
int y = i / region_map->width();
for (int i = 0; i < region_map->tilemapSize(); i++) {
QImage img = this->tile_selector->tileImg(region_map->getTile(i));
int x = i % region_map->tilemapWidth();
int y = i / region_map->tilemapWidth();
QPoint pos = QPoint(x * 8, y * 8);
painter.drawImage(pos, img);
}
@@ -23,8 +24,77 @@ void RegionMapPixmapItem::paint(QGraphicsSceneMouseEvent *event) {
QPointF pos = event->pos();
int x = static_cast<int>(pos.x()) / 8;
int y = static_cast<int>(pos.y()) / 8;
int index = x + y * region_map->width();
this->region_map->map_squares[index].tile_img_id = this->tile_selector->selectedTile;
int index = x + y * region_map->tilemapWidth();
this->region_map->setTileData(index,
this->tile_selector->selectedTile,
this->tile_selector->tile_hFlip,
this->tile_selector->tile_vFlip,
this->tile_selector->tile_palette
);
draw();
}
}
void RegionMapPixmapItem::floodFill(int x, int y, std::shared_ptr<TilemapTile> oldTile, std::shared_ptr<TilemapTile> newTile) {
// out of bounds
if (x < 0
|| y < 0
|| x >= this->region_map->tilemapWidth()
|| y >= this->region_map->tilemapHeight()) {
return;
}
auto tile = this->region_map->getTile(x, y);
if (!tile->operator==(*oldTile) || tile->operator==(*newTile)) {
return;
}
int index = x + y * this->region_map->tilemapWidth();
this->region_map->setTileData(index,
newTile->id(),
newTile->hFlip(),
newTile->vFlip(),
newTile->palette()
);
floodFill(x + 1, y, oldTile, newTile);
floodFill(x - 1, y, oldTile, newTile);
floodFill(x, y + 1, oldTile, newTile);
floodFill(x, y - 1, oldTile, newTile);
}
void RegionMapPixmapItem::fill(QGraphicsSceneMouseEvent *event) {
if (region_map) {
QPointF pos = event->pos();
int x = static_cast<int>(pos.x()) / 8;
int y = static_cast<int>(pos.y()) / 8;
int index = x + y * this->region_map->tilemapWidth();
std::shared_ptr<TilemapTile> currentTile, newTile, oldTile;
currentTile = this->region_map->getTile(index);
switch(this->tile_selector->format) {
case TilemapFormat::Plain:
oldTile = std::make_shared<PlainTile>(currentTile->raw());
newTile = std::make_shared<PlainTile>(currentTile->raw());
newTile->setId(this->tile_selector->selectedTile);
break;
case TilemapFormat::BPP_4:
oldTile = std::make_shared<BPP4Tile>(currentTile->raw());
newTile = std::make_shared<BPP4Tile>(currentTile->raw());
newTile->setId(this->tile_selector->selectedTile);
newTile->setHFlip(this->tile_selector->tile_hFlip);
newTile->setVFlip(this->tile_selector->tile_vFlip);
newTile->setPalette(this->tile_selector->tile_palette);
break;
case TilemapFormat::BPP_8:
oldTile = std::make_shared<BPP8Tile>(currentTile->raw());
newTile = std::make_shared<BPP8Tile>(currentTile->raw());
newTile->setId(this->tile_selector->selectedTile);
newTile->setId(this->tile_selector->selectedTile);
newTile->setHFlip(this->tile_selector->tile_hFlip);
newTile->setVFlip(this->tile_selector->tile_vFlip);
break;
}
floodFill(x, y, oldTile, newTile);
draw();
}
}
@@ -54,8 +124,8 @@ void RegionMapPixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
QPointF pos = event->pos();
int x = static_cast<int>(pos.x()) / 8;
int y = static_cast<int>(pos.y()) / 8;
if (x < this->region_map->width() && x >= 0
&& y < this->region_map->height() && y >= 0) {
if (x < this->region_map->tilemapWidth() && x >= 0
&& y < this->region_map->tilemapHeight() && y >= 0) {
emit this->hoveredRegionMapTileChanged(x, y);
emit mouseEvent(event, this);
}

View File

@@ -0,0 +1,257 @@
#include "project.h"
#include "regionmappropertiesdialog.h"
#include "ui_regionmappropertiesdialog.h"
RegionMapPropertiesDialog::RegionMapPropertiesDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::RegionMapPropertiesDialog)
{
ui->setupUi(this);
this->hideMessages();
}
RegionMapPropertiesDialog::~RegionMapPropertiesDialog()
{
delete ui;
}
void RegionMapPropertiesDialog::hideMessages() {
ui->message_alias->setVisible(false);
ui->message_tilemapFormat->setVisible(false);
ui->message_tilemapWidth->setVisible(false);
ui->message_tilemapHeight->setVisible(false);
ui->message_tilemapImagePath->setVisible(false);
ui->message_tilemapBinPath->setVisible(false);
ui->message_layoutFormat->setVisible(false);
ui->message_layoutPath->setVisible(false);
ui->message_layoutWidth->setVisible(false);
ui->message_layoutHeight->setVisible(false);
this->adjustSize();
}
QString RegionMapPropertiesDialog::browse(QString filter, QFileDialog::FileMode mode) {
if (!this->project) return QString();
QFileDialog browser;
browser.setFileMode(mode);
QString filepath = browser.getOpenFileName(this, "Select a File", this->project->root, filter);
// remove the project root from the filepath
return filepath.replace(this->project->root + "/", "");
}
// TODO: test for missing fields/invalid cases
void RegionMapPropertiesDialog::setProperties(poryjson::Json json) {
poryjson::Json::object object = json.object_items();
// Region Map Properties
ui->config_alias->setText(object["alias"].string_value());
// Tilemap properties
poryjson::Json::object tilemap = object["tilemap"].object_items();
ui->config_tilemapFormat->setCurrentText(tilemap["format"].string_value());
ui->config_tilemapWidth->setValue(tilemap["width"].int_value());
ui->config_tilemapHeight->setValue(tilemap["height"].int_value());
ui->config_tilemapImagePath->setText(tilemap["tileset_path"].string_value());
ui->config_tilemapBinPath->setText(tilemap["tilemap_path"].string_value());
if (tilemap.contains("palette"))
ui->config_tilemapPalettePath->setText(tilemap["palette"].string_value());
// Layout props
if (object["layout"].is_null()) {
ui->group_layout->setChecked(false);
} else {
poryjson::Json::object layout = object["layout"].object_items();
ui->config_layoutFormat->setCurrentText(layout["format"].string_value());
ui->config_layoutPath->setText(layout["path"].string_value());
ui->config_layoutWidth->setValue(layout["width"].int_value());
ui->config_layoutHeight->setValue(layout["height"].int_value());
ui->config_leftOffs->setValue(layout["offset_left"].int_value());
ui->config_topOffs->setValue(layout["offset_top"].int_value());
}
}
poryjson::Json RegionMapPropertiesDialog::saveToJson() {
poryjson::Json::object config;
// TODO: make sure next comment is not a lie
// data should already be verified and valid at this point
config["alias"] = ui->config_alias->text();
poryjson::Json::object tilemapObject;
tilemapObject["width"] = ui->config_tilemapWidth->value();
tilemapObject["height"] = ui->config_tilemapHeight->value();
tilemapObject["format"] = ui->config_tilemapFormat->currentText();
tilemapObject["tileset_path"] = ui->config_tilemapImagePath->text();
tilemapObject["tilemap_path"] = ui->config_tilemapBinPath->text();
tilemapObject["palette"] = ui->config_tilemapPalettePath->text();
config["tilemap"] = tilemapObject;
if (ui->group_layout->isChecked()) {
poryjson::Json::object layoutObject;
layoutObject["format"] = ui->config_layoutFormat->currentText();
layoutObject["path"] = ui->config_layoutPath->text();
layoutObject["width"] = ui->config_layoutWidth->value();
layoutObject["height"] = ui->config_layoutHeight->value();
layoutObject["offset_left"] = ui->config_leftOffs->value();
layoutObject["offset_top"] = ui->config_topOffs->value();
config["layout"] = layoutObject;
} else {
config["layout"] = nullptr;
}
return poryjson::Json(config);
}
void RegionMapPropertiesDialog::on_browse_tilesetImagePath_clicked() {
QString path = browse("Images (*.png *.bmp)", QFileDialog::ExistingFile);
if (!path.isEmpty()) {
ui->config_tilemapImagePath->setText(path);
}
}
void RegionMapPropertiesDialog::on_browse_tilemapBinPath_clicked() {
QString path = browse("Binary (*.bin *.tilemap *.4bpp *.8bpp)", QFileDialog::AnyFile);
if (!path.isEmpty()) {
ui->config_tilemapBinPath->setText(path);
}
}
void RegionMapPropertiesDialog::on_browse_tilemapPalettePath_clicked() {
QString path = browse("Text (*.pal)", QFileDialog::AnyFile);
if (!path.isEmpty()) {
ui->config_tilemapPalettePath->setText(path);
}
}
void RegionMapPropertiesDialog::on_browse_layoutPath_clicked() {
if (ui->config_layoutFormat->currentIndex() == 0) {
QString path = browse("Text File (*.h *.c *.inc *.txt)", QFileDialog::AnyFile);
if (!path.isEmpty()) {
ui->config_layoutPath->setText(path);
}
} else {
QString path = browse("Binary (*.bin)", QFileDialog::AnyFile);
if (!path.isEmpty()) {
ui->config_layoutPath->setText(path);
}
}
}
void RegionMapPropertiesDialog::accept() {
bool valid = true;
// verify alias is okay
QString alias = ui->config_alias->text();
if (alias.isEmpty()) {
valid = false;
ui->message_alias->setText("alias cannot be empty");
ui->message_alias->setVisible(true);
} else {
QRegularExpression re("[A-Za-z0-9_\\- ]+");
int temp = 0;
QRegularExpressionValidator v(re, 0);
if (v.validate(alias, temp) != QValidator::Acceptable) {
ui->message_alias->setText("this alias is not an acceptable string");
ui->message_alias->setVisible(true);
valid = false;
}
else { // no issues detected
ui->message_alias->setText("");
ui->message_alias->setVisible(false);
}
}
// tilemap properties
// tilemap dimensions are specific: 64x32, 32x64, 16x16, 32x32, 64x64, 128x128
// TODO: why is 30x20 allowed in firered?
int tilemapWidth = ui->config_tilemapWidth->value();
int tilemapHeight = ui->config_tilemapHeight->value();
QMap<int, QList<int>> acceptableDimensions = { {16, {16}}, {30, {20}}, {32, {32, 64}}, {64, {32, 64}}, {128, {128}} };
if (!acceptableDimensions.contains(tilemapWidth)) {
// width not valid
valid = false;
ui->message_tilemapWidth->setText("tilemap width not valid, must be one of [16, 32, 64, 128]");
ui->message_tilemapWidth->setVisible(true);
} else {
ui->message_tilemapWidth->setText("");
ui->message_tilemapWidth->setVisible(false);
// check width, height combo
if (!acceptableDimensions.value(tilemapWidth).contains(tilemapHeight)) {
valid = false;
QString options = "";
for (int i : acceptableDimensions.value(tilemapWidth))
options += QString::number(i) + ", ";
options.chop(2);
ui->message_tilemapHeight->setText("tilemap height not valid, must be one of [" + options + "]");
ui->message_tilemapHeight->setVisible(true);
}
else { // no issues detected
ui->message_tilemapHeight->setText("");
ui->message_tilemapHeight->setVisible(false);
}
}
// layout dimensions
// need to verify <= tilemap dimensions, only req here
int width = ui->config_layoutWidth->value() + ui->config_leftOffs->value();
int height = ui->config_layoutHeight->value() + ui->config_topOffs->value();
if (width > tilemapWidth) {
valid = false;
ui->message_layoutWidth->setText("layout map width + left offset cannot be larger than tilemap width");
ui->message_layoutWidth->setVisible(true);
} else {
ui->message_layoutWidth->setText("");
ui->message_layoutWidth->setVisible(false);
}
if (height > tilemapHeight) {
valid = false;
ui->message_layoutHeight->setText("layout map height + top offset cannot be larger than tilemap height");
ui->message_layoutHeight->setVisible(true);
} else {
ui->message_layoutHeight->setText("");
ui->message_layoutHeight->setVisible(false);
}
// make sure paths arent empty
if (ui->config_tilemapImagePath->text().isEmpty()) {
valid = false;
ui->message_tilemapImagePath->setText("this path cannot be empty");
ui->message_tilemapImagePath->setVisible(true);
} else {
ui->message_tilemapImagePath->setText("");
ui->message_tilemapImagePath->setVisible(false);
}
if (ui->config_tilemapBinPath->text().isEmpty()) {
valid = false;
ui->message_tilemapBinPath->setText("this path cannot be empty");
ui->message_tilemapBinPath->setVisible(true);
} else {
ui->message_tilemapBinPath->setText("");
ui->message_tilemapBinPath->setVisible(false);
}
// layout path only needs to exist if layout is enabled (obviously)
if (ui->group_layout->isChecked()) {
if (ui->config_layoutPath->text().isEmpty()) {
valid = false;
ui->message_layoutPath->setText("this path cannot be empty");
ui->message_layoutPath->setVisible(true);
} else {
ui->message_layoutPath->setText("");
ui->message_layoutPath->setVisible(false);
}
} else {
ui->message_layoutPath->setText("");
ui->message_layoutPath->setVisible(false);
}
// TODO: limitations for map width/height if implementing
if (valid) {
QDialog::accept();
}
}

View File

@@ -3,16 +3,16 @@
#include <QDebug>
void TilemapTileSelector::draw() {
size_t width_ = this->tilemap.width();
size_t width_ = this->tileset.width();
this->pixelWidth = width_;
size_t height_ = this->tilemap.height();
size_t height_ = this->tileset.height();
this->pixelHeight = height_;
size_t ntiles_ = (width_/8) * (height_/8);
this->numTilesWide = width_ / 8;
this->numTiles = ntiles_;
this->setPixmap(tilemap);
this->setPixmap(QPixmap::fromImage(this->setPalette(this->tile_palette)));
this->drawSelection();
}
@@ -20,6 +20,7 @@ void TilemapTileSelector::select(unsigned tileId) {
QPoint coords = this->getTileIdCoords(tileId);
SelectablePixmapItem::select(coords.x(), coords.y(), 0, 0);
this->selectedTile = tileId;
this->drawSelection();
emit selectedTileChanged(tileId);
}
@@ -28,10 +29,6 @@ void TilemapTileSelector::updateSelectedTile() {
this->selectedTile = this->getTileId(origin.x(), origin.y());
}
unsigned TilemapTileSelector::getSelectedTile() {
return this->selectedTile;
}
unsigned TilemapTileSelector::getTileId(int x, int y) {
unsigned index = y * this->numTilesWide + x;
return index < this->numTiles ? index : this->numTiles % index;
@@ -42,9 +39,63 @@ QPoint TilemapTileSelector::getTileIdCoords(unsigned tileId) {
return QPoint(index % this->numTilesWide, index / this->numTilesWide);
}
QImage TilemapTileSelector::tileImg(unsigned tileId) {
QImage TilemapTileSelector::setPalette(int paletteIndex) {
QImage tilesetImage = this->tileset;
tilesetImage.convertTo(QImage::Format::Format_Indexed8);
// TODO: bounds check on the palette copying
switch(this->format) {
case TilemapFormat::Plain:
break;
case TilemapFormat::BPP_4:
{
QVector<QRgb> newColorTable;
int palMinLength = paletteIndex * 16 + 16;
if ((this->palette.count() < palMinLength) || (tilesetImage.colorTable().count() != 16)) {
// either a) the palette has less than 256 colors, or b) the image is improperly indexed
for (QRgb color : tilesetImage.colorTable()) {
int gray = qGray(color);
newColorTable.append(qRgb(gray, gray, gray));
}
} else {
// use actual pal
// before Qt 6, the color table is a QVector which is deprecated now, and this method does not exits
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
newColorTable = this->palette.toVector().mid(paletteIndex * 16, 16);
#else
newColorTable = this->palette.mid(paletteIndex * 16, 16);
#endif
}
tilesetImage.setColorTable(newColorTable);
break;
}
case TilemapFormat::BPP_8:
{
if (tilesetImage.colorTable().count() == this->palette.count()) {
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
tilesetImage.setColorTable(this->palette.toVector());
#else
tilesetImage.setColorTable(this->palette);
#endif
}
break;
}
default: break;
}
return tilesetImage;
}
QImage TilemapTileSelector::tileImg(shared_ptr<TilemapTile> tile) {
unsigned tileId = tile->id();
QPoint pos = getTileIdCoords(tileId);
return this->tilemap.copy(pos.x() * 8, pos.y() * 8, 8, 8).toImage();
QImage tilesetImage = setPalette(tile->palette());
// take a tile from the tileset
QImage img = tilesetImage.copy(pos.x() * 8, pos.y() * 8, 8, 8);
img = img.mirrored(tile->hFlip(), tile->vFlip());
return img;
}
void TilemapTileSelector::mousePressEvent(QGraphicsSceneMouseEvent *event) {

View File

@@ -40,6 +40,7 @@ TilesetEditor::~TilesetEditor()
delete selectedTilePixmapItem;
delete selectedTileScene;
delete metatileLayersScene;
delete copiedMetatile;
}
void TilesetEditor::update(Map *map, QString primaryTilesetLabel, QString secondaryTilesetLabel) {
@@ -76,8 +77,8 @@ bool TilesetEditor::selectMetatile(uint16_t metatileId) {
return true;
}
uint16_t TilesetEditor::getSelectedMetatile() {
return this->metatileSelector->getSelectedMetatile();
uint16_t TilesetEditor::getSelectedMetatileId() {
return this->metatileSelector->getSelectedMetatileId();
}
void TilesetEditor::setTilesets(QString primaryTilesetLabel, QString secondaryTilesetLabel) {
@@ -177,7 +178,7 @@ void TilesetEditor::initMetatileSelector()
}
void TilesetEditor::initMetatileLayersItem() {
Metatile *metatile = Tileset::getMetatile(this->getSelectedMetatile(), this->primaryTileset, this->secondaryTileset);
Metatile *metatile = Tileset::getMetatile(this->getSelectedMetatileId(), this->primaryTileset, this->secondaryTileset);
this->metatileLayersItem = new MetatileLayersItem(metatile, this->primaryTileset, this->secondaryTileset);
connect(this->metatileLayersItem, &MetatileLayersItem::tileChanged,
this, &TilesetEditor::onMetatileLayerTileChanged);
@@ -282,7 +283,7 @@ void TilesetEditor::refresh() {
this->metatileLayersItem->setTilesets(this->primaryTileset, this->secondaryTileset);
this->tileSelector->setTilesets(this->primaryTileset, this->secondaryTileset);
this->metatileSelector->setTilesets(this->primaryTileset, this->secondaryTileset);
this->metatileSelector->select(this->getSelectedMetatile());
this->metatileSelector->select(this->getSelectedMetatileId());
this->drawSelectedTiles();
if (metatileSelector) {
@@ -419,7 +420,7 @@ void TilesetEditor::onMetatileLayerTileChanged(int x, int y) {
this->metatileLayersItem->draw();
this->hasUnsavedChanges = true;
MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatile(),
MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatileId(),
prevMetatile, new Metatile(*this->metatile));
metatileHistory.push(commit);
}
@@ -486,7 +487,7 @@ void TilesetEditor::on_comboBox_metatileBehaviors_textActivated(const QString &m
if (this->metatile) {
Metatile *prevMetatile = new Metatile(*this->metatile);
this->metatile->behavior = static_cast<uint16_t>(project->metatileBehaviorMap[metatileBehavior]);
MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatile(),
MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatileId(),
prevMetatile, new Metatile(*this->metatile));
metatileHistory.push(commit);
this->hasUnsavedChanges = true;
@@ -510,7 +511,7 @@ void TilesetEditor::saveMetatileLabel()
if (this->metatile && this->metatile->label != this->ui->lineEdit_metatileLabel->text()) {
Metatile *prevMetatile = new Metatile(*this->metatile);
this->metatile->label = this->ui->lineEdit_metatileLabel->text();
MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatile(),
MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatileId(),
prevMetatile, new Metatile(*this->metatile));
metatileHistory.push(commit);
this->hasUnsavedChanges = true;
@@ -522,7 +523,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);
MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatile(),
MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatileId(),
prevMetatile, new Metatile(*this->metatile));
metatileHistory.push(commit);
this->hasUnsavedChanges = true;
@@ -534,7 +535,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);
MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatile(),
MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatileId(),
prevMetatile, new Metatile(*this->metatile));
metatileHistory.push(commit);
this->hasUnsavedChanges = true;
@@ -546,7 +547,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);
MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatile(),
MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatileId(),
prevMetatile, new Metatile(*this->metatile));
metatileHistory.push(commit);
this->hasUnsavedChanges = true;
@@ -811,6 +812,21 @@ void TilesetEditor::onPaletteEditorChangedPalette(int paletteId) {
this->on_spinBox_paletteSelector_valueChanged(paletteId);
}
bool TilesetEditor::replaceMetatile(uint16_t metatileId, Metatile * src)
{
Metatile * dest = Tileset::getMetatile(metatileId, this->primaryTileset, this->secondaryTileset);
if (!dest || !src || *dest == *src)
return false;
this->metatile = dest;
*this->metatile = *src;
this->metatileSelector->select(metatileId);
this->metatileSelector->draw();
this->metatileLayersItem->draw();
this->metatileLayersItem->clearLastModifiedCoords();
return true;
}
void TilesetEditor::on_actionUndo_triggered()
{
MetatileHistoryItem *commit = this->metatileHistory.current();
@@ -818,34 +834,39 @@ void TilesetEditor::on_actionUndo_triggered()
Metatile *prev = commit->prevMetatile;
if (!prev) return;
this->metatileHistory.back();
Metatile *temp = Tileset::getMetatile(commit->metatileId, this->primaryTileset, this->secondaryTileset);
if (temp) {
this->metatile = temp;
*this->metatile = *prev;
this->metatileSelector->select(commit->metatileId);
this->metatileSelector->draw();
this->metatileLayersItem->draw();
this->metatileLayersItem->clearLastModifiedCoords();
}
this->replaceMetatile(commit->metatileId, prev);
}
void TilesetEditor::on_actionRedo_triggered()
{
MetatileHistoryItem *commit = this->metatileHistory.next();
if (!commit) return;
Metatile *next = commit->newMetatile;
if (!next) return;
this->replaceMetatile(commit->metatileId, commit->newMetatile);
}
Metatile *temp = Tileset::getMetatile(commit->metatileId, this->primaryTileset, this->secondaryTileset);
if (temp) {
this->metatile = temp;
*this->metatile = *next;
this->metatileSelector->select(commit->metatileId);
this->metatileSelector->draw();
this->metatileLayersItem->draw();
this->metatileLayersItem->clearLastModifiedCoords();
void TilesetEditor::on_actionCopy_triggered()
{
Metatile * toCopy = Tileset::getMetatile(this->getSelectedMetatileId(), this->primaryTileset, this->secondaryTileset);
if (!toCopy) return;
if (!this->copiedMetatile)
this->copiedMetatile = new Metatile(*toCopy);
else
*this->copiedMetatile = *toCopy;
this->copiedMetatile->label = ""; // Don't copy the label, these should be unique to each metatile
}
void TilesetEditor::on_actionPaste_triggered()
{
Metatile *prevMetatile = new Metatile(*this->metatile);
uint16_t metatileId = this->getSelectedMetatileId();
if (!this->replaceMetatile(metatileId, this->copiedMetatile)) {
delete prevMetatile;
return;
}
MetatileHistoryItem *commit = new MetatileHistoryItem(metatileId, prevMetatile, new Metatile(*this->metatile));
metatileHistory.push(commit);
}
void TilesetEditor::on_actionExport_Primary_Tiles_Image_triggered()

View File

@@ -78,7 +78,7 @@ void TilesetEditorMetatileSelector::updateSelectedMetatile() {
emit selectedMetatileChanged(this->selectedMetatile);
}
uint16_t TilesetEditorMetatileSelector::getSelectedMetatile() {
uint16_t TilesetEditorMetatileSelector::getSelectedMetatileId() {
return this->selectedMetatile;
}