Add warning for warp behaviors

This commit is contained in:
GriffinR 2023-11-07 12:35:31 -05:00
parent 60fb1a246e
commit 5d4d88d11e
11 changed files with 163 additions and 46 deletions

View file

@ -345,6 +345,8 @@ public:
void setDestinationWarpID(QString newDestinationWarpID) { this->destinationWarpID = newDestinationWarpID; } void setDestinationWarpID(QString newDestinationWarpID) { this->destinationWarpID = newDestinationWarpID; }
QString getDestinationWarpID() { return this->destinationWarpID; } QString getDestinationWarpID() { return this->destinationWarpID; }
void setWarningEnabled(bool enabled);
private: private:
QString destinationMap; QString destinationMap;
QString destinationWarpID; QString destinationWarpID;

View file

@ -103,7 +103,8 @@ public:
QList<DraggablePixmapItem *> getObjects(); QList<DraggablePixmapItem *> getObjects();
void updateCursorRectPos(int x, int y); void updateCursorRectPos(int x, int y);
void setCursorRectVisible(bool visible); void setCursorRectVisible(bool visible);
void updateWarpEventWarning(Event *event);
void updateWarpEventWarnings();
bool eventLimitReached(Map *, Event::Type); bool eventLimitReached(Map *, Event::Type);
QGraphicsScene *scene = nullptr; QGraphicsScene *scene = nullptr;
@ -189,6 +190,7 @@ private:
static bool startDetachedProcess(const QString &command, static bool startDetachedProcess(const QString &command,
const QString &workingDirectory = QString(), const QString &workingDirectory = QString(),
qint64 *pid = nullptr); qint64 *pid = nullptr);
void constructBehaviorValueList(); // TODO: Remove
private slots: private slots:
void onMapStartPaint(QGraphicsSceneMouseEvent *event, MapPixmapItem *item); void onMapStartPaint(QGraphicsSceneMouseEvent *event, MapPixmapItem *item);

View file

@ -159,6 +159,7 @@ public:
public slots: public slots:
void on_mainTabBar_tabBarClicked(int index); void on_mainTabBar_tabBarClicked(int index);
void on_mapViewTab_tabBarClicked(int index); void on_mapViewTab_tabBarClicked(int index);
void openProjectSettingsEditor(int tab);
private slots: private slots:
void on_action_Open_Project_triggered(); void on_action_Open_Project_triggered();

View file

