Add clone objects

This commit is contained in:
GriffinR 2022-02-05 21:31:54 -05:00 committed by huderlem
parent 31f400e2c9
commit b01581dc4d
11 changed files with 289 additions and 221 deletions

View file

@ -148,7 +148,7 @@ public:
this->enableHiddenItemQuantity = false;
this->enableHiddenItemRequiresItemfinder = false;
this->enableHealLocationRespawnData = false;
this->enableObjectEventInConnection = false;
this->enableEventCloneObject = false;
this->enableFloorNumber = false;
this->createMapTextFile = false;
this->enableTripleLayerMetatiles = false;
@ -178,8 +178,8 @@ public:
bool getHiddenItemRequiresItemfinderEnabled();
void setHealLocationRespawnDataEnabled(bool enable);
bool getHealLocationRespawnDataEnabled();
void setObjectEventInConnectionEnabled(bool enable);
bool getObjectEventInConnectionEnabled();
void setEventCloneObjectEnabled(bool enable);
bool getEventCloneObjectEnabled();
void setFloorNumberEnabled(bool enable);
bool getFloorNumberEnabled();
void setCreateMapTextFileEnabled(bool enable);
@ -206,7 +206,7 @@ private:
bool enableHiddenItemQuantity;
bool enableHiddenItemRequiresItemfinder;
bool enableHealLocationRespawnData;
bool enableObjectEventInConnection;
bool enableEventCloneObject;
bool enableFloorNumber;
bool createMapTextFile;
bool enableTripleLayerMetatiles;

View file

@ -14,6 +14,7 @@ class EventType
{
public:
static QString Object;
static QString CloneObject;
static QString Warp;
static QString Trigger;
static QString WeatherTrigger;
@ -23,6 +24,16 @@ public:
static QString HealLocation;
};
class EventGroup
{
public:
static QString Object;
static QString Warp;
static QString Coord;
static QString Bg;
static QString Heal;
};
class DraggablePixmapItem;
class Project;
class Event
@ -68,6 +79,7 @@ public:
static Event* createNewEvent(QString, QString, Project*);
static Event* createNewObjectEvent(Project*);
static Event* createNewCloneObjectEvent(Project*, QString);
static Event* createNewWarpEvent(QString);
static Event* createNewHealLocationEvent(QString);
static Event* createNewTriggerEvent(Project*);
@ -75,8 +87,11 @@ public:
static Event* createNewSignEvent(Project*);
static Event* createNewHiddenItemEvent(Project*);
static Event* createNewSecretBaseEvent(Project*);
static bool isValidType(QString event_type);
static QString typeToGroup(QString event_type);
OrderedJson::object buildObjectEventJSON();
OrderedJson::object buildCloneObjectEventJSON(const QMap<QString, QString> &);
OrderedJson::object buildWarpEventJSON(const QMap<QString, QString> &);
OrderedJson::object buildTriggerEventJSON();
OrderedJson::object buildWeatherTriggerEventJSON();
@ -86,7 +101,7 @@ public:
void setPixmapFromSpritesheet(QImage, int, int, bool);
int getPixelX();
int getPixelY();
QMap<QString, bool> getExpectedFields();
QStringList getExpectedFields();
void readCustomValues(QJsonObject values);
void addCustomValuesTo(OrderedJson::object *obj);
void setFrameFromMovement(QString);

View file

@ -60,7 +60,7 @@ public:
QMap<QString, int> mapSectionNameToValue;
QMap<int, QString> mapSectionValueToName;
QMap<QString, EventGraphics*> eventGraphicsMap;
QStringList gfxNames;
QMap<QString, int> gfxDefines;
QStringList songNames;
QStringList itemNames;
QStringList flagNames;

View file

@ -11,6 +11,7 @@ public:
explicit NewEventToolButton(QWidget *parent = nullptr);
QString getSelectedEventType();
QAction *newObjectAction;
QAction *newCloneObjectAction;
QAction *newWarpAction;
QAction *newHealLocationAction;
QAction *newTriggerAction;
@ -20,6 +21,7 @@ public:
QAction *newSecretBaseAction;
public slots:
void newObject();
void newCloneObject();
void newWarp();
void newHealLocation();
void newTrigger();

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

