From 582405d68bc15f7adc3c5b2efbd938e35c79a784 Mon Sep 17 00:00:00 2001 From: garak Date: Tue, 19 Jul 2022 17:56:12 -0400 Subject: [PATCH] change Event class design in favor of polymorphism --- forms/mainwindow.ui | 310 +++++++- include/core/event.h | 123 --- include/core/events.h | 669 ++++++++++++++++ include/core/heallocation.h | 5 +- include/core/map.h | 18 +- include/core/parseutil.h | 1 + include/core/regionmapeditcommands.h | 2 +- include/editor.h | 10 +- include/lib/orderedjson.h | 4 +- include/mainwindow.h | 10 +- include/project.h | 6 +- include/ui/customattributestable.h | 2 +- include/ui/draggablepixmapitem.h | 29 +- include/ui/eventframes.h | 272 +++++++ include/ui/eventpropertiesframe.h | 29 - include/ui/neweventtoolbutton.h | 8 +- porymap.pro | 10 +- src/core/editcommands.cpp | 44 +- src/core/event.cpp | 480 ------------ src/core/events.cpp | 875 +++++++++++++++++++++ src/core/heallocation.cpp | 39 +- src/core/map.cpp | 30 +- src/core/parseutil.cpp | 2 + src/core/regionmapeditcommands.cpp | 3 +- src/editor.cpp | 131 +++- src/mainwindow.cpp | 697 +++++------------ src/project.cpp | 325 +++----- src/ui/customattributestable.cpp | 9 +- src/ui/draggablepixmapitem.cpp | 60 +- src/ui/eventframes.cpp | 1054 ++++++++++++++++++++++++++ src/ui/eventpropertiesframe.cpp | 28 - src/ui/mapimageexporter.cpp | 30 +- src/ui/neweventtoolbutton.cpp | 20 +- src/ui/newmappopup.cpp | 1 - 34 files changed, 3675 insertions(+), 1661 deletions(-) delete mode 100644 include/core/event.h create mode 100644 include/core/events.h create mode 100644 include/ui/eventframes.h delete mode 100644 include/ui/eventpropertiesframe.h delete mode 100644 src/core/event.cpp create mode 100644 src/core/events.cpp create mode 100644 src/ui/eventframes.cpp delete mode 100644 src/ui/eventpropertiesframe.cpp diff --git a/forms/mainwindow.ui b/forms/mainwindow.ui index f7e9e245..3eaded3f 100644 --- a/forms/mainwindow.ui +++ b/forms/mainwindow.ui @@ -813,8 +813,8 @@ 0 0 - 428 - 77 + 423 + 74 @@ -1001,10 +1001,10 @@ - 0 + 8 0 411 - 449 + 413 @@ -1155,7 +1155,7 @@ 0 0 428 - 704 + 696 @@ -1404,16 +1404,6 @@ 3 - - - - There are no events on the current map. - - - Qt::AlignCenter - - - @@ -1522,6 +1512,16 @@ + + + + There are no events on the current map. + + + Qt::AlignCenter + + + @@ -1544,8 +1544,57 @@ 0 + + + + 12 + + + 12 + + + 12 + + + 0 + + + + + + 60 + 0 + + + + + + + + object id + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + QFrame::NoFrame + true @@ -1557,8 +1606,8 @@ 0 0 - 98 - 28 + 434 + 581 @@ -1589,8 +1638,57 @@ 0 + + + + 12 + + + 12 + + + 12 + + + 0 + + + + + + 60 + 0 + + + + + + + + warp id + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + QFrame::NoFrame + true @@ -1602,8 +1700,8 @@ 0 0 - 98 - 28 + 434 + 581 @@ -1634,8 +1732,57 @@ 0 + + + + 12 + + + 12 + + + 12 + + + 0 + + + + + + 60 + 0 + + + + + + + + coord id + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + QFrame::NoFrame + true @@ -1647,8 +1794,8 @@ 0 0 - 98 - 28 + 434 + 581 @@ -1679,8 +1826,63 @@ 0 + + + + 12 + + + 12 + + + 12 + + + 0 + + + + + + 0 + 0 + + + + + 60 + 0 + + + + + + + + bg id + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + QFrame::NoFrame + true @@ -1692,8 +1894,8 @@ 0 0 - 98 - 28 + 434 + 581 @@ -1724,8 +1926,57 @@ 0 + + + + 12 + + + 12 + + + 12 + + + 0 + + + + + + 60 + 0 + + + + + + + + heal id + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + QFrame::NoFrame + true @@ -1737,8 +1988,8 @@ 0 0 - 98 - 28 + 434 + 581 @@ -1777,6 +2028,9 @@ 0 + + QFrame::NoFrame + true @@ -1788,8 +2042,8 @@ 0 0 - 98 - 28 + 434 + 625 @@ -2679,7 +2933,7 @@ 0 0 1287 - 21 + 22 diff --git a/include/core/event.h b/include/core/event.h deleted file mode 100644 index 7a82d5cd..00000000 --- a/include/core/event.h +++ /dev/null @@ -1,123 +0,0 @@ -#pragma once -#ifndef EVENT_H -#define EVENT_H - -#include -#include -#include - -#include "orderedjson.h" - -using OrderedJson = poryjson::Json; - -class EventType -{ -public: - static QString Object; - static QString CloneObject; - static QString Warp; - static QString Trigger; - static QString WeatherTrigger; - static QString Sign; - static QString HiddenItem; - static QString SecretBase; - 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 -{ -public: - Event(); - Event(const Event&); - Event(QJsonObject, QString); -public: - int x() const { - return getInt("x"); - } - int y() const { - return getInt("y"); - } - int elevation() { - return getInt("elevation"); - } - void setX(int x) { - put("x", x); - } - void setY(int y) { - put("y", y); - } - QString get(const QString &key) const { - return values.value(key); - } - int getInt(const QString &key) const { - return values.value(key).toInt(nullptr, 0); - } - uint16_t getU16(const QString &key) const { - return values.value(key).toUShort(nullptr, 0); - } - int16_t getS16(const QString &key) const { - return values.value(key).toShort(nullptr, 0); - } - void put(QString key, int value) { - put(key, QString("%1").arg(value)); - } - void put(QString key, QString value) { - values.insert(key, value); - } - - 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*); - static Event* createNewWeatherTriggerEvent(Project*); - static Event* createNewSignEvent(Project*); - static Event* createNewHiddenItemEvent(Project*); - static Event* createNewSecretBaseEvent(Project*); - static bool isValidType(QString event_type); - static QString typeToGroup(QString event_type); - static int getIndexOffset(QString group_type); - - OrderedJson::object buildObjectEventJSON(); - OrderedJson::object buildCloneObjectEventJSON(const QMap &); - OrderedJson::object buildWarpEventJSON(const QMap &); - OrderedJson::object buildTriggerEventJSON(); - OrderedJson::object buildWeatherTriggerEventJSON(); - OrderedJson::object buildSignEventJSON(); - OrderedJson::object buildHiddenItemEventJSON(); - OrderedJson::object buildSecretBaseEventJSON(); - void setPixmapFromSpritesheet(QImage, int, int, bool); - int getPixelX(); - int getPixelY(); - QSet getExpectedFields(); - void readCustomValues(QJsonObject values); - void addCustomValuesTo(OrderedJson::object *obj); - void setFrameFromMovement(QString); - - QMap values; - QMap customValues; - QPixmap pixmap; - int spriteWidth; - int spriteHeight; - int frame = 0; - bool hFlip = false; - bool usingSprite; - - DraggablePixmapItem *pixmapItem = nullptr; - void setPixmapItem(DraggablePixmapItem *item) { pixmapItem = item; } -}; - -#endif // EVENT_H diff --git a/include/core/events.h b/include/core/events.h new file mode 100644 index 00000000..9998d630 --- /dev/null +++ b/include/core/events.h @@ -0,0 +1,669 @@ +#pragma once +#ifndef EVENTS_H +#define EVENTS_H + +#include +#include +#include +#include +#include + +#include "orderedjson.h" +using OrderedJson = poryjson::Json; + + +class Project; +class Map; +class EventFrame; +class ObjectFrame; +class CloneObjectFrame; +class WarpFrame; +class DraggablePixmapItem; + +class Event; +class ObjectEvent; +class CloneObjectEvent; +class WarpEvent; +class CoordEvent; +class TriggerEvent; +class WeatherTriggerEvent; +class BgEvent; +class SignEvent; +class HiddenItemEvent; +class SecretBaseEvent; +class HealLocationEvent; + +class EventVisitor { +public: + virtual void nothing() { } + virtual void visitObject(ObjectEvent *) = 0; + virtual void visitTrigger(TriggerEvent *) = 0; + virtual void visitSign(SignEvent *) = 0; +}; + + + +/// +/// Event base class -- purely virtual +/// +class Event { +public: + virtual ~Event(); + + // disable copy constructor + Event(const Event &other) = delete; + + // disable assignment operator + Event& operator=(const Event &other) = delete; + +protected: + Event() { + this->spriteWidth = 16; + this->spriteHeight = 16; + this->usingSprite = false; + } + +// public enums & static methods +public: + enum class Type { + Object, CloneObject, + Warp, + Trigger, WeatherTrigger, + Sign, HiddenItem, SecretBase, + HealLocation, + Generic, + None, + }; + + enum class Group { + Object, + Warp, + Coord, + Bg, + Heal, + None, + }; + + // all event groups excepts warps have IDs that start at 1 + static int getIndexOffset(Event::Group group) { + return (group == Event::Group::Warp) ? 0 : 1; + } + + static Event::Group typeToGroup(Event::Type type) { + switch (type) { + case Event::Type::Object: + case Event::Type::CloneObject: + return Event::Group::Object; + case Event::Type::Warp: + return Event::Group::Warp; + case Event::Type::Trigger: + case Event::Type::WeatherTrigger: + return Event::Group::Coord; + case Event::Type::Sign: + case Event::Type::HiddenItem: + case Event::Type::SecretBase: + return Event::Group::Bg; + case Event::Type::HealLocation: + return Event::Group::Heal; + default: + return Event::Group::None; + } + } + + +// standard public methods +public: + + virtual Event *duplicate() = 0; + + void setMap(Map *newMap) { this->map = newMap; } + Map *getMap() const { return this->map; } + + virtual void accept(EventVisitor *) { } + + void setX(int newX) { this->x = newX; } + void setY(int newY) { this->y = newY; } + void setZ(int newZ) { this->elevation = newZ; } + void setElevation(int newElevation) { this->elevation = newElevation; } + + int getX() const { return this->x; } + int getY() const { return this->y; } + int getZ() const { return this->elevation; } + int getElevation() const { return this->elevation; } + + int getPixelX() const { return (this->x * 16) - qMax(0, (this->spriteWidth - 16) / 2); } + int getPixelY() const { return (this->y * 16) - qMax(0, this->spriteHeight - 16); } + + virtual EventFrame *getEventFrame(); + virtual EventFrame *createEventFrame() = 0; + void destroyEventFrame(); + + Event::Group getEventGroup() const { return this->eventGroup; } + Event::Type getEventType() const { return this->eventType; } + + virtual OrderedJson::object buildEventJson(Project *project) = 0; + virtual bool loadFromJson(QJsonObject json, Project *project) = 0; + + virtual void setDefaultValues(Project *project); + + virtual QSet getExpectedFields() = 0; + void readCustomValues(QJsonObject values); + void addCustomValuesTo(OrderedJson::object *obj); + QMap getCustomValues() { return this->customValues; } + void setCustomValues(QMap newCustomValues) { this->customValues = newCustomValues; } + + virtual void loadPixmap(Project *project) = 0; + + void setPixmap(QPixmap newPixmap) { this->pixmap = newPixmap; } + QPixmap getPixmap() { return this->pixmap; } + + void setPixmapItem(DraggablePixmapItem *item) { this->pixmapItem = item; } + DraggablePixmapItem *getPixmapItem() { return this->pixmapItem; } + + void setUsingSprite(bool newUsingSprite) { this->usingSprite = newUsingSprite; } + bool getUsingSprite() const { return this->usingSprite; } + + void setSpriteWidth(int newSpriteWidth) { this->spriteWidth = newSpriteWidth; } + int getspriteWidth() const { return this->spriteWidth; } + + void setSpriteHeight(int newSpriteHeight) { this->spriteHeight = newSpriteHeight; } + int getspriteHeight() const { return this->spriteHeight; } + + int getEventIndex(); + + static QString eventTypeToString(Event::Type type); + static Event::Type eventTypeFromString(QString type); + + +// pure virtual public methods +public: + + // // update spinbox values, etc, combo indices + // virtual void updateFrame(); // setFrameFromMovement, (aka redisplay?) + // virtual void disableFrame(); // setParrent(nullptr), disconnectSignals() + +// protected attributes +protected: + Map *map = nullptr; + + Type eventType = Event::Type::None; + Group eventGroup = Event::Group::None; + + // could be private? + int x = 0; + int y = 0; + int elevation = 0; + + int spriteWidth = 16; + int spriteHeight = 16; + bool usingSprite = false; + + QMap customValues; + + QPixmap pixmap; + DraggablePixmapItem *pixmapItem = nullptr; + + EventFrame *eventFrame = nullptr; +}; + + + +/// +/// Object Event +/// +class ObjectEvent : public Event { + // + // in each derived class constructor, need to createEventFrame, since not + // doing that in base class. make sure to upcall though + +public: + ObjectEvent() : Event() { + this->eventGroup = Event::Group::Object; + this->eventType = Event::Type::Object; + } + virtual ~ObjectEvent() {} + + virtual Event *duplicate() override; + + virtual void accept(EventVisitor *visitor) override { visitor->visitObject(this); } + + //virtual EventFrame *getEventFrame() override; + virtual EventFrame *createEventFrame() override; + + virtual OrderedJson::object buildEventJson(Project *project) override; + virtual bool loadFromJson(QJsonObject json, Project *project) override; + + virtual void setDefaultValues(Project *project) override; + + virtual QSet getExpectedFields() override; + + virtual void loadPixmap(Project *project) override; + + void setGfx(QString newGfx) { this->gfx = newGfx; } + QString getGfx() { return this->gfx; } + + void setMovement(QString newMovement) { this->movement = newMovement; } + QString getMovement() { return this->movement; } + + void setRadiusX(int newRadiusX) { this->radiusX = newRadiusX; } + int getRadiusX() { return this->radiusX; } + + void setRadiusY(int newRadiusY) { this->radiusY = newRadiusY; } + int getRadiusY() { return this->radiusY; } + + void setTrainerType(QString newTrainerType) { this->trainerType = newTrainerType; } + QString getTrainerType() { return this->trainerType; } + + void setSightRadiusBerryTreeID(QString newValue) { this->sightRadiusBerryTreeID = newValue; } + QString getSightRadiusBerryTreeID() { return this->sightRadiusBerryTreeID; } + + void setScript(QString newScript) { this->script = newScript; } + QString getScript() { return this->script; } + + void setFlag(QString newFlag) { this->flag = newFlag; } + QString getFlag() { return this->flag; } + +public: + void setFrameFromMovement(QString movement); + void setPixmapFromSpritesheet(QImage, int, int, bool); + + +protected: + QString gfx; + QString movement; + int radiusX = 0; + int radiusY = 0; + QString trainerType; + QString sightRadiusBerryTreeID; // TODO: int? + QString script; + QString flag; + + int frame = 0; + bool hFlip = false; + bool vFlip = false; +}; + + + +/// +/// Clone Object Event +/// +class CloneObjectEvent : public ObjectEvent { + +public: + CloneObjectEvent() : ObjectEvent() { + this->eventGroup = Event::Group::Object; + this->eventType = Event::Type::CloneObject; + } + virtual ~CloneObjectEvent() {} + + virtual Event *duplicate() override; + + virtual EventFrame *createEventFrame() override; + + virtual OrderedJson::object buildEventJson(Project *project) override; + virtual bool loadFromJson(QJsonObject json, Project *project) override; + + virtual void setDefaultValues(Project *project) override; + + virtual QSet getExpectedFields() override; + + virtual void loadPixmap(Project *project) override; + + void setTargetMap(QString newTargetMap) { this->targetMap = newTargetMap; } + QString getTargetMap() { return this->targetMap; } + + void setTargetID(int newTargetID) { this->targetID = newTargetID; } + int getTargetID() { return this->targetID; } + +private: + QString targetMap; + int targetID = 0; +}; + + + +/// +/// Warp Event +/// +class WarpEvent : public Event { + +public: + WarpEvent() : Event() { + this->eventGroup = Event::Group::Warp; + this->eventType = Event::Type::Warp; + } + virtual ~WarpEvent() {} + + virtual Event *duplicate() override; + + virtual EventFrame *createEventFrame() override; + + virtual OrderedJson::object buildEventJson(Project *project) override; + virtual bool loadFromJson(QJsonObject json, Project *project) override; + + virtual void setDefaultValues(Project *project) override; + + virtual QSet getExpectedFields() override; + + virtual void loadPixmap(Project *) override; + + void setDestinationMap(QString newDestinationMap) { this->destinationMap = newDestinationMap; } + QString getDestinationMap() { return this->destinationMap; } + + void setDestinationWarpID(int newDestinationWarpID) { this->destinationWarpID = newDestinationWarpID; } + int getDestinationWarpID() { return this->destinationWarpID; } + +private: + QString destinationMap; + int destinationWarpID = 0; +}; + + + +/// +/// Coord Event +/// +class CoordEvent : public Event { + +public: + CoordEvent() : Event() {} + virtual ~CoordEvent() {} + + virtual Event *duplicate() override = 0; + + virtual EventFrame *createEventFrame() override = 0; + + virtual OrderedJson::object buildEventJson(Project *project) override = 0; + virtual bool loadFromJson(QJsonObject json, Project *project) override = 0; + + virtual void setDefaultValues(Project *project) override = 0; + + virtual QSet getExpectedFields() override = 0; + + virtual void loadPixmap(Project *) override; +}; + + + +/// +/// Trigger Event +/// +class TriggerEvent : public CoordEvent { + +public: + TriggerEvent() : CoordEvent() { + this->eventGroup = Event::Group::Coord; + this->eventType = Event::Type::Trigger; + } + virtual ~TriggerEvent() {} + + virtual Event *duplicate() override; + + virtual void accept(EventVisitor *visitor) override { visitor->visitTrigger(this); } + + virtual EventFrame *createEventFrame() override; + + virtual OrderedJson::object buildEventJson(Project *project) override; + virtual bool loadFromJson(QJsonObject json, Project *project) override; + + virtual void setDefaultValues(Project *project) override; + + virtual QSet getExpectedFields() override; + + void setScriptVar(QString newScriptVar) { this->scriptVar = newScriptVar; } + QString getScriptVar() { return this->scriptVar; } + + void setScriptVarValue(QString newScriptVarValue) { this->scriptVarValue = newScriptVarValue; } + QString getScriptVarValue() { return this->scriptVarValue; } + + void setScriptLabel(QString newScriptLabel) { this->scriptLabel = newScriptLabel; } + QString getScriptLabel() { return this->scriptLabel; } + +private: + QString scriptVar; + QString scriptVarValue; + QString scriptLabel; +}; + + + +/// +/// Weather Trigger Event +/// +class WeatherTriggerEvent : public CoordEvent { + +public: + WeatherTriggerEvent() : CoordEvent() { + this->eventGroup = Event::Group::Coord; + this->eventType = Event::Type::WeatherTrigger; + } + virtual ~WeatherTriggerEvent() {} + + virtual Event *duplicate() override; + + virtual EventFrame *createEventFrame() override; + + virtual OrderedJson::object buildEventJson(Project *project) override; + virtual bool loadFromJson(QJsonObject json, Project *project) override; + + virtual void setDefaultValues(Project *project) override; + + virtual QSet getExpectedFields() override; + + void setWeather(QString newWeather) { this->weather = newWeather; } + QString getWeather() { return this->weather; } + +private: + QString weather; +}; + + + +/// +/// BG Event +/// +class BGEvent : public Event { + +public: + BGEvent() : Event() { + this->eventGroup = Event::Group::Bg; + } + virtual ~BGEvent() {} + + virtual Event *duplicate() override = 0; + + virtual EventFrame *createEventFrame() override = 0; + + virtual OrderedJson::object buildEventJson(Project *project) override = 0; + virtual bool loadFromJson(QJsonObject json, Project *project) override = 0; + + virtual void setDefaultValues(Project *project) override = 0; + + virtual QSet getExpectedFields() override = 0; + + virtual void loadPixmap(Project *project) override; +}; + + + +/// +/// Sign Event +/// +class SignEvent : public BGEvent { + +public: + SignEvent() : BGEvent() { + this->eventType = Event::Type::Sign; + } + virtual ~SignEvent() {} + + virtual Event *duplicate() override; + + virtual void accept(EventVisitor *visitor) override { visitor->visitSign(this); } + + virtual EventFrame *createEventFrame() override; + + virtual OrderedJson::object buildEventJson(Project *project) override; + virtual bool loadFromJson(QJsonObject json, Project *project) override; + + virtual void setDefaultValues(Project *project) override; + + virtual QSet getExpectedFields() override; + + void setFacingDirection(QString newFacingDirection) { this->facingDirection = newFacingDirection; } + QString getFacingDirection() { return this->facingDirection; } + + void setScriptLabel(QString newScriptLabel) { this->scriptLabel = newScriptLabel; } + QString getScriptLabel() { return this->scriptLabel; } + +private: + QString facingDirection; + QString scriptLabel; +}; + + + +/// +/// Hidden Item Event +/// +class HiddenItemEvent : public BGEvent { + +public: + HiddenItemEvent() : BGEvent() { + this->eventType = Event::Type::HiddenItem; + } + virtual ~HiddenItemEvent() {} + + virtual Event *duplicate() override; + + virtual EventFrame *createEventFrame() override; + + virtual OrderedJson::object buildEventJson(Project *project) override; + virtual bool loadFromJson(QJsonObject json, Project *project) override; + + virtual void setDefaultValues(Project *project) override; + + virtual QSet getExpectedFields() override; + + void setItem(QString newItem) { this->item = newItem; } + QString getItem() { return this->item; } + + void setFlag(QString newFlag) { this->flag = newFlag; } + QString getFlag() { return this->flag; } + + void setQuantity(int newQuantity) { this->quantity = newQuantity; } + int getQuantity() { return this->quantity; } + + void setUnderfoot(bool newUnderfoot) { this->underfoot = newUnderfoot; } + bool getUnderfoot() { return this->underfoot; } + +private: + QString item; + QString flag; + + // optional + int quantity = 0; + bool underfoot = false; +}; + + + +/// +/// Secret Base Event +/// +class SecretBaseEvent : public BGEvent { + +public: + SecretBaseEvent() : BGEvent() { + this->eventType = Event::Type::SecretBase; + } + virtual ~SecretBaseEvent() {} + + virtual Event *duplicate() override; + + virtual EventFrame *createEventFrame() override; + + virtual OrderedJson::object buildEventJson(Project *project) override; + virtual bool loadFromJson(QJsonObject json, Project *project) override; + + virtual void setDefaultValues(Project *project) override; + + virtual QSet getExpectedFields() override; + + void setBaseID(QString newBaseID) { this->baseID = newBaseID; } + QString getBaseID() { return this->baseID; } + +private: + QString baseID; +}; + + + +/// +/// Heal Location Event +/// +class HealLocationEvent : public Event { + +public: + HealLocationEvent() : Event() { + this->eventGroup = Event::Group::Heal; + this->eventType = Event::Type::HealLocation; + } + virtual ~HealLocationEvent() {} + + virtual Event *duplicate() override { return nullptr; } + + virtual EventFrame *createEventFrame() override; + + virtual OrderedJson::object buildEventJson(Project *project) override; + virtual bool loadFromJson(QJsonObject, Project *) override { return false; } + + virtual void setDefaultValues(Project *project) override; + + virtual QSet getExpectedFields() override { return QSet(); } + + virtual void loadPixmap(Project *project) override; + + void setIndex(int newIndex) { this->index = newIndex; } + int getIndex() { return this->index; } + + void setLocationName(QString newLocationName) { this->locationName = newLocationName; } + QString getLocationName() { return this->locationName; } + + void setIdName(QString newIdName) { this->idName = newIdName; } + QString getIdName() { return this->idName; } + + void setRespawnMap(QString newRespawnMap) { this->respawnMap = newRespawnMap; } + QString getRespawnMap() { return this->respawnMap; } + + void setRespawnNPC(uint16_t newRespawnNPC) { this->respawnNPC = newRespawnNPC; } + uint16_t getRespawnNPC() { return this->respawnNPC; } + +private: + int index = -1; + QString locationName; + QString idName; + QString respawnMap; + uint16_t respawnNPC = 0; +}; + + + +/// +/// Keeps track of scripts +/// +class ScriptTracker : public EventVisitor { +public: + virtual void visitObject(ObjectEvent *object) override { this->scripts << object->getScript(); }; + virtual void visitTrigger(TriggerEvent *trigger) override { this->scripts << trigger->getScriptLabel(); }; + virtual void visitSign(SignEvent *sign) override { this->scripts << sign->getScriptLabel(); }; + + QStringList getScripts() { return this->scripts; } + +private: + QStringList scripts; +}; + + +#endif // EVENTS_H diff --git a/include/core/heallocation.h b/include/core/heallocation.h index a39386c1..fbb93308 100644 --- a/include/core/heallocation.h +++ b/include/core/heallocation.h @@ -2,10 +2,11 @@ #ifndef HEALLOCATION_H #define HEALLOCATION_H -#include "event.h" #include #include +class Event; + class HealLocation { public: @@ -21,7 +22,7 @@ public: uint16_t y; QString respawnMap; uint16_t respawnNPC; - static HealLocation fromEvent(Event*); + static HealLocation fromEvent(Event *); }; #endif // HEALLOCATION_H diff --git a/include/core/map.h b/include/core/map.h index 717fd0f3..39aa8fef 100644 --- a/include/core/map.h +++ b/include/core/map.h @@ -6,7 +6,7 @@ #include "mapconnection.h" #include "maplayout.h" #include "tileset.h" -#include "event.h" +#include "events.h" #include #include @@ -63,7 +63,10 @@ public: QPixmap collision_pixmap; QImage image; QPixmap pixmap; - QMap> events; + + QMap> events; + QList ownedEvents; // for memory management + QList connections; QList metatileLayerOrder; QList metatileLayerOpacity; @@ -92,10 +95,10 @@ public: void floodFillCollisionElevation(int x, int y, uint16_t collision, uint16_t elevation); void _floodFillCollisionElevation(int x, int y, uint16_t collision, uint16_t elevation); void magicFillCollisionElevation(int x, int y, uint16_t collision, uint16_t elevation); - QList getAllEvents() const; - QStringList eventScriptLabels(const QString &event_group_type = QString()) const; - void removeEvent(Event*); - void addEvent(Event*); + QList getAllEvents() const; + QStringList eventScriptLabels(Event::Group group = Event::Group::None) const; + void removeEvent(Event *); + void addEvent(Event *); QPixmap renderConnection(MapConnection, MapLayout *); QPixmap renderBorder(bool ignoreCache = false); void setDimensions(int newWidth, int newHeight, bool setNewBlockdata = true, bool enableScriptCallback = false); @@ -105,9 +108,6 @@ public: bool isWithinBounds(int x, int y); bool isWithinBorderBounds(int x, int y); - // for memory management - QVector ownedEvents; - MapPixmapItem *mapItem = nullptr; void setMapItem(MapPixmapItem *item) { mapItem = item; } diff --git a/include/core/parseutil.h b/include/core/parseutil.h index 5cb07366..97bf2e71 100644 --- a/include/core/parseutil.h +++ b/include/core/parseutil.h @@ -4,6 +4,7 @@ #include "heallocation.h" #include "log.h" +#include "orderedjson.h" #include #include diff --git a/include/core/regionmapeditcommands.h b/include/core/regionmapeditcommands.h index 16cd6486..69bea251 100644 --- a/include/core/regionmapeditcommands.h +++ b/include/core/regionmapeditcommands.h @@ -158,7 +158,7 @@ public: void undo() override; void redo() override; - bool mergeWith(const QUndoCommand *command) override { return false; } + bool mergeWith(const QUndoCommand *) override { return false; } int id() const override { return RMCommandId::ID_ClearEntries; } private: diff --git a/include/editor.h b/include/editor.h index 03573ae1..811848a2 100644 --- a/include/editor.h +++ b/include/editor.h @@ -96,7 +96,7 @@ public: DraggablePixmapItem *addMapEvent(Event *event); void selectMapEvent(DraggablePixmapItem *object); void selectMapEvent(DraggablePixmapItem *object, bool toggle); - DraggablePixmapItem *addNewEvent(QString event_type); + DraggablePixmapItem *addNewEvent(Event::Type type); void deleteEvent(Event *); void updateSelectedEvents(); void duplicateSelectedEvents(); @@ -131,8 +131,7 @@ public: CurrentSelectedMetatilesPixmapItem *current_metatile_selection_item = nullptr; MovementPermissionsSelector *movement_permissions_selector_item = nullptr; - QList *events = nullptr; - QList *selected_events = nullptr; + QList *selected_events = nullptr; QString map_edit_mode = "paint"; QString obj_edit_mode = "select"; @@ -151,7 +150,7 @@ public: void shouldReselectEvents(); void scaleMapView(int); void openInTextEditor(const QString &path, int lineNum = 0) const; - bool eventLimitReached(QString event_type); + bool eventLimitReached(Event::Type type); public slots: void openMapScripts() const; @@ -159,6 +158,7 @@ public slots: void openProjectInTextEditor() const; void maskNonVisibleConnectionTiles(); void onBorderMetatilesChanged(); + void selectedEventIndexChanged(int index, Event::Group eventGroup); private: void setConnectionItemsVisible(bool); @@ -210,7 +210,7 @@ signals: void selectedObjectsChanged(); void loadMapRequested(QString, QString); void wildMonDataChanged(); - void warpEventDoubleClicked(QString, QString, QString); + void warpEventDoubleClicked(QString, int, Event::Group); void currentMetatilesSelectionChanged(); void mapRulerStatusChanged(const QString &); void editedMapData(); diff --git a/include/lib/orderedjson.h b/include/lib/orderedjson.h index 20463cee..17dafe10 100644 --- a/include/lib/orderedjson.h +++ b/include/lib/orderedjson.h @@ -104,8 +104,8 @@ public: Json(double value); // NUMBER Json(int value); // NUMBER Json(bool value); // BOOL - Json(const QString &value); // STRING - Json(QString &&value); // STRING + Json(const QString &value); // STRING + Json(QString &&value); // STRING Json(const char * value); // STRING Json(const array &values); // ARRAY Json(array &&values); // ARRAY diff --git a/include/mainwindow.h b/include/mainwindow.h index 89319d0e..9b2de654 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -26,6 +26,8 @@ #include "shortcutseditor.h" #include "preferenceeditor.h" + + namespace Ui { class MainWindow; } @@ -161,7 +163,7 @@ private slots: void on_action_Reload_Project_triggered(); void on_mapList_activated(const QModelIndex &index); void on_action_Save_Project_triggered(); - void openWarpMap(QString map_name, QString event_id, QString event_group); + void openWarpMap(QString map_name, int event_id, Event::Group event_group); void duplicate(); void setClipboardData(poryjson::Json::object); @@ -216,7 +218,7 @@ private slots: void on_toolButton_deleteObject_clicked(); - void addNewEvent(QString); + void addNewEvent(Event::Type type); void updateSelectedObjects(); void updateObjects(); @@ -265,8 +267,6 @@ private slots: void eventTabChanged(int index); - void selectedEventIndexChanged(int index); - void on_horizontalSlider_CollisionTransparency_valueChanged(int value); void on_toolButton_ExpandAll_clicked(); void on_toolButton_CollapseAll_clicked(); @@ -374,7 +374,7 @@ private: void setTheme(QString); bool openRecentProject(); void updateTilesetEditor(); - QString getEventGroupFromTabWidget(QWidget *tab); + Event::Group getEventGroupFromTabWidget(QWidget *tab); void closeSupplementaryWindows(); void setWindowDisabled(bool); diff --git a/include/project.h b/include/project.h index 0828284f..29486ba4 100644 --- a/include/project.h +++ b/include/project.h @@ -5,7 +5,6 @@ #include "map.h" #include "blockdata.h" #include "heallocation.h" -#include "event.h" #include "wildmoninfo.h" #include "parseutil.h" #include "orderedjson.h" @@ -83,6 +82,8 @@ public: QMap modifiedFileTimestamps; bool usingAsmTilesets; + const QPixmap entitiesPixmap = QPixmap(":/images/Entities_16x16.png"); + void set_root(QString); void initSignals(); @@ -194,7 +195,7 @@ public: bool readEventGraphics(); QMap> readObjEventGfxInfo(); - void setEventPixmap(Event * event, bool forceLoad = false); + void setEventPixmap(Event *event, bool forceLoad = false); QString fixPalettePath(QString path); QString fixGraphicPath(QString path); @@ -204,6 +205,7 @@ public: QString getMapScriptsFilePath(const QString &mapName) const; QStringList getEventScriptsFilePaths() const; QCompleter *getEventScriptLabelCompleter(QStringList additionalScriptLabels); + QStringList getGlobalScriptLabels(); void saveMapHealEvents(Map *map); diff --git a/include/ui/customattributestable.h b/include/ui/customattributestable.h index de353b7c..bf9334d0 100644 --- a/include/ui/customattributestable.h +++ b/include/ui/customattributestable.h @@ -1,7 +1,7 @@ #ifndef CUSTOMATTRIBUTESTABLE_H #define CUSTOMATTRIBUTESTABLE_H -#include "event.h" +#include "events.h" #include #include #include diff --git a/include/ui/draggablepixmapitem.h b/include/ui/draggablepixmapitem.h index a836ea23..9c318962 100644 --- a/include/ui/draggablepixmapitem.h +++ b/include/ui/draggablepixmapitem.h @@ -8,7 +8,7 @@ #include -#include "event.h" +#include "events.h" class Editor; @@ -17,10 +17,10 @@ class DraggablePixmapItem : public QObject, public QGraphicsPixmapItem { public: DraggablePixmapItem(QPixmap pixmap): QGraphicsPixmapItem(pixmap) {} - DraggablePixmapItem(Event *event_, Editor *editor_) : QGraphicsPixmapItem(event_->pixmap) { - event = event_; + DraggablePixmapItem(Event *event, Editor *editor) : QGraphicsPixmapItem(event->getPixmap()) { + this->event = event; event->setPixmapItem(this); - editor = editor_; + this->editor = editor; updatePosition(); } @@ -37,8 +37,6 @@ public: void moveTo(const QPoint &pos); void emitPositionChanged(); void updatePixmap(); - void bind(QComboBox *combo, QString key); - void bindToUserData(QComboBox *combo, QString key); signals: void positionChanged(Event *event); @@ -49,25 +47,18 @@ signals: void onPropertyChanged(QString key, QString value); public slots: - void set_x(const QString &text) { - event->put("x", text); + void set_x(int x) { + event->setX(x); updatePosition(); } - void set_y(const QString &text) { - event->put("y", text); + void set_y(int y) { + event->setY(y); updatePosition(); } - void set_elevation(const QString &text) { - event->put("elevation", text); + void set_elevation(int z) { + event->setElevation(z); updatePosition(); } - void set_sprite(const QString &text) { - event->put("sprite", text); - updatePixmap(); - } - void set_script(const QString &text) { - event->put("script_label", text); - } protected: void mousePressEvent(QGraphicsSceneMouseEvent*); diff --git a/include/ui/eventframes.h b/include/ui/eventframes.h new file mode 100644 index 00000000..872f07c8 --- /dev/null +++ b/include/ui/eventframes.h @@ -0,0 +1,272 @@ +#pragma once +#ifndef EVENTRAMES_H +#define EVENTRAMES_H + +#include + +#include "noscrollspinbox.h" +#include "noscrollcombobox.h" + +#include "events.h" + + + +class Project; + +class EventFrame : public QFrame { + Q_OBJECT + +public: + EventFrame(Event *event, QWidget *parent = nullptr) + : QFrame(parent), event(event) { } + + virtual void setup(); + void initCustomAttributesTable(); + virtual void connectSignals(); + virtual void initialize(); + virtual void populate(Project *project); + + virtual void setActive(bool active); + +public: + QLabel *label_id; + + QVBoxLayout *layout_main; + + QSpinBox *spinner_id; + + NoScrollSpinBox *spinner_x; + NoScrollSpinBox *spinner_y; + NoScrollSpinBox *spinner_z; + + QLabel *label_icon; + + QFrame *frame_contents; + QVBoxLayout *layout_contents; + +protected: + bool populated = false; + bool initialized = false; + +private: + Event *event; +}; + + + +class ObjectFrame : public EventFrame { + Q_OBJECT + +public: + ObjectFrame(ObjectEvent *object, QWidget *parent = nullptr) + : EventFrame(object, parent), object(object) {} + + virtual ~ObjectFrame() { + delete this->scriptCompleter; + } + + virtual void setup() override; + virtual void initialize() override; + virtual void connectSignals() override; + virtual void populate(Project *project) override; + +public: + NoScrollComboBox *combo_sprite; + NoScrollComboBox *combo_movement; + NoScrollSpinBox *spinner_radius_x; + NoScrollSpinBox *spinner_radius_y; + NoScrollComboBox *combo_script; + NoScrollComboBox *combo_flag; + NoScrollComboBox *combo_trainer_type; + NoScrollComboBox *combo_radius_treeid; + QCheckBox *check_in_connection; + +private: + ObjectEvent *object; + + QCompleter *scriptCompleter = nullptr; +}; + + + +class CloneObjectFrame : public EventFrame { + Q_OBJECT + +public: + CloneObjectFrame(CloneObjectEvent *clone, QWidget *parent = nullptr) + : EventFrame(clone, parent), clone(clone) {} + + virtual void setup() override; + virtual void initialize() override; + virtual void connectSignals() override; + virtual void populate(Project *project) override; + +public: + NoScrollComboBox *combo_sprite; + NoScrollSpinBox *spinner_target_id; + NoScrollComboBox *combo_target_map; + +private: + CloneObjectEvent *clone; +}; + + + +class WarpFrame : public EventFrame { + Q_OBJECT + +public: + WarpFrame(WarpEvent *warp, QWidget *parent = nullptr) + : EventFrame(warp, parent), warp(warp) {} + + virtual void setup() override; + virtual void initialize() override; + virtual void connectSignals() override; + virtual void populate(Project *project) override; + +public: + NoScrollComboBox *combo_dest_map; + NoScrollSpinBox *spinner_dest_warp; + +private: + WarpEvent *warp; +}; + + + +class TriggerFrame : public EventFrame { + Q_OBJECT + +public: + TriggerFrame(TriggerEvent *trigger, QWidget *parent = nullptr) + : EventFrame(trigger, parent), trigger(trigger) {} + + virtual void setup() override; + virtual void initialize() override; + virtual void connectSignals() override; + virtual void populate(Project *project) override; + +public: + NoScrollComboBox *combo_script; + NoScrollComboBox *combo_var; + NoScrollComboBox *combo_var_value; + +private: + TriggerEvent *trigger; + + QCompleter *scriptCompleter = nullptr; +}; + + + +class WeatherTriggerFrame : public EventFrame { + Q_OBJECT + +public: + WeatherTriggerFrame(WeatherTriggerEvent *weatherTrigger, QWidget *parent = nullptr) + : EventFrame(weatherTrigger, parent), weatherTrigger(weatherTrigger) {} + + virtual void setup() override; + virtual void initialize() override; + virtual void connectSignals() override; + virtual void populate(Project *project) override; + +public: + NoScrollComboBox *combo_weather; + +private: + WeatherTriggerEvent *weatherTrigger; +}; + + + +class SignFrame : public EventFrame { + Q_OBJECT + +public: + SignFrame(SignEvent *sign, QWidget *parent = nullptr) + : EventFrame(sign, parent), sign(sign) {} + + virtual void setup() override; + virtual void initialize() override; + virtual void connectSignals() override; + virtual void populate(Project *project) override; + +public: + NoScrollComboBox *combo_facing_dir; + NoScrollComboBox *combo_script; + +private: + SignEvent *sign; + + QCompleter *scriptCompleter = nullptr; +}; + + + +class HiddenItemFrame : public EventFrame { + Q_OBJECT + +public: + HiddenItemFrame(HiddenItemEvent *hiddenItem, QWidget *parent = nullptr) + : EventFrame(hiddenItem, parent), hiddenItem(hiddenItem) {} + + virtual void setup() override; + virtual void initialize() override; + virtual void connectSignals() override; + virtual void populate(Project *project) override; + +public: + NoScrollComboBox *combo_item; + NoScrollComboBox *combo_flag; + NoScrollSpinBox *spinner_quantity; + QCheckBox *check_itemfinder; + +private: + HiddenItemEvent *hiddenItem; +}; + + + +class SecretBaseFrame : public EventFrame { + Q_OBJECT + +public: + SecretBaseFrame(SecretBaseEvent *secretBase, QWidget *parent = nullptr) + : EventFrame(secretBase, parent), secretBase(secretBase) {} + + virtual void setup() override; + virtual void initialize() override; + virtual void connectSignals() override; + virtual void populate(Project *project) override; + +public: + NoScrollComboBox *combo_base_id; + +private: + SecretBaseEvent *secretBase; +}; + + + +class HealLocationFrame : public EventFrame { + Q_OBJECT + +public: + HealLocationFrame(HealLocationEvent *healLocation, QWidget *parent = nullptr) + : EventFrame(healLocation, parent), healLocation(healLocation) {} + + virtual void setup() override; + virtual void initialize() override; + virtual void connectSignals() override; + virtual void populate(Project *project) override; + +public: + NoScrollComboBox *combo_respawn_map; + NoScrollSpinBox *spinner_respawn_npc; + +private: + HealLocationEvent *healLocation; +}; + +#endif // EVENTRAMES_H diff --git a/include/ui/eventpropertiesframe.h b/include/ui/eventpropertiesframe.h deleted file mode 100644 index 7e526ab7..00000000 --- a/include/ui/eventpropertiesframe.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef EVENTPROPERTIESFRAME_H -#define EVENTPROPERTIESFRAME_H - -#include "event.h" - -#include - -namespace Ui { -class EventPropertiesFrame; -} - -class EventPropertiesFrame : public QFrame -{ - Q_OBJECT - -public: - explicit EventPropertiesFrame(Event *event, QWidget *parent = nullptr); - ~EventPropertiesFrame(); - void paintEvent(QPaintEvent*); - -public: - Ui::EventPropertiesFrame *ui; - -private: - Event *event; - bool firstShow = true; -}; - -#endif // EVENTPROPERTIESFRAME_H diff --git a/include/ui/neweventtoolbutton.h b/include/ui/neweventtoolbutton.h index fa2405df..721fe2f2 100644 --- a/include/ui/neweventtoolbutton.h +++ b/include/ui/neweventtoolbutton.h @@ -1,7 +1,7 @@ #ifndef NEWEVENTTOOLBUTTON_H #define NEWEVENTTOOLBUTTON_H -#include "event.h" +#include "events.h" #include class NewEventToolButton : public QToolButton @@ -9,7 +9,7 @@ class NewEventToolButton : public QToolButton Q_OBJECT public: explicit NewEventToolButton(QWidget *parent = nullptr); - QString getSelectedEventType(); + Event::Type getSelectedEventType(); QAction *newObjectAction; QAction *newCloneObjectAction; QAction *newWarpAction; @@ -30,9 +30,9 @@ public slots: void newHiddenItem(); void newSecretBase(); signals: - void newEventAdded(QString); + void newEventAdded(Event::Type); private: - QString selectedEventType; + Event::Type selectedEventType; void init(); }; diff --git a/porymap.pro b/porymap.pro index 97b017ce..b0e321a2 100644 --- a/porymap.pro +++ b/porymap.pro @@ -17,7 +17,7 @@ QMAKE_TARGET_BUNDLE_PREFIX = com.pret SOURCES += src/core/block.cpp \ src/core/blockdata.cpp \ - src/core/event.cpp \ + src/core/events.cpp \ src/core/heallocation.cpp \ src/core/imageexport.cpp \ src/core/map.cpp \ @@ -53,7 +53,7 @@ SOURCES += src/core/block.cpp \ src/ui/regionmapentriespixmapitem.cpp \ src/ui/cursortilerect.cpp \ src/ui/customattributestable.cpp \ - src/ui/eventpropertiesframe.cpp \ + src/ui/eventframes.cpp \ src/ui/filterchildrenproxymodel.cpp \ src/ui/graphicsview.cpp \ src/ui/imageproviders.cpp \ @@ -99,7 +99,7 @@ SOURCES += src/core/block.cpp \ HEADERS += include/core/block.h \ include/core/blockdata.h \ - include/core/event.h \ + include/core/events.h \ include/core/heallocation.h \ include/core/history.h \ include/core/imageexport.h \ @@ -136,7 +136,7 @@ HEADERS += include/core/block.h \ include/ui/regionmapentriespixmapitem.h \ include/ui/cursortilerect.h \ include/ui/customattributestable.h \ - include/ui/eventpropertiesframe.h \ + include/ui/eventframes.h \ include/ui/filterchildrenproxymodel.h \ include/ui/graphicsview.h \ include/ui/imageproviders.h \ @@ -185,7 +185,6 @@ HEADERS += include/core/block.h \ include/log.h FORMS += forms/mainwindow.ui \ - forms/eventpropertiesframe.ui \ forms/prefabcreationdialog.ui \ forms/prefabframe.ui \ forms/tileseteditor.ui \ @@ -209,5 +208,6 @@ INCLUDEPATH += include INCLUDEPATH += include/core INCLUDEPATH += include/ui INCLUDEPATH += include/lib +INCLUDEPATH += forms include(src/vendor/QtGifImage/gifimage/qtgifimage.pri) diff --git a/src/core/editcommands.cpp b/src/core/editcommands.cpp index 5b21d878..394c51cb 100644 --- a/src/core/editcommands.cpp +++ b/src/core/editcommands.cpp @@ -9,16 +9,16 @@ int getEventTypeMask(QList events) { int eventTypeMask = 0; for (auto event : events) { - QString groupType = event->get("event_group_type"); - if (groupType == EventGroup::Object) { + Event::Group groupType = event->getEventGroup(); + if (groupType == Event::Group::Object) { eventTypeMask |= IDMask_EventType_Object; - } else if (groupType == EventGroup::Warp) { + } else if (groupType == Event::Group::Warp) { eventTypeMask |= IDMask_EventType_Warp; - } else if (groupType == EventGroup::Coord) { + } else if (groupType == Event::Group::Coord) { eventTypeMask |= IDMask_EventType_Trigger; - } else if (groupType == EventGroup::Bg) { + } else if (groupType == Event::Group::Bg) { eventTypeMask |= IDMask_EventType_BG; - } else if (groupType == EventGroup::Heal) { + } else if (groupType == Event::Group::Heal) { eventTypeMask |= IDMask_EventType_Heal; } } @@ -261,13 +261,13 @@ void EventMove::redo() { QUndoCommand::redo(); for (Event *event : events) { - event->pixmapItem->move(deltaX, deltaY); + event->getPixmapItem()->move(deltaX, deltaY); } } void EventMove::undo() { for (Event *event : events) { - event->pixmapItem->move(-deltaX, -deltaY); + event->getPixmapItem()->move(-deltaX, -deltaY); } QUndoCommand::undo(); @@ -331,16 +331,16 @@ void EventCreate::redo() { // select this event editor->selected_events->clear(); - editor->selectMapEvent(event->pixmapItem, false); + editor->selectMapEvent(event->getPixmapItem(), false); } void EventCreate::undo() { map->removeEvent(event); - if (editor->scene->items().contains(event->pixmapItem)) { - editor->scene->removeItem(event->pixmapItem); + if (editor->scene->items().contains(event->getPixmapItem())) { + editor->scene->removeItem(event->getPixmapItem()); } - editor->selected_events->removeOne(event->pixmapItem); + editor->selected_events->removeOne(event->getPixmapItem()); editor->shouldReselectEvents(); @@ -377,15 +377,15 @@ void EventDelete::redo() { for (Event *event : selectedEvents) { map->removeEvent(event); - if (editor->scene->items().contains(event->pixmapItem)) { - editor->scene->removeItem(event->pixmapItem); + if (editor->scene->items().contains(event->getPixmapItem())) { + editor->scene->removeItem(event->getPixmapItem()); } - editor->selected_events->removeOne(event->pixmapItem); + editor->selected_events->removeOne(event->getPixmapItem()); } editor->selected_events->clear(); if (nextSelectedEvent) - editor->selected_events->append(nextSelectedEvent->pixmapItem); + editor->selected_events->append(nextSelectedEvent->getPixmapItem()); editor->shouldReselectEvents(); } @@ -399,7 +399,7 @@ void EventDelete::undo() { // select these events editor->selected_events->clear(); for (Event *event : selectedEvents) { - editor->selected_events->append(event->pixmapItem); + editor->selected_events->append(event->getPixmapItem()); } editor->shouldReselectEvents(); @@ -441,7 +441,7 @@ void EventDuplicate::redo() { // select these events editor->selected_events->clear(); for (Event *event : selectedEvents) { - editor->selected_events->append(event->pixmapItem); + editor->selected_events->append(event->getPixmapItem()); } editor->shouldReselectEvents(); } @@ -450,10 +450,10 @@ void EventDuplicate::undo() { for (Event *event : selectedEvents) { map->removeEvent(event); - if (editor->scene->items().contains(event->pixmapItem)) { - editor->scene->removeItem(event->pixmapItem); + if (editor->scene->items().contains(event->getPixmapItem())) { + editor->scene->removeItem(event->getPixmapItem()); } - editor->selected_events->removeOne(event->pixmapItem); + editor->selected_events->removeOne(event->getPixmapItem()); } editor->shouldReselectEvents(); @@ -471,7 +471,7 @@ int EventDuplicate::id() const { EventPaste::EventPaste(Editor *editor, Map *map, QList pastedEvents, - QUndoCommand *parent) : EventDuplicate(editor, map, pastedEvents) { + QUndoCommand *parent) : EventDuplicate(editor, map, pastedEvents, parent) { if (pastedEvents.size() > 1) { setText("Paste Events"); } else { diff --git a/src/core/event.cpp b/src/core/event.cpp deleted file mode 100644 index df247559..00000000 --- a/src/core/event.cpp +++ /dev/null @@ -1,480 +0,0 @@ -#include "event.h" -#include "map.h" -#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_healspot"; - -const QMap 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), - spriteHeight(16), - usingSprite(false) -{ } - -Event::Event(const Event& toCopy) : - values(toCopy.values), - customValues(toCopy.customValues), - pixmap(toCopy.pixmap), - spriteWidth(toCopy.spriteWidth), - spriteHeight(toCopy.spriteHeight), - frame(toCopy.frame), - hFlip(toCopy.hFlip), - usingSprite(toCopy.usingSprite) -{ } - -Event::Event(QJsonObject obj, QString type) : Event() -{ - this->put("event_type", type); - this->readCustomValues(obj); -} - -Event* Event::createNewEvent(QString event_type, QString map_name, Project *project) -{ - Event *event = nullptr; - 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) { - event = createNewHealLocationEvent(map_name); - } else if (event_type == EventType::Trigger) { - event = createNewTriggerEvent(project); - } else if (event_type == EventType::WeatherTrigger) { - event = createNewWeatherTriggerEvent(project); - } else if (event_type == EventType::Sign) { - event = createNewSignEvent(project); - } else if (event_type == EventType::HiddenItem) { - event = createNewHiddenItemEvent(project); - } else if (event_type == EventType::SecretBase) { - event = createNewSecretBaseEvent(project); - } else { - // should never be reached but just in case - 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; -} - -Event* Event::createNewObjectEvent(Project *project) -{ - Event *event = new Event; - event->put("sprite", project->gfxDefines.keys().first()); - event->put("movement_type", project->movementTypes.first()); - event->put("radius_x", 0); - event->put("radius_y", 0); - event->put("script_label", "NULL"); - event->put("event_flag", "0"); - event->put("replacement", "0"); - event->put("trainer_type", project->trainerTypes.value(0, "0")); - event->put("sight_radius_tree_id", 0); - event->put("elevation", 3); - 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("destination_warp", 0); - event->put("destination_map_name", map_name); - event->put("elevation", 0); - return event; -} - -Event* Event::createNewHealLocationEvent(QString map_name) -{ - Event *event = new Event; - 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); - if (projectConfig.getHealLocationRespawnDataEnabled()) { - event->put("respawn_map", map_name); - event->put("respawn_npc", 1); - } - return event; -} - -Event* Event::createNewTriggerEvent(Project *project) -{ - Event *event = new Event; - event->put("script_label", "NULL"); - event->put("script_var", project->varNames.first()); - event->put("script_var_value", "0"); - event->put("elevation", 0); - return event; -} - -Event* Event::createNewWeatherTriggerEvent(Project *project) -{ - Event *event = new Event; - event->put("weather", project->coordEventWeatherNames.first()); - event->put("elevation", 0); - return event; -} - -Event* Event::createNewSignEvent(Project *project) -{ - Event *event = new Event; - event->put("player_facing_direction", project->bgEventFacingDirections.first()); - event->put("script_label", "NULL"); - event->put("elevation", 0); - return event; -} - -Event* Event::createNewHiddenItemEvent(Project *project) -{ - Event *event = new Event; - event->put("item", project->itemNames.first()); - event->put("flag", project->flagNames.first()); - event->put("elevation", 3); - if (projectConfig.getHiddenItemQuantityEnabled()) { - event->put("quantity", 1); - } - if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) { - event->put("underfoot", false); - } - return event; -} - -Event* Event::createNewSecretBaseEvent(Project *project) -{ - Event *event = new Event; - event->put("secret_base_id", project->secretBaseIds.first()); - event->put("elevation", 0); - return event; -} - -int Event::getPixelX() -{ - return (this->x() * 16) - qMax(0, (this->spriteWidth - 16) / 2); -} - -int Event::getPixelY() -{ - return (this->y() * 16) - qMax(0, this->spriteHeight - 16); -} - -const QSet expectedObjectFields = { - "graphics_id", - "elevation", - "movement_type", - "movement_range_x", - "movement_range_y", - "trainer_type", - "trainer_sight_or_berry_tree_id", - "script", - "flag", -}; - -const QSet expectedCloneObjectFields = { - "type", - "graphics_id", - "target_local_id", - "target_map", -}; - -const QSet expectedWarpFields = { - "elevation", - "dest_map", - "dest_warp_id", -}; - -const QSet expectedTriggerFields = { - "type", - "elevation", - "var", - "var_value", - "script", -}; - -const QSet expectedWeatherTriggerFields = { - "type", - "elevation", - "weather", -}; - -const QSet expectedSignFields = { - "type", - "elevation", - "player_facing_dir", - "script", -}; - -const QSet expectedHiddenItemFields = { - "type", - "elevation", - "item", - "flag", -}; - -const QSet expectedSecretBaseFields = { - "type", - "elevation", - "secret_base_id", -}; - -QSet Event::getExpectedFields() -{ - QString type = this->get("event_type"); - QSet expectedFields = QSet(); - if (type == EventType::Object) { - expectedFields = expectedObjectFields; - 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) { - expectedFields = expectedTriggerFields; - } else if (type == EventType::WeatherTrigger) { - expectedFields = expectedWeatherTriggerFields; - } else if (type == EventType::Sign) { - expectedFields = expectedSignFields; - } else if (type == EventType::HiddenItem) { - expectedFields = expectedHiddenItemFields; - if (projectConfig.getHiddenItemQuantityEnabled()) { - expectedFields.insert("quantity"); - } - if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) { - expectedFields.insert("underfoot"); - } - } else if (type == EventType::SecretBase) { - expectedFields = expectedSecretBaseFields; - } - expectedFields << "x" << "y"; - return expectedFields; -}; - -void Event::readCustomValues(QJsonObject values) -{ - this->customValues.clear(); - QSet expectedFields = this->getExpectedFields(); - for (QString key : values.keys()) { - if (!expectedFields.contains(key)) { - this->customValues[key] = values[key].toString(); - } - } -} - -void Event::addCustomValuesTo(OrderedJson::object *obj) -{ - for (QString key : this->customValues.keys()) { - if (!obj->contains(key)) { - (*obj)[key] = this->customValues[key]; - } - } -} - -OrderedJson::object Event::buildObjectEventJSON() -{ - OrderedJson::object objectObj; - if (projectConfig.getEventCloneObjectEnabled()) { - objectObj["type"] = "object"; - } - 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 objectObj; -} - -OrderedJson::object Event::buildCloneObjectEventJSON(const QMap &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 &mapNamesToMapConstants) -{ - OrderedJson::object warpObj; - warpObj["x"] = this->getU16("x"); - warpObj["y"] = this->getU16("y"); - warpObj["elevation"] = this->getInt("elevation"); - warpObj["dest_map"] = mapNamesToMapConstants.value(this->get("destination_map_name")); - warpObj["dest_warp_id"] = this->getInt("destination_warp"); - this->addCustomValuesTo(&warpObj); - - return warpObj; -} - -OrderedJson::object Event::buildTriggerEventJSON() -{ - OrderedJson::object triggerObj; - triggerObj["type"] = "trigger"; - triggerObj["x"] = this->getU16("x"); - triggerObj["y"] = this->getU16("y"); - triggerObj["elevation"] = this->getInt("elevation"); - triggerObj["var"] = this->get("script_var"); - triggerObj["var_value"] = this->get("script_var_value"); - triggerObj["script"] = this->get("script_label"); - this->addCustomValuesTo(&triggerObj); - - return triggerObj; -} - -OrderedJson::object Event::buildWeatherTriggerEventJSON() -{ - OrderedJson::object weatherObj; - weatherObj["type"] = "weather"; - weatherObj["x"] = this->getU16("x"); - weatherObj["y"] = this->getU16("y"); - weatherObj["elevation"] = this->getInt("elevation"); - weatherObj["weather"] = this->get("weather"); - this->addCustomValuesTo(&weatherObj); - - return weatherObj; -} - -OrderedJson::object Event::buildSignEventJSON() -{ - OrderedJson::object signObj; - signObj["type"] = "sign"; - signObj["x"] = this->getU16("x"); - signObj["y"] = this->getU16("y"); - signObj["elevation"] = this->getInt("elevation"); - signObj["player_facing_dir"] = this->get("player_facing_direction"); - signObj["script"] = this->get("script_label"); - this->addCustomValuesTo(&signObj); - - return signObj; -} - -OrderedJson::object Event::buildHiddenItemEventJSON() -{ - OrderedJson::object hiddenItemObj; - hiddenItemObj["type"] = "hidden_item"; - hiddenItemObj["x"] = this->getU16("x"); - hiddenItemObj["y"] = this->getU16("y"); - hiddenItemObj["elevation"] = this->getInt("elevation"); - hiddenItemObj["item"] = this->get("item"); - hiddenItemObj["flag"] = this->get("flag"); - if (projectConfig.getHiddenItemQuantityEnabled()) { - hiddenItemObj["quantity"] = this->getInt("quantity"); - } - if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) { - hiddenItemObj["underfoot"] = this->getInt("underfoot") > 0 || this->get("underfoot") == "TRUE"; - } - this->addCustomValuesTo(&hiddenItemObj); - - return hiddenItemObj; -} - -OrderedJson::object Event::buildSecretBaseEventJSON() -{ - OrderedJson::object secretBaseObj; - secretBaseObj["type"] = "secret_base"; - secretBaseObj["x"] = this->getU16("x"); - secretBaseObj["y"] = this->getU16("y"); - secretBaseObj["elevation"] = this->getInt("elevation"); - secretBaseObj["secret_base_id"] = this->get("secret_base_id"); - this->addCustomValuesTo(&secretBaseObj); - - return secretBaseObj; -} - -void Event::setPixmapFromSpritesheet(QImage spritesheet, int spriteWidth, int spriteHeight, bool inanimate) -{ - int frame = inanimate ? 0 : this->frame; - QImage img = spritesheet.copy(frame * spriteWidth % spritesheet.width(), 0, spriteWidth, spriteHeight); - if (this->hFlip && !inanimate) { - img = img.transformed(QTransform().scale(-1, 1)); - } - // Set first palette color fully transparent. - img.setColor(0, qRgba(0, 0, 0, 0)); - pixmap = QPixmap::fromImage(img); - this->spriteWidth = spriteWidth; - this->spriteHeight = spriteHeight; - this->usingSprite = true; -} - -void Event::setFrameFromMovement(QString facingDir) { - // defaults - this->frame = 0; - this->hFlip = false; - if (facingDir == "DIR_NORTH") { - this->frame = 1; - this->hFlip = false; - } else if (facingDir == "DIR_SOUTH") { - this->frame = 0; - this->hFlip = false; - } else if (facingDir == "DIR_WEST") { - this->frame = 2; - this->hFlip = false; - } else if (facingDir == "DIR_EAST") { - this->frame = 2; - 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()); -} diff --git a/src/core/events.cpp b/src/core/events.cpp new file mode 100644 index 00000000..07617e50 --- /dev/null +++ b/src/core/events.cpp @@ -0,0 +1,875 @@ +#include "events.h" + +#include "eventframes.h" +#include "project.h" +#include "config.h" + + + +Event::~Event() { + if (this->eventFrame) + this->eventFrame->deleteLater(); +} + +EventFrame *Event::getEventFrame() { + if (!this->eventFrame) createEventFrame(); + return this->eventFrame; +} + +void Event::destroyEventFrame() { + if (eventFrame) delete eventFrame; + eventFrame = nullptr; +} + +int Event::getEventIndex() { + return this->map->events.value(this->getEventGroup()).indexOf(this); +} + +void Event::setDefaultValues(Project *) { + this->setX(0); + this->setY(0); + this->setElevation(3); +} + +void Event::readCustomValues(QJsonObject values) { + this->customValues.clear(); + QSet expectedFields = this->getExpectedFields(); + for (QString key : values.keys()) { + if (!expectedFields.contains(key)) { + this->customValues[key] = values[key].toString(); + } + } +} + +void Event::addCustomValuesTo(OrderedJson::object *obj) { + for (QString key : this->customValues.keys()) { + if (!obj->contains(key)) { + (*obj)[key] = this->customValues[key]; + } + } +} + +QString Event::eventTypeToString(Event::Type type) { + switch (type) { + case Event::Type::Object: + return "event_object"; + case Event::Type::CloneObject: + return "event_clone_object"; + case Event::Type::Warp: + return "event_warp"; + case Event::Type::Trigger: + return "event_trigger"; + case Event::Type::WeatherTrigger: + return "event_weather_trigger"; + case Event::Type::Sign: + return "event_sign"; + case Event::Type::HiddenItem: + return "event_hidden_item"; + case Event::Type::SecretBase: + return "event_secret_base"; + case Event::Type::HealLocation: + return "event_healspot"; + default: + return ""; + } +} + +Event::Type Event::eventTypeFromString(QString type) { + if (type == "event_object") { + return Event::Type::Object; + } else if (type == "event_clone_object") { + return Event::Type::CloneObject; + } else if (type == "event_warp") { + return Event::Type::Warp; + } else if (type == "event_trigger") { + return Event::Type::Trigger; + } else if (type == "event_weather_trigger") { + return Event::Type::WeatherTrigger; + } else if (type == "event_sign") { + return Event::Type::Sign; + } else if (type == "event_hidden_item") { + return Event::Type::HiddenItem; + } else if (type == "event_secret_base") { + return Event::Type::SecretBase; + } else if (type == "event_healspot") { + return Event::Type::HealLocation; + } else { + return Event::Type::None; + } +} + + + +Event *ObjectEvent::duplicate() { + ObjectEvent *copy = new ObjectEvent(); + + copy->setX(this->getX()); + copy->setY(this->getY()); + copy->setElevation(this->getElevation()); + copy->setGfx(this->getGfx()); + copy->setMovement(this->getMovement()); + copy->setRadiusX(this->getRadiusX()); + copy->setRadiusY(this->getRadiusY()); + copy->setTrainerType(this->getTrainerType()); + copy->setSightRadiusBerryTreeID(this->getSightRadiusBerryTreeID()); + copy->setScript(this->getScript()); + copy->setFlag(this->getFlag()); + copy->setCustomValues(this->getCustomValues()); + + return copy; +} + +EventFrame *ObjectEvent::createEventFrame() { + if (!this->eventFrame) { + this->eventFrame = new ObjectFrame(this); + this->eventFrame->setup(); + + QObject::connect(this->eventFrame, &QObject::destroyed, [this](){ this->eventFrame = nullptr; }); + } + return this->eventFrame; +} + +OrderedJson::object ObjectEvent::buildEventJson(Project *) { + OrderedJson::object objectJson; + + if (projectConfig.getEventCloneObjectEnabled()) { + objectJson["type"] = "object"; + } + objectJson["graphics_id"] = this->getGfx(); + objectJson["x"] = this->getX(); + objectJson["y"] = this->getY(); + objectJson["elevation"] = this->getElevation(); + objectJson["movement_type"] = this->getMovement(); + objectJson["movement_range_x"] = this->getRadiusX(); + objectJson["movement_range_y"] = this->getRadiusY(); + objectJson["trainer_type"] = this->getTrainerType(); + objectJson["trainer_sight_or_berry_tree_id"] = this->getSightRadiusBerryTreeID(); + objectJson["script"] = this->getScript(); + objectJson["flag"] = this->getFlag(); + this->addCustomValuesTo(&objectJson); + + return objectJson; +} + +bool ObjectEvent::loadFromJson(QJsonObject json, Project *) { + this->setX(json["x"].toInt()); + this->setY(json["y"].toInt()); + this->setElevation(json["elevation"].toInt()); + this->setGfx(json["graphics_id"].toString()); + this->setMovement(json["movement_type"].toString()); + this->setRadiusX(json["movement_range_x"].toInt()); + this->setRadiusY(json["movement_range_y"].toInt()); + this->setTrainerType(json["trainer_type"].toString()); + this->setSightRadiusBerryTreeID(json["trainer_sight_or_berry_tree_id"].toString()); + this->setScript(json["script"].toString()); + this->setFlag(json["flag"].toString()); + + this->readCustomValues(json); + + return true; +} + +void ObjectEvent::setDefaultValues(Project *project) { + this->setGfx(project->gfxDefines.keys().first()); + this->setMovement(project->movementTypes.first()); + this->setScript("NULL"); + this->setTrainerType(project->trainerTypes.value(0, "0")); + + this->setRadiusX(0); + this->setRadiusY(0); + + this->setFrameFromMovement(project->facingDirections.value(this->getMovement())); +} + +const QSet expectedObjectFields = { + "graphics_id", + "elevation", + "movement_type", + "movement_range_x", + "movement_range_y", + "trainer_type", + "trainer_sight_or_berry_tree_id", + "script", + "flag", +}; + +QSet ObjectEvent::getExpectedFields() { + QSet expectedFields = QSet(); + expectedFields = expectedObjectFields; + if (projectConfig.getEventCloneObjectEnabled()) { + expectedFields.insert("type"); + } + expectedFields << "x" << "y"; + return expectedFields; +} + +void ObjectEvent::loadPixmap(Project *project) { + EventGraphics *eventGfx = project->eventGraphicsMap.value(gfx, nullptr); + if (!eventGfx || eventGfx->spritesheet.isNull()) { + // No sprite associated with this gfx constant. + // Use default sprite instead. + this->pixmap = project->entitiesPixmap.copy(0, 0, 16, 16); + } else { + this->setFrameFromMovement(project->facingDirections.value(this->movement)); + this->setPixmapFromSpritesheet(eventGfx->spritesheet, eventGfx->spriteWidth, eventGfx->spriteHeight, eventGfx->inanimate); + } +} + +void ObjectEvent::setPixmapFromSpritesheet(QImage spritesheet, int spriteWidth, int spriteHeight, bool inanimate) +{ + int frame = inanimate ? 0 : this->frame; + QImage img = spritesheet.copy(frame * spriteWidth % spritesheet.width(), 0, spriteWidth, spriteHeight); + if (this->hFlip && !inanimate) { + img = img.transformed(QTransform().scale(-1, 1)); + } + // Set first palette color fully transparent. + img.setColor(0, qRgba(0, 0, 0, 0)); + pixmap = QPixmap::fromImage(img); + this->spriteWidth = spriteWidth; + this->spriteHeight = spriteHeight; + this->usingSprite = true; +} + +void ObjectEvent::setFrameFromMovement(QString facingDir) { + // defaults + // TODO: read this from a file somewhere? + this->frame = 0; + this->hFlip = false; + if (facingDir == "DIR_NORTH") { + this->frame = 1; + this->hFlip = false; + } else if (facingDir == "DIR_SOUTH") { + this->frame = 0; + this->hFlip = false; + } else if (facingDir == "DIR_WEST") { + this->frame = 2; + this->hFlip = false; + } else if (facingDir == "DIR_EAST") { + this->frame = 2; + this->hFlip = true; + } +} + + + +Event *CloneObjectEvent::duplicate() { + CloneObjectEvent *copy = new CloneObjectEvent(); + + copy->setX(this->getX()); + copy->setY(this->getY()); + copy->setElevation(this->getElevation()); + copy->setGfx(this->getGfx()); + copy->setTargetID(this->getTargetID()); + copy->setTargetMap(this->getTargetMap()); + copy->setCustomValues(this->getCustomValues()); + + return copy; +} + +EventFrame *CloneObjectEvent::createEventFrame() { + if (!this->eventFrame) { + this->eventFrame = new CloneObjectFrame(this); + this->eventFrame->setup(); + + QObject::connect(this->eventFrame, &QObject::destroyed, [this](){ this->eventFrame = nullptr; }); + } + return this->eventFrame; +} + +OrderedJson::object CloneObjectEvent::buildEventJson(Project *project) { + OrderedJson::object cloneJson; + + cloneJson["type"] = "clone"; + cloneJson["graphics_id"] = this->getGfx(); + cloneJson["x"] = this->getX(); + cloneJson["y"] = this->getY(); + cloneJson["target_local_id"] = this->getTargetID(); + cloneJson["target_map"] = project->mapNamesToMapConstants.value(this->getTargetMap()); + this->addCustomValuesTo(&cloneJson); + + return cloneJson; +} + +bool CloneObjectEvent::loadFromJson(QJsonObject json, Project *project) { + this->setX(json["x"].toInt()); + this->setY(json["y"].toInt()); + this->setGfx(json["graphics_id"].toString()); + this->setTargetID(json["target_local_id"].toInt()); + + // Ensure the target map constant is valid before adding it to the events. + QString mapConstant = json["target_map"].toString(); + if (project->mapConstantsToMapNames.contains(mapConstant)) { + this->setTargetMap(project->mapConstantsToMapNames.value(mapConstant)); + } else if (mapConstant == NONE_MAP_CONSTANT) { + this->setTargetMap(NONE_MAP_NAME); + } else { + logError(QString("Destination map constant '%1' is invalid").arg(mapConstant)); + return false; + } + + this->readCustomValues(json); + + return true; +} + +void CloneObjectEvent::setDefaultValues(Project *project) { + this->setGfx(project->gfxDefines.keys().first()); + this->setTargetID(1); + if (this->getMap()) this->setTargetMap(this->getMap()->name); +} + +const QSet expectedCloneObjectFields = { + "type", + "graphics_id", + "target_local_id", + "target_map", +}; + +QSet CloneObjectEvent::getExpectedFields() { + QSet expectedFields = QSet(); + expectedFields = expectedCloneObjectFields; + expectedFields << "x" << "y"; + return expectedFields; +} + +void CloneObjectEvent::loadPixmap(Project *project) { + // Try to get the targeted object to clone + int eventIndex = this->targetID - 1; + Map *clonedMap = project->getMap(this->targetMap); + Event *clonedEvent = clonedMap ? clonedMap->events[Event::Group::Object].value(eventIndex, nullptr) : nullptr; + + if (clonedEvent && clonedEvent->getEventType() == Event::Type::Object) { + // Get graphics data from cloned object + ObjectEvent *clonedObject = dynamic_cast(clonedEvent); + this->gfx = clonedObject->getGfx(); + this->movement = clonedObject->getMovement(); + } else { + // Invalid object specified, use default graphics data (as would be shown in-game) + this->gfx = project->gfxDefines.key(0); + this->movement = project->movementTypes.first(); + } + + EventGraphics *eventGfx = project->eventGraphicsMap.value(gfx, nullptr); + if (!eventGfx || eventGfx->spritesheet.isNull()) { + // No sprite associated with this gfx constant. + // Use default sprite instead. + this->pixmap = project->entitiesPixmap.copy(0, 0, 16, 16); + } else { + this->setFrameFromMovement(project->facingDirections.value(this->movement)); + this->setPixmapFromSpritesheet(eventGfx->spritesheet, eventGfx->spriteWidth, eventGfx->spriteHeight, eventGfx->inanimate); + } +} + + + +Event *WarpEvent::duplicate() { + WarpEvent *copy = new WarpEvent(); + + copy->setX(this->getX()); + copy->setY(this->getY()); + copy->setElevation(this->getElevation()); + copy->setDestinationMap(this->getDestinationMap()); + copy->setDestinationWarpID(this->getDestinationWarpID()); + + copy->setCustomValues(this->getCustomValues()); + + return copy; +} + +EventFrame *WarpEvent::createEventFrame() { + if (!this->eventFrame) { + this->eventFrame = new WarpFrame(this); + this->eventFrame->setup(); + + QObject::connect(this->eventFrame, &QObject::destroyed, [this](){ this->eventFrame = nullptr; }); + } + return this->eventFrame; +} + +OrderedJson::object WarpEvent::buildEventJson(Project *project) { + OrderedJson::object warpJson; + + warpJson["x"] = this->getX(); + warpJson["y"] = this->getY(); + warpJson["elevation"] = this->getElevation(); + warpJson["dest_map"] = project->mapNamesToMapConstants.value(this->getDestinationMap()); + warpJson["dest_warp_id"] = this->getDestinationWarpID(); + + this->addCustomValuesTo(&warpJson); + + return warpJson; +} + +bool WarpEvent::loadFromJson(QJsonObject json, Project *project) { + this->setX(json["x"].toInt()); + this->setY(json["y"].toInt()); + this->setElevation(json["elevation"].toInt()); + this->setDestinationWarpID(json["dest_warp_id"].toInt()); + + // Ensure the warp destination map constant is valid before adding it to the warps. + QString mapConstant = json["dest_map"].toString(); + if (project->mapConstantsToMapNames.contains(mapConstant)) { + this->setDestinationMap(project->mapConstantsToMapNames.value(mapConstant)); + } else if (mapConstant == NONE_MAP_CONSTANT) { + this->setDestinationMap(NONE_MAP_NAME); + } else { + logError(QString("Destination map constant '%1' is invalid for warp").arg(mapConstant)); + return false; + } + + this->readCustomValues(json); + + return true; +} + +void WarpEvent::setDefaultValues(Project *) { + if (this->getMap()) this->setDestinationMap(this->getMap()->name); + this->setDestinationWarpID(0); + this->setElevation(0); +} + +const QSet expectedWarpFields = { + "elevation", + "dest_map", + "dest_warp_id", +}; + +QSet WarpEvent::getExpectedFields() { + QSet expectedFields = QSet(); + expectedFields = expectedWarpFields; + expectedFields << "x" << "y"; + return expectedFields; +} + +void WarpEvent::loadPixmap(Project *project) { + this->pixmap = project->entitiesPixmap.copy(16, 0, 16, 16); +} + + + +void CoordEvent::loadPixmap(Project *project) { + this->pixmap = project->entitiesPixmap.copy(32, 0, 16, 16); +} + + + +Event *TriggerEvent::duplicate() { + TriggerEvent *copy = new TriggerEvent(); + + copy->setX(this->getX()); + copy->setY(this->getY()); + copy->setElevation(this->getElevation()); + copy->setScriptVar(this->getScriptVar()); + copy->setScriptVarValue(this->getScriptVarValue()); + copy->setScriptLabel(this->getScriptLabel()); + + copy->setCustomValues(this->getCustomValues()); + + return copy; +} + +EventFrame *TriggerEvent::createEventFrame() { + if (!this->eventFrame) { + this->eventFrame = new TriggerFrame(this); + this->eventFrame->setup(); + + QObject::connect(this->eventFrame, &QObject::destroyed, [this](){ this->eventFrame = nullptr; }); + } + return this->eventFrame; +} + +OrderedJson::object TriggerEvent::buildEventJson(Project *) { + OrderedJson::object triggerJson; + + triggerJson["type"] = "trigger"; + triggerJson["x"] = this->getX(); + triggerJson["y"] = this->getY(); + triggerJson["elevation"] = this->getElevation(); + triggerJson["var"] = this->getScriptVar(); + triggerJson["var_value"] = this->getScriptVarValue(); + triggerJson["script"] = this->getScriptLabel(); + + this->addCustomValuesTo(&triggerJson); + + return triggerJson; +} + +bool TriggerEvent::loadFromJson(QJsonObject json, Project *) { + this->setX(json["x"].toInt()); + this->setY(json["y"].toInt()); + this->setElevation(json["elevation"].toInt()); + this->setScriptVar(json["var"].toString()); + this->setScriptVarValue(json["var_value"].toString()); + this->setScriptLabel(json["script"].toString()); + + this->readCustomValues(json); + + return true; +} + +void TriggerEvent::setDefaultValues(Project *project) { + this->setScriptLabel("NULL"); + this->setScriptVar(project->varNames.first()); + this->setScriptVarValue("0"); + this->setElevation(0); +} + +const QSet expectedTriggerFields = { + "type", + "elevation", + "var", + "var_value", + "script", +}; + +QSet TriggerEvent::getExpectedFields() { + QSet expectedFields = QSet(); + expectedFields = expectedTriggerFields; + expectedFields << "x" << "y"; + return expectedFields; +} + + + +Event *WeatherTriggerEvent::duplicate() { + WeatherTriggerEvent *copy = new WeatherTriggerEvent(); + + copy->setX(this->getX()); + copy->setY(this->getY()); + copy->setElevation(this->getElevation()); + copy->setWeather(this->getWeather()); + + copy->setCustomValues(this->getCustomValues()); + + return copy; +} + +EventFrame *WeatherTriggerEvent::createEventFrame() { + if (!this->eventFrame) { + this->eventFrame = new WeatherTriggerFrame(this); + this->eventFrame->setup(); + + QObject::connect(this->eventFrame, &QObject::destroyed, [this](){ this->eventFrame = nullptr; }); + } + return this->eventFrame; +} + +OrderedJson::object WeatherTriggerEvent::buildEventJson(Project *) { + OrderedJson::object weatherJson; + + weatherJson["type"] = "weather"; + weatherJson["x"] = this->getX(); + weatherJson["y"] = this->getY(); + weatherJson["elevation"] = this->getElevation(); + weatherJson["weather"] = this->getWeather(); + + this->addCustomValuesTo(&weatherJson); + + return weatherJson; +} + +bool WeatherTriggerEvent::loadFromJson(QJsonObject json, Project *) { + this->setX(json["x"].toInt()); + this->setY(json["y"].toInt()); + this->setElevation(json["elevation"].toInt()); + this->setWeather(json["weather"].toString()); + + this->readCustomValues(json); + + return true; +} + +void WeatherTriggerEvent::setDefaultValues(Project *project) { + this->setWeather(project->coordEventWeatherNames.first()); + this->setElevation(0); +} + +const QSet expectedWeatherTriggerFields = { + "type", + "elevation", + "weather", +}; + +QSet WeatherTriggerEvent::getExpectedFields() { + QSet expectedFields = QSet(); + expectedFields = expectedWeatherTriggerFields; + expectedFields << "x" << "y"; + return expectedFields; +} + + + +void BGEvent::loadPixmap(Project *project) { + this->pixmap = project->entitiesPixmap.copy(48, 0, 16, 16); +} + + + +Event *SignEvent::duplicate() { + SignEvent *copy = new SignEvent(); + + copy->setX(this->getX()); + copy->setY(this->getY()); + copy->setElevation(this->getElevation()); + copy->setFacingDirection(this->getFacingDirection()); + copy->setScriptLabel(this->getScriptLabel()); + + copy->setCustomValues(this->getCustomValues()); + + return copy; +} + +EventFrame *SignEvent::createEventFrame() { + if (!this->eventFrame) { + this->eventFrame = new SignFrame(this); + this->eventFrame->setup(); + + QObject::connect(this->eventFrame, &QObject::destroyed, [this](){ this->eventFrame = nullptr; }); + } + return this->eventFrame; +} + +OrderedJson::object SignEvent::buildEventJson(Project *) { + OrderedJson::object signJson; + + signJson["type"] = "sign"; + signJson["x"] = this->getX(); + signJson["y"] = this->getY(); + signJson["elevation"] = this->getElevation(); + signJson["player_facing_dir"] = this->getFacingDirection(); + signJson["script"] = this->getScriptLabel(); + + this->addCustomValuesTo(&signJson); + + return signJson; +} + +bool SignEvent::loadFromJson(QJsonObject json, Project *) { + this->setX(json["x"].toInt()); + this->setY(json["y"].toInt()); + this->setElevation(json["elevation"].toInt()); + this->setFacingDirection(json["player_facing_dir"].toString()); + this->setScriptLabel(json["script"].toString()); + + this->readCustomValues(json); + + return true; +} + +void SignEvent::setDefaultValues(Project *project) { + this->setFacingDirection(project->bgEventFacingDirections.first()); + this->setScriptLabel("NULL"); + this->setElevation(0); +} + +const QSet expectedSignFields = { + "type", + "elevation", + "player_facing_dir", + "script", +}; + +QSet SignEvent::getExpectedFields() { + QSet expectedFields = QSet(); + expectedFields = expectedSignFields; + expectedFields << "x" << "y"; + return expectedFields; +} + + + +Event *HiddenItemEvent::duplicate() { + HiddenItemEvent *copy = new HiddenItemEvent(); + + copy->setX(this->getX()); + copy->setY(this->getY()); + copy->setElevation(this->getElevation()); + copy->setItem(this->getItem()); + copy->setFlag(this->getFlag()); + copy->setQuantity(this->getQuantity()); + copy->setQuantity(this->getQuantity()); + + copy->setCustomValues(this->getCustomValues()); + + return copy; +} + +EventFrame *HiddenItemEvent::createEventFrame() { + if (!this->eventFrame) { + this->eventFrame = new HiddenItemFrame(this); + this->eventFrame->setup(); + + QObject::connect(this->eventFrame, &QObject::destroyed, [this](){ this->eventFrame = nullptr; }); + } + return this->eventFrame; +} + +OrderedJson::object HiddenItemEvent::buildEventJson(Project *) { + OrderedJson::object hiddenItemJson; + + hiddenItemJson["type"] = "hidden_item"; + hiddenItemJson["x"] = this->getX(); + hiddenItemJson["y"] = this->getY(); + hiddenItemJson["elevation"] = this->getElevation(); + hiddenItemJson["item"] = this->getItem(); + hiddenItemJson["flag"] = this->getFlag(); + if (projectConfig.getHiddenItemQuantityEnabled()) { + hiddenItemJson["quantity"] = this->getQuantity(); + } + if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) { + hiddenItemJson["underfoot"] = this->getUnderfoot(); + } + + this->addCustomValuesTo(&hiddenItemJson); + + return hiddenItemJson; +} + +bool HiddenItemEvent::loadFromJson(QJsonObject json, Project *) { + this->setX(json["x"].toInt()); + this->setY(json["y"].toInt()); + this->setElevation(json["elevation"].toInt()); + this->setItem(json["item"].toString()); + this->setFlag(json["flag"].toString()); + if (projectConfig.getHiddenItemQuantityEnabled()) { + this->setQuantity(json["quantity"].toInt()); + } + if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) { + this->setUnderfoot(json["underfoot"].toBool()); + } + + this->readCustomValues(json); + + return true; +} + +void HiddenItemEvent::setDefaultValues(Project *project) { + this->setItem(project->itemNames.first()); + this->setFlag(project->flagNames.first()); + if (projectConfig.getHiddenItemQuantityEnabled()) { + this->setQuantity(1); + } + if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) { + this->setUnderfoot(false); + } +} + +const QSet expectedHiddenItemFields = { + "type", + "elevation", + "item", + "flag", +}; + +QSet HiddenItemEvent::getExpectedFields() { + QSet expectedFields = QSet(); + expectedFields = expectedHiddenItemFields; + if (projectConfig.getHiddenItemQuantityEnabled()) { + expectedFields << "quantity"; + } + if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) { + expectedFields << "underfoot"; + } + expectedFields << "x" << "y"; + return expectedFields; +} + + + +Event *SecretBaseEvent::duplicate() { + SecretBaseEvent *copy = new SecretBaseEvent(); + + copy->setX(this->getX()); + copy->setY(this->getY()); + copy->setElevation(this->getElevation()); + copy->setBaseID(this->getBaseID()); + + copy->setCustomValues(this->getCustomValues()); + + return copy; +} + +EventFrame *SecretBaseEvent::createEventFrame() { + if (!this->eventFrame) { + this->eventFrame = new SecretBaseFrame(this); + this->eventFrame->setup(); + + QObject::connect(this->eventFrame, &QObject::destroyed, [this](){ this->eventFrame = nullptr; }); + } + return this->eventFrame; +} + +OrderedJson::object SecretBaseEvent::buildEventJson(Project *) { + OrderedJson::object secretBaseJson; + + secretBaseJson["type"] = "secret_base"; + secretBaseJson["x"] = this->getX(); + secretBaseJson["y"] = this->getY(); + secretBaseJson["elevation"] = this->getElevation(); + secretBaseJson["secret_base_id"] = this->getBaseID(); + + this->addCustomValuesTo(&secretBaseJson); + + return secretBaseJson; +} + +bool SecretBaseEvent::loadFromJson(QJsonObject json, Project *) { + this->setX(json["x"].toInt()); + this->setY(json["y"].toInt()); + this->setElevation(json["elevation"].toInt()); + this->setBaseID(json["secret_base_id"].toString()); + + this->readCustomValues(json); + + return true; +} + +void SecretBaseEvent::setDefaultValues(Project *project) { + this->setBaseID(project->secretBaseIds.first()); + this->setElevation(0); +} + +const QSet expectedSecretBaseFields = { + "type", + "elevation", + "secret_base_id", +}; + +QSet SecretBaseEvent::getExpectedFields() { + QSet expectedFields = QSet(); + expectedFields = expectedSecretBaseFields; + expectedFields << "x" << "y"; + return expectedFields; +} + + + +EventFrame *HealLocationEvent::createEventFrame() { + if (!this->eventFrame) { + this->eventFrame = new HealLocationFrame(this); + this->eventFrame->setup(); + + QObject::connect(this->eventFrame, &QObject::destroyed, [this](){ this->eventFrame = nullptr; }); + } + return this->eventFrame; +} + +OrderedJson::object HealLocationEvent::buildEventJson(Project *) { + return OrderedJson::object(); +} + +void HealLocationEvent::setDefaultValues(Project *) { + if (this->getMap()) { + this->setLocationName(Map::mapConstantFromName(this->getMap()->name).remove(0,4)); + this->setIdName(this->getMap()->name.replace(QRegularExpression("([a-z])([A-Z])"), "\\1_\\2").toUpper()); + } + this->setElevation(3); + if (projectConfig.getHealLocationRespawnDataEnabled()) { + if (this->getMap()) this->setRespawnMap(this->getMap()->name); + this->setRespawnNPC(1); + } +} + +void HealLocationEvent::loadPixmap(Project *project) { + this->pixmap = project->entitiesPixmap.copy(64, 0, 16, 16); +} diff --git a/src/core/heallocation.cpp b/src/core/heallocation.cpp index 8ecb70a8..7dc59a19 100644 --- a/src/core/heallocation.cpp +++ b/src/core/heallocation.cpp @@ -1,9 +1,11 @@ #include "heallocation.h" #include "config.h" +#include "events.h" #include "map.h" -HealLocation::HealLocation(QString id, QString map, int i, uint16_t x, uint16_t y, QString respawnMap, uint16_t respawnNPC) -{ +HealLocation::HealLocation(QString id, QString map, + int i, uint16_t x, uint16_t y, + QString respawnMap, uint16_t respawnNPC) { this->idName = id; this->mapName = map; this->index = i; @@ -13,28 +15,23 @@ HealLocation::HealLocation(QString id, QString map, int i, uint16_t x, uint16_t this->respawnNPC = respawnNPC; } -HealLocation HealLocation::fromEvent(Event *event) -{ - HealLocation hl; - hl.idName = event->get("id_name"); - hl.mapName = event->get("loc_name"); - try { - hl.index = event->get("index").toInt(); - } - catch(...) { - hl.index = 0; - } - hl.x = event->getU16("x"); - hl.y = event->getU16("y"); +HealLocation HealLocation::fromEvent(Event *fromEvent) { + HealLocationEvent *event = dynamic_cast(fromEvent); + + HealLocation healLocation; + healLocation.idName = event->getIdName(); + healLocation.mapName = event->getLocationName(); + healLocation.index = event->getIndex(); + healLocation.x = event->getX(); + healLocation.y = event->getY(); if (projectConfig.getHealLocationRespawnDataEnabled()) { - hl.respawnNPC = event->getU16("respawn_npc"); - hl.respawnMap = Map::mapConstantFromName(event->get("respawn_map")).remove(0,4); + healLocation.respawnNPC = event->getRespawnNPC(); + healLocation.respawnMap = Map::mapConstantFromName(event->getRespawnMap()).remove(0,4); } - return hl; + return healLocation; } -QDebug operator<<(QDebug debug, const HealLocation &hl) -{ - debug << "HealLocation_" + hl.mapName << "(" << hl.x << ',' << hl.y << ")"; +QDebug operator<<(QDebug debug, const HealLocation &healLocation) { + debug << "HealLocation_" + healLocation.mapName << "(" << healLocation.x << ',' << healLocation.y << ")"; return debug; } diff --git a/src/core/map.cpp b/src/core/map.cpp index 9bbe68c4..65facef3 100644 --- a/src/core/map.cpp +++ b/src/core/map.cpp @@ -474,34 +474,40 @@ QList Map::getAllEvents() const { return all_events; } -QStringList Map::eventScriptLabels(const QString &event_group_type) const { +QStringList Map::eventScriptLabels(Event::Group group) const { QStringList scriptLabels; - if (event_group_type.isEmpty()) { - for (const auto *event : getAllEvents()) - scriptLabels << event->get("script_label"); + + if (group == Event::Group::None) { + ScriptTracker scriptTracker; + for (Event *event : this->getAllEvents()) { + event->accept(&scriptTracker); + } + scriptLabels = scriptTracker.getScripts(); } else { - for (const auto *event : events.value(event_group_type)) - scriptLabels << event->get("script_label"); + ScriptTracker scriptTracker; + for (Event *event : events.value(group)) { + event->accept(&scriptTracker); + } + scriptLabels = scriptTracker.getScripts(); } scriptLabels.removeAll(""); scriptLabels.removeDuplicates(); - if (scriptLabels.contains("0x0")) - scriptLabels.move(scriptLabels.indexOf("0x0"), scriptLabels.count() - 1); - if (scriptLabels.contains("NULL")) - scriptLabels.move(scriptLabels.indexOf("NULL"), scriptLabels.count() - 1); + scriptLabels.prepend("0x0"); + scriptLabels.prepend("NULL"); return scriptLabels; } void Map::removeEvent(Event *event) { - for (QString key : events.keys()) { + for (Event::Group key : events.keys()) { events[key].removeAll(event); } } void Map::addEvent(Event *event) { - events[event->get("event_group_type")].append(event); + event->setMap(this); + events[event->getEventGroup()].append(event); if (!ownedEvents.contains(event)) ownedEvents.append(event); } diff --git a/src/core/parseutil.cpp b/src/core/parseutil.cpp index 63fbd84d..9c2be360 100644 --- a/src/core/parseutil.cpp +++ b/src/core/parseutil.cpp @@ -15,6 +15,8 @@ const QRegularExpression ParseUtil::re_poryScriptLabel("\\b(script)(\\((global|l const QRegularExpression ParseUtil::re_globalPoryScriptLabel("\\b(script)(\\((global)\\))?\\s*\\b(?