@ -6,6 +6,7 @@
#include "noscrollspinbox.h" #include "noscrollspinbox.h"
#include "noscrollcombobox.h" #include "noscrollcombobox.h"
#include "mainwindow.h"
#include "events.h" #include "events.h"
@ -22,7 +23,7 @@ public:
virtual void setup(); virtual void setup();
void initCustomAttributesTable(); void initCustomAttributesTable();
virtual void connectSignals(); virtual void connectSignals(MainWindow *);
virtual void initialize(); virtual void initialize();
virtual void populate(Project *project); virtual void populate(Project *project);
@ -69,7 +70,7 @@ public:
virtual void setup() override; virtual void setup() override;
virtual void initialize() override; virtual void initialize() override;
virtual void connectSignals() override; virtual void connectSignals(MainWindow *) override;
virtual void populate(Project *project) override; virtual void populate(Project *project) override;
public: public:
@ -101,7 +102,7 @@ public:
virtual void setup() override; virtual void setup() override;
virtual void initialize() override; virtual void initialize() override;
virtual void connectSignals() override; virtual void connectSignals(MainWindow *) override;
virtual void populate(Project *project) override; virtual void populate(Project *project) override;
public: public:
@ -124,12 +125,13 @@ public:
virtual void setup() override; virtual void setup() override;
virtual void initialize() override; virtual void initialize() override;
virtual void connectSignals() override; virtual void connectSignals(MainWindow *) override;
virtual void populate(Project *project) override; virtual void populate(Project *project) override;
public: public:
NoScrollComboBox *combo_dest_map; NoScrollComboBox *combo_dest_map;
NoScrollComboBox *combo_dest_warp; NoScrollComboBox *combo_dest_warp;
QPushButton *warning;
private: private:
WarpEvent *warp; WarpEvent *warp;
@ -146,7 +148,7 @@ public:
virtual void setup() override; virtual void setup() override;
virtual void initialize() override; virtual void initialize() override;
virtual void connectSignals() override; virtual void connectSignals(MainWindow *) override;
virtual void populate(Project *project) override; virtual void populate(Project *project) override;
public: public:
@ -171,7 +173,7 @@ public:
virtual void setup() override; virtual void setup() override;
virtual void initialize() override; virtual void initialize() override;
virtual void connectSignals() override; virtual void connectSignals(MainWindow *) override;
virtual void populate(Project *project) override; virtual void populate(Project *project) override;
public: public:
@ -192,7 +194,7 @@ public:
virtual void setup() override; virtual void setup() override;
virtual void initialize() override; virtual void initialize() override;
virtual void connectSignals() override; virtual void connectSignals(MainWindow *) override;
virtual void populate(Project *project) override; virtual void populate(Project *project) override;
public: public:
@ -216,7 +218,7 @@ public:
virtual void setup() override; virtual void setup() override;
virtual void initialize() override; virtual void initialize() override;
virtual void connectSignals() override; virtual void connectSignals(MainWindow *) override;
virtual void populate(Project *project) override; virtual void populate(Project *project) override;
public: public:
@ -242,7 +244,7 @@ public:
virtual void setup() override; virtual void setup() override;
virtual void initialize() override; virtual void initialize() override;
virtual void connectSignals() override; virtual void connectSignals(MainWindow *) override;
virtual void populate(Project *project) override; virtual void populate(Project *project) override;
public: public:
@ -263,7 +265,7 @@ public:
virtual void setup() override; virtual void setup() override;
virtual void initialize() override; virtual void initialize() override;
virtual void connectSignals() override; virtual void connectSignals(MainWindow *) override;
virtual void populate(Project *project) override; virtual void populate(Project *project) override;
public: public:

View file

@ -21,6 +21,9 @@ public:
explicit ProjectSettingsEditor(QWidget *parent = nullptr, Project *project = nullptr); explicit ProjectSettingsEditor(QWidget *parent = nullptr, Project *project = nullptr);
~ProjectSettingsEditor(); ~ProjectSettingsEditor();
static const int warpBehaviorsTab;
void setTab(int index);
signals: signals:
void reloadProject(); void reloadProject();

View file

@ -517,6 +517,13 @@ QSet<QString> WarpEvent::getExpectedFields() {
return expectedFields; return expectedFields;
} }
void WarpEvent::setWarningEnabled(bool enabled) {
WarpFrame * frame = static_cast<WarpFrame*>(this->getEventFrame());
if (frame && frame->warning)
frame->warning->setVisible(enabled);
}
Event *TriggerEvent::duplicate() { Event *TriggerEvent::duplicate() {
TriggerEvent *copy = new TriggerEvent(); TriggerEvent *copy = new TriggerEvent();

View file

@ -106,6 +106,7 @@ void Editor::setEditingMap() {
this->cursorMapTileRect->setActive(true); this->cursorMapTileRect->setActive(true);
setMapEditingButtonsEnabled(true); setMapEditingButtonsEnabled(true);
this->constructBehaviorValueList(); // TODO: Remove
} }
void Editor::setEditingCollision() { void Editor::setEditingCollision() {
@ -151,6 +152,7 @@ void Editor::setEditingObjects() {
setConnectionsEditable(false); setConnectionsEditable(false);
this->cursorMapTileRect->setSingleTileMode(); this->cursorMapTileRect->setSingleTileMode();
this->cursorMapTileRect->setActive(false); this->cursorMapTileRect->setActive(false);
updateWarpEventWarnings();
setMapEditingButtonsEnabled(false); setMapEditingButtonsEnabled(false);
} }
@ -1987,6 +1989,82 @@ void Editor::redrawObject(DraggablePixmapItem *item) {
} }
} }
/* TODO: Add tab to PSE for warp behaviors, containing:
- A description of what it means
- A check box to enable/disable the warning
- An editable list of warp behavior names
*/
// TODO: Relocate to file handling the "warp behaviors" window, make static list below a config default
const QStringList warpBehaviorNames = {
"MB_NORTH_ARROW_WARP",
"MB_SOUTH_ARROW_WARP",
"MB_WEST_ARROW_WARP",
"MB_EAST_ARROW_WARP",
"MB_STAIRS_OUTSIDE_ABANDONED_SHIP",
"MB_WATER_SOUTH_ARROW_WARP",
"MB_SHOAL_CAVE_ENTRANCE",
"MB_SECRET_BASE_SPOT_RED_CAVE_OPEN",
"MB_SECRET_BASE_SPOT_BROWN_CAVE_OPEN",
"MB_SECRET_BASE_SPOT_YELLOW_CAVE_OPEN",
"MB_SECRET_BASE_SPOT_BLUE_CAVE_OPEN",
"MB_SECRET_BASE_SPOT_TREE_LEFT_OPEN",
"MB_SECRET_BASE_SPOT_TREE_RIGHT_OPEN",
"MB_SECRET_BASE_SPOT_SHRUB_OPEN",
"MB_ANIMATED_DOOR",
"MB_NON_ANIMATED_DOOR",
"MB_PETALBURG_GYM_DOOR",
"MB_WATER_DOOR",
"MB_LADDER",
"MB_UP_ESCALATOR",
"MB_DOWN_ESCALATOR",
"MB_DEEP_SOUTH_WARP",
"MB_LAVARIDGE_GYM_B1F_WARP",
"MB_LAVARIDGE_GYM_1F_WARP",
"MB_AQUA_HIDEOUT_WARP",
"MB_MT_PYRE_HOLE",
"MB_MOSSDEEP_GYM_WARP",
"MB_BRIDGE_OVER_OCEAN",
};
QSet<uint32_t> warpBehaviorValues;
void Editor::constructBehaviorValueList() {
if (!project) return;
warpBehaviorValues.clear();
//warpBehaviorNames.removeDuplicates(); // TODO: Uncomment when list is actually dynamic
for (auto name : warpBehaviorNames) {
if (project->metatileBehaviorMap.contains(name)) {
warpBehaviorValues.insert(project->metatileBehaviorMap[name]);
}
}
}
// Warp events display a warning if they're not positioned on a metatile with a warp behavior.
void Editor::updateWarpEventWarning(Event *event) {
if (!map || !event || event->getEventType() != Event::Type::Warp)
return;
Block block;
Metatile * metatile = nullptr;
WarpEvent * warpEvent = static_cast<WarpEvent*>(event);
if (map->getBlock(warpEvent->getX(), warpEvent->getY(), &block)) {
metatile = Tileset::getMetatile(block.metatileId(), map->layout->tileset_primary, map->layout->tileset_secondary);
}
// metatile may be null if the warp is in the map border. Display the warning in this case
bool validWarpBehavior = metatile && warpBehaviorValues.contains(metatile->behavior());
warpEvent->setWarningEnabled(!validWarpBehavior);
}
// The warp event behavior warning is updated whenever the event moves or the event selection changes.
// It does not respond to changes in the underlying metatile. To capture the common case of a user painting
// metatiles on the Map tab then returning to the Events tab we update the warings for all selected warp
// events when the Events tab is opened. This does not cover the case where metatiles are painted while
// still on the Events tab, such as by Undo/Redo or the scripting API.
void Editor::updateWarpEventWarnings() {
if (selected_events) {
for (auto selection : *selected_events)
updateWarpEventWarning(selection->event);
}
}
void Editor::shouldReselectEvents() { void Editor::shouldReselectEvents() {
selectNewEvents = true; selectNewEvents = true;
} }

View file