@ -10,6 +10,7 @@ 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";
@ -20,6 +21,7 @@ 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},
@ -58,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) {
@ -77,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;
@ -85,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", EventGroup::Object);
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");
@ -103,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", EventGroup::Warp);
event->put("event_type", EventType::Warp);
event->put("destination_warp", 0);
event->put("destination_map_name", map_name);
event->put("elevation", 0);
@ -117,8 +125,6 @@ Event* Event::createNewWarpEvent(QString map_name)
Event* Event::createNewHealLocationEvent(QString map_name)
{
Event *event = new Event;
event->put("event_group_type", EventGroup::Heal);
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);
@ -132,8 +138,6 @@ Event* Event::createNewHealLocationEvent(QString map_name)
Event* Event::createNewTriggerEvent(Project *project)
{
Event *event = new Event;
event->put("event_group_type", EventGroup::Coord);
event->put("event_type", EventType::Trigger);
event->put("script_label", "NULL");
event->put("script_var", project->varNames.first());
event->put("script_var_value", "0");
@ -144,8 +148,6 @@ Event* Event::createNewTriggerEvent(Project *project)
Event* Event::createNewWeatherTriggerEvent(Project *project)
{
Event *event = new Event;
event->put("event_group_type", EventGroup::Coord);
event->put("event_type", EventType::WeatherTrigger);
event->put("weather", project->coordEventWeatherNames.first());
event->put("elevation", 0);
return event;
@ -154,8 +156,6 @@ Event* Event::createNewWeatherTriggerEvent(Project *project)
Event* Event::createNewSignEvent(Project *project)
{
Event *event = new Event;
event->put("event_group_type", EventGroup::Bg);
event->put("event_type", EventType::Sign);
event->put("player_facing_direction", project->bgEventFacingDirections.first());
event->put("script_label", "NULL");
event->put("elevation", 0);
@ -165,8 +165,6 @@ Event* Event::createNewSignEvent(Project *project)
Event* Event::createNewHiddenItemEvent(Project *project)
{
Event *event = new Event;
event->put("event_group_type", EventGroup::Bg);
event->put("event_type", EventType::HiddenItem);
event->put("item", project->itemNames.first());
event->put("flag", project->flagNames.first());
event->put("elevation", 3);
@ -182,8 +180,6 @@ Event* Event::createNewHiddenItemEvent(Project *project)
Event* Event::createNewSecretBaseEvent(Project *project)
{
Event *event = new Event;
event->put("event_group_type", EventGroup::Bg);
event->put("event_type", EventType::SecretBase);
event->put("secret_base_id", project->secretBaseIds.first());
event->put("elevation", 0);
return event;
@ -199,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 QStringList 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 QStringList 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 QStringList expectedWarpFields = {
"elevation",
"dest_map",
"dest_warp_id",
};
static QMap<QString, bool> expectedWeatherTriggerFields {
{"type", true},
{"x", true},
{"y", true},
{"elevation", true},
{"weather", true},
const QStringList 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 QStringList expectedWeatherTriggerFields = {
"type",
"elevation",
"weather",
};
static QMap<QString, bool> expectedHiddenItemFields {
{"type", true},
{"x", true},
{"y", true},
{"elevation", true},
{"item", true},
{"flag", true},
const QStringList 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 QStringList expectedHiddenItemFields = {
"type",
"elevation",
"item",
"flag",
};
QMap<QString, bool> Event::getExpectedFields()
const QStringList expectedSecretBaseFields = {
"type",
"elevation",
"secret_base_id",
};
QStringList Event::getExpectedFields()
{
QString type = this->get("event_type");
QMap<QString, bool> expectedFields = QMap<QString, bool>();
QStringList expectedFields = QStringList();
if (type == EventType::Object) {
expectedFields = expectedObjectFields;
if (projectConfig.getObjectEventInConnectionEnabled()) {
expectedFields.insert("in_connection", true);
if (projectConfig.getEventCloneObjectEnabled()) {
expectedFields.append("type");
}
} else if (type == EventType::CloneObject) {
expectedFields = expectedCloneObjectFields;
} else if (type == EventType::Warp) {
expectedFields = expectedWarpFields;
} else if (type == EventType::Trigger) {
@ -285,23 +276,24 @@ QMap<QString, bool> Event::getExpectedFields()
} else if (type == EventType::HiddenItem) {
expectedFields = expectedHiddenItemFields;
if (projectConfig.getHiddenItemQuantityEnabled()) {
expectedFields.insert("quantity", true);
expectedFields.append("quantity");
}
if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) {
expectedFields.insert("underfoot", true);
expectedFields.append("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();
QStringList expectedFields = this->getExpectedFields();
for (QString key : values.keys()) {
if (!expectedValues.contains(key)) {
if (!expectedFields.contains(key)) {
this->customValues[key] = values[key].toString();
}
}
@ -318,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)

View file

@ -2064,7 +2064,7 @@ 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)
if (Event::typeToGroup(event_type) == EventGroup::Object)
return map->events.value(EventGroup::Object).length() >= project->getMaxObjectEvents();
}
return false;

View file

@ -389,23 +389,13 @@ void MainWindow::setProjectSpecificUIVisibility()
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)
@ -1859,7 +1849,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 +1869,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 +1909,6 @@ void MainWindow::updateSelectedObjects() {
QList<EventPropertiesFrame *> frames;
bool inConnectionEnabled = projectConfig.getObjectEventInConnectionEnabled();
bool quantityEnabled = projectConfig.getHiddenItemQuantityEnabled();
bool underfootEnabled = projectConfig.getHiddenItemRequiresItemfinderEnabled();
bool respawnDataEnabled = projectConfig.getHealLocationRespawnDataEnabled();
@ -2021,7 +1973,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 +1986,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 +2016,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 +2064,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 +2189,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 +2200,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);
}

View file

@ -213,26 +213,51 @@ bool Project::loadMapData(Map* map) {
// Events
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 == "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", EventGroup::Object);
map->events[EventGroup::Object].append(object);
}
map->events[EventGroup::Warp].clear();
@ -1334,9 +1359,15 @@ void Project::saveMap(Map *map) {
// Object events
OrderedJson::array objectEventsArr;
for (int i = 0; i < map->events[EventGroup::Object].length(); i++) {
Event *object_event = map->events[EventGroup::Object].value(i);
OrderedJson::object eventObj = object_event->buildObjectEventJSON();
objectEventsArr.push_back(eventObj);
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;
@ -2248,9 +2279,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 +2410,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 +2466,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("&", "");

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 Object Clone", 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;