undo/redo for edit/clear quest

This commit is contained in:
2025-06-12 15:17:08 -05:00
parent 9aa348e28d
commit 71629e45bd
8 changed files with 108 additions and 18 deletions

15
src/scenario/quest.cpp Normal file
View File

@@ -0,0 +1,15 @@
#include "quest.hpp"
bool cQuest::operator==(const cQuest& other) {
CHECK_EQ(other, deadline_is_relative);
CHECK_EQ(other, auto_start);
CHECK_EQ(other, deadline);
CHECK_EQ(other, event);
CHECK_EQ(other, xp);
CHECK_EQ(other, gold);
CHECK_EQ(other, bank1);
CHECK_EQ(other, bank2);
CHECK_EQ(other, name);
CHECK_EQ(other, descr);
return true;
}

View File

@@ -21,6 +21,10 @@ public:
short bank1 = -1, bank2 = -1; // which job bank(s) this quest is in; -1 for none
std::string name;
std::string descr;
// For detecting actual changes to quests in the scenario editor
bool operator==(const cQuest& other);
bool operator!=(const cQuest& other) { return !(*this == other); }
};
class cJob {

View File

@@ -635,21 +635,17 @@ static bool handle_rb_action(location the_point, bool option_hit) {
}
// Clear quest (it can't be deleted fully)
else {
scenario.quests[j] = cQuest();
scenario.quests[j].name = "Unused Quest";
cQuest cleared;
cleared.name = "Unused Quest";
undo_list.add(action_ptr(new aEditClearQuest("Clear Quest", j, scenario.quests[j], cleared)));
update_edit_menu();
scenario.quests[j] = cleared;
}
} else {
bool is_new = (j == scenario.quests.size());
if(edit_quest(j)){
// Create new confirmed
if(is_new){
undo_list.add(action_ptr(new aCreateDeleteQuest(true, scenario.quests.back())));
update_edit_menu();
}
// Quest edited
else{
// TODO undo action
}
// Quest create/edit undo action is added in save_quest_from_dlog() because quest editor
// has left/right buttons and can be launched with create/edit buttons elsewhere.
}
// Create new canceled
else if(is_new){

View File

@@ -2296,7 +2296,7 @@ static void put_quest_in_dlog(cDialog& me, const cQuest& quest, size_t which_que
}
}
static bool save_quest_from_dlog(cDialog& me, cQuest& quest, size_t which_quest, bool close) {
static bool save_quest_from_dlog(cDialog& me, cQuest& quest, size_t which_quest, bool& is_new, bool need_confirm, bool close) {
if(!me.toast(true)) return false;
quest.name = me["name"].getText();
@@ -2313,13 +2313,37 @@ static bool save_quest_from_dlog(cDialog& me, cQuest& quest, size_t which_quest,
quest.bank2 = me["bank2"].getTextAsNum();
} else quest.bank1 = quest.bank2 = -1;
scenario.quests[which_quest] = quest;
// Edit confirmed and real changes made:
if(scenario.quests[which_quest] != quest || is_new){
if(need_confirm){
// Confirm keeping changes
cChoiceDlog dlog("confirm-edit-quest", {"keep","revert","cancel"}, &me);
dlog->getControl("keep-msg").replaceText("{{quest}}", quest.name);
std::string choice = dlog.show();
if(choice == "revert"){
put_quest_in_dlog(me, scenario.quests[which_quest], which_quest);
return false;
}else if(choice == "cancel"){
return false;
}
}
if(is_new){
undo_list.add(action_ptr(new aCreateDeleteQuest(true, scenario.quests.back())));
update_edit_menu();
}else{
undo_list.add(action_ptr(new aEditClearQuest("Edit Quest", which_quest, scenario.quests[which_quest], quest)));
update_edit_menu();
}
scenario.quests[which_quest] = quest;
is_new = false;
}
if(!close) me.untoast();
return true;
}
static bool change_quest_dlog_page(cDialog& me, std::string dir, cQuest& quest, size_t& which_quest) {
if(!save_quest_from_dlog(me, quest, which_quest, false))
static bool change_quest_dlog_page(cDialog& me, std::string dir, cQuest& quest, size_t& which_quest, bool& is_new) {
if(!save_quest_from_dlog(me, quest, which_quest, is_new, true, false))
return true;
if(dir == "left") {
@@ -2338,8 +2362,11 @@ static bool change_quest_dlog_page(cDialog& me, std::string dir, cQuest& quest,
}
bool edit_quest(size_t which_quest) {
short first = which_quest;
using namespace std::placeholders;
bool is_new = false;
if(which_quest == scenario.quests.size()){
is_new = true;
scenario.quests.resize(which_quest + 1);
scenario.quests[which_quest].name = "New Quest";
}
@@ -2347,7 +2374,7 @@ bool edit_quest(size_t which_quest) {
cDialog quest_dlg(*ResMgr::dialogs.get("edit-quest"));
quest_dlg["cancel"].attachClickHandler(std::bind(&cDialog::toast, _1, false));
quest_dlg["okay"].attachClickHandler(std::bind(save_quest_from_dlog, _1, std::ref(quest), std::ref(which_quest), true));
quest_dlg["okay"].attachClickHandler(std::bind(save_quest_from_dlog, _1, std::ref(quest), std::ref(which_quest), std::ref(is_new), false, true));
quest_dlg.attachClickHandlers([](cDialog& me, std::string item_hit, eKeyMod) {
std::string field_id = item_hit.substr(7);
std::string title = field_id == "evt" ? "Select an event:" : "Select a job board:";
@@ -2378,12 +2405,12 @@ bool edit_quest(size_t which_quest) {
quest_dlg["left"].hide();
quest_dlg["right"].hide();
} else {
quest_dlg.attachClickHandlers(std::bind(change_quest_dlog_page, _1, _2, std::ref(quest), std::ref(which_quest)), {"left", "right"});
quest_dlg.attachClickHandlers(std::bind(change_quest_dlog_page, _1, _2, std::ref(quest), std::ref(which_quest), std::ref(is_new)), {"left", "right"});
}
put_quest_in_dlog(quest_dlg, quest, which_quest);
quest_dlg.run();
return quest_dlg.accepted();
return quest_dlg.accepted() || first != which_quest;
}
static bool put_shop_item_in_dlog(cPict& pic, cControl& num, cControl& title, const cShop& shop, int which) {

View File

@@ -459,4 +459,24 @@ bool aEditClearSpecialItem::redo_me() {
}
scenario.special_items[which] = after;
return true;
}
bool aEditClearQuest::undo_me() {
// If not editing quests, show it
if(overall_mode != MODE_EDIT_QUESTS){
start_quest_editing();
// TODO scroll to show the quest
}
scenario.quests[which] = before;
return true;
}
bool aEditClearQuest::redo_me() {
// If not editing quests, show it
if(overall_mode != MODE_EDIT_QUESTS){
start_quest_editing();
// TODO scroll to show the quest
}
scenario.quests[which] = after;
return true;
}

View File

@@ -316,4 +316,16 @@ public:
cAction(name), which(which), before(before), after(after) {}
};
/// Action which edits or clears a quest
class aEditClearQuest : public cAction {
size_t which;
cQuest before;
cQuest after;
bool undo_me() override;
bool redo_me() override;
public:
aEditClearQuest(std::string name, size_t which, cQuest before, cQuest after) :
cAction(name), which(which), before(before), after(after) {}
};
#endif