@ -2035,7 +2035,7 @@ void MainWindow::updateSelectedObjects() {
EventFrame *eventFrame = event->createEventFrame(); EventFrame *eventFrame = event->createEventFrame();
eventFrame->populate(this->editor->project); eventFrame->populate(this->editor->project);
eventFrame->initialize(); eventFrame->initialize();
eventFrame->connectSignals(); eventFrame->connectSignals(this);
frames.append(eventFrame); frames.append(eventFrame);
} }
@ -2730,16 +2730,20 @@ void MainWindow::togglePreferenceSpecificUi() {
ui->actionOpen_Project_in_Text_Editor->setEnabled(true); ui->actionOpen_Project_in_Text_Editor->setEnabled(true);
} }
void MainWindow::on_actionProject_Settings_triggered() { void MainWindow::openProjectSettingsEditor(int tab) {
if (!this->projectSettingsEditor) { if (!this->projectSettingsEditor) {
this->projectSettingsEditor = new ProjectSettingsEditor(this, this->editor->project); this->projectSettingsEditor = new ProjectSettingsEditor(this, this->editor->project);
connect(this->projectSettingsEditor, &ProjectSettingsEditor::reloadProject, connect(this->projectSettingsEditor, &ProjectSettingsEditor::reloadProject,
this, &MainWindow::on_action_Reload_Project_triggered); this, &MainWindow::on_action_Reload_Project_triggered);
} }
this->projectSettingsEditor->setTab(tab);
openSubWindow(this->projectSettingsEditor); openSubWindow(this->projectSettingsEditor);
} }
void MainWindow::on_actionProject_Settings_triggered() {
this->openProjectSettingsEditor(porymapConfig.getProjectSettingsTab());
}
void MainWindow::on_actionCustom_Scripts_triggered() { void MainWindow::on_actionCustom_Scripts_triggered() {
if (!this->customScriptsEditor) if (!this->customScriptsEditor)
initCustomScriptsEditor(); initCustomScriptsEditor();

View file

@ -17,6 +17,7 @@ void DraggablePixmapItem::updatePosition() {
} else { } else {
setZValue(event->getY()); setZValue(event->getY());
} }
editor->updateWarpEventWarning(event);
} }
void DraggablePixmapItem::emitPositionChanged() { void DraggablePixmapItem::emitPositionChanged() {

View file

@ -3,9 +3,6 @@
#include "editcommands.h" #include "editcommands.h"
#include "draggablepixmapitem.h" #include "draggablepixmapitem.h"
#include "project.h"
#include "editor.h"
#include <limits> #include <limits>
using std::numeric_limits; using std::numeric_limits;
@ -109,7 +106,7 @@ void EventFrame::initCustomAttributesTable() {
this->layout_contents->addWidget(customAttributes); this->layout_contents->addWidget(customAttributes);
} }
void EventFrame::connectSignals() { void EventFrame::connectSignals(MainWindow *) {
this->connected = true; this->connected = true;
this->spinner_x->disconnect(); this->spinner_x->disconnect();
@ -258,10 +255,10 @@ void ObjectFrame::setup() {
EventFrame::initCustomAttributesTable(); EventFrame::initCustomAttributesTable();
} }
void ObjectFrame::connectSignals() { void ObjectFrame::connectSignals(MainWindow *window) {
if (this->connected) return; if (this->connected) return;
EventFrame::connectSignals(); EventFrame::connectSignals(window);
// sprite update // sprite update
this->combo_sprite->disconnect(); this->combo_sprite->disconnect();
@ -418,10 +415,10 @@ void CloneObjectFrame::setup() {
EventFrame::initCustomAttributesTable(); EventFrame::initCustomAttributesTable();
} }
void CloneObjectFrame::connectSignals() { void CloneObjectFrame::connectSignals(MainWindow *window) {
if (this->connected) return; if (this->connected) return;
EventFrame::connectSignals(); EventFrame::connectSignals(window);
// update icon displayed in frame with target // update icon displayed in frame with target
connect(this->clone->getPixmapItem(), &DraggablePixmapItem::spriteChanged, this->label_icon, &QLabel::setPixmap); connect(this->clone->getPixmapItem(), &DraggablePixmapItem::spriteChanged, this->label_icon, &QLabel::setPixmap);
@ -472,8 +469,6 @@ void CloneObjectFrame::populate(Project *project) {
this->combo_target_map->addItems(project->mapNames); this->combo_target_map->addItems(project->mapNames);
} }
void WarpFrame::setup() { void WarpFrame::setup() {
EventFrame::setup(); EventFrame::setup();
@ -493,14 +488,26 @@ void WarpFrame::setup() {
l_form_dest_warp->addRow("Destination Warp", this->combo_dest_warp); l_form_dest_warp->addRow("Destination Warp", this->combo_dest_warp);
this->layout_contents->addLayout(l_form_dest_warp); this->layout_contents->addLayout(l_form_dest_warp);
// warning
static const QString warningText = "Warning:\n"
"This warp event is not positioned on a metatile with a warp behavior.\n"
"Click this warning for more details.";
QVBoxLayout *l_vbox_warning = new QVBoxLayout();
this->warning = new QPushButton(warningText, this);
this->warning->setFlat(true);
this->warning->setStyleSheet("color: red; text-align: left");
this->warning->setVisible(false);
l_vbox_warning->addWidget(this->warning);
this->layout_contents->addLayout(l_vbox_warning);
// custom attributes // custom attributes
EventFrame::initCustomAttributesTable(); EventFrame::initCustomAttributesTable();
} }
void WarpFrame::connectSignals() { void WarpFrame::connectSignals(MainWindow *window) {
if (this->connected) return; if (this->connected) return;
EventFrame::connectSignals(); EventFrame::connectSignals(window);
// dest map // dest map
this->combo_dest_map->disconnect(); this->combo_dest_map->disconnect();
@ -515,6 +522,12 @@ void WarpFrame::connectSignals() {
this->warp->setDestinationWarpID(text); this->warp->setDestinationWarpID(text);
this->warp->modify(); this->warp->modify();
}); });
// warning
this->warning->disconnect();
connect(this->warning, &QPushButton::clicked, [window]() {
window->openProjectSettingsEditor(ProjectSettingsEditor::warpBehaviorsTab);
});
} }
void WarpFrame::initialize() { void WarpFrame::initialize() {
@ -572,10 +585,10 @@ void TriggerFrame::setup() {
EventFrame::initCustomAttributesTable(); EventFrame::initCustomAttributesTable();
} }
void TriggerFrame::connectSignals() { void TriggerFrame::connectSignals(MainWindow *window) {
if (this->connected) return; if (this->connected) return;
EventFrame::connectSignals(); EventFrame::connectSignals(window);
// label // label
this->combo_script->disconnect(); this->combo_script->disconnect();
@ -657,10 +670,10 @@ void WeatherTriggerFrame::setup() {
EventFrame::initCustomAttributesTable(); EventFrame::initCustomAttributesTable();
} }
void WeatherTriggerFrame::connectSignals() { void WeatherTriggerFrame::connectSignals(MainWindow *window) {
if (this->connected) return; if (this->connected) return;
EventFrame::connectSignals(); EventFrame::connectSignals(window);
// weather // weather
this->combo_weather->disconnect(); this->combo_weather->disconnect();
@ -716,10 +729,10 @@ void SignFrame::setup() {
EventFrame::initCustomAttributesTable(); EventFrame::initCustomAttributesTable();
} }
void SignFrame::connectSignals() { void SignFrame::connectSignals(MainWindow *window) {
if (this->connected) return; if (this->connected) return;
EventFrame::connectSignals(); EventFrame::connectSignals(window);
// facing dir // facing dir
this->combo_facing_dir->disconnect(); this->combo_facing_dir->disconnect();
@ -818,10 +831,10 @@ void HiddenItemFrame::setup() {
EventFrame::initCustomAttributesTable(); EventFrame::initCustomAttributesTable();
} }
void HiddenItemFrame::connectSignals() { void HiddenItemFrame::connectSignals(MainWindow *window) {
if (this->connected) return; if (this->connected) return;
EventFrame::connectSignals(); EventFrame::connectSignals(window);
// item // item
this->combo_item->disconnect(); this->combo_item->disconnect();
@ -909,10 +922,10 @@ void SecretBaseFrame::setup() {
EventFrame::initCustomAttributesTable(); EventFrame::initCustomAttributesTable();
} }
void SecretBaseFrame::connectSignals() { void SecretBaseFrame::connectSignals(MainWindow *window) {
if (this->connected) return; if (this->connected) return;
EventFrame::connectSignals(); EventFrame::connectSignals(window);
this->combo_base_id->disconnect(); this->combo_base_id->disconnect();
connect(this->combo_base_id, &QComboBox::currentTextChanged, [this](const QString &text) { connect(this->combo_base_id, &QComboBox::currentTextChanged, [this](const QString &text) {
@ -973,10 +986,10 @@ void HealLocationFrame::setup() {
EventFrame::initCustomAttributesTable(); EventFrame::initCustomAttributesTable();
} }
void HealLocationFrame::connectSignals() { void HealLocationFrame::connectSignals(MainWindow *window) {
if (this->connected) return; if (this->connected) return;
EventFrame::connectSignals(); EventFrame::connectSignals(window);
if (projectConfig.getHealLocationRespawnDataEnabled()) { if (projectConfig.getHealLocationRespawnDataEnabled()) {
this->combo_respawn_map->disconnect(); this->combo_respawn_map->disconnect();

View file

@ -10,6 +10,8 @@
Editor for the settings in a user's porymap.project.cfg file (and 'use_encounter_json' in porymap.user.cfg). Editor for the settings in a user's porymap.project.cfg file (and 'use_encounter_json' in porymap.user.cfg).
*/ */
const int ProjectSettingsEditor::warpBehaviorsTab = 4;
ProjectSettingsEditor::ProjectSettingsEditor(QWidget *parent, Project *project) : ProjectSettingsEditor::ProjectSettingsEditor(QWidget *parent, Project *project) :
QMainWindow(parent), QMainWindow(parent),
ui(new Ui::ProjectSettingsEditor), ui(new Ui::ProjectSettingsEditor),
@ -84,11 +86,6 @@ void ProjectSettingsEditor::markEdited() {
this->hasUnsavedChanges = true; this->hasUnsavedChanges = true;
} }
// Remember the current settings tab for future sessions
void ProjectSettingsEditor::on_mainTabs_tabBarClicked(int index) {
porymapConfig.setProjectSettingsTab(index);
}
void ProjectSettingsEditor::initUi() { void ProjectSettingsEditor::initUi() {
// Populate combo boxes // Populate combo boxes
if (project) { if (project) {
@ -99,9 +96,6 @@ void ProjectSettingsEditor::initUi() {
ui->comboBox_BaseGameVersion->addItems(ProjectConfig::versionStrings); ui->comboBox_BaseGameVersion->addItems(ProjectConfig::versionStrings);
ui->comboBox_AttributesSize->addItems({"1", "2", "4"}); ui->comboBox_AttributesSize->addItems({"1", "2", "4"});
// Select tab from last session
ui->mainTabs->setCurrentIndex(porymapConfig.getProjectSettingsTab());
// Validate that the border metatiles text is a comma-separated list of metatile values // Validate that the border metatiles text is a comma-separated list of metatile values
static const QString regex_Hex = "(0[xX])?[A-Fa-f0-9]+"; static const QString regex_Hex = "(0[xX])?[A-Fa-f0-9]+";
static const QRegularExpression expression(QString("^(%1,)*%1$").arg(regex_Hex)); // Comma-separated list of hex values static const QRegularExpression expression(QString("^(%1,)*%1$").arg(regex_Hex)); // Comma-separated list of hex values
@ -163,6 +157,16 @@ void ProjectSettingsEditor::disableParsedSetting(QWidget * widget, const QString
widget->setToolTip(QString("This value has been read from '%1' in %2").arg(name).arg(filepath)); widget->setToolTip(QString("This value has been read from '%1' in %2").arg(name).arg(filepath));
} }
// Remember the current settings tab for future sessions
void ProjectSettingsEditor::on_mainTabs_tabBarClicked(int index) {
porymapConfig.setProjectSettingsTab(index);
}
void ProjectSettingsEditor::setTab(int index) {
ui->mainTabs->setCurrentIndex(index);
porymapConfig.setProjectSettingsTab(index);
}
void ProjectSettingsEditor::setBorderMetatilesUi(bool customSize) { void ProjectSettingsEditor::setBorderMetatilesUi(bool customSize) {
ui->stackedWidget_BorderMetatiles->setCurrentIndex(customSize ? 0 : 1); ui->stackedWidget_BorderMetatiles->setCurrentIndex(customSize ? 0 : 1);
} }