undo/redo place/erase creatures

This commit is contained in:
2025-06-03 11:13:43 -05:00
parent a732e8350b
commit da988afb28
5 changed files with 70 additions and 21 deletions

View File

@@ -713,6 +713,7 @@ stroke_ter_changes_t current_stroke_changes;
std::string current_stroke_type;
item_changes_t current_items_placed;
creature_changes_t current_creatures_placed;
void commit_stroke() {
if(!current_stroke_changes.empty()){
@@ -724,6 +725,10 @@ void commit_stroke() {
undo_list.add(action_ptr(new aPlaceEraseItem(current_items_placed.size() > 1 ? "Place Items" : "Place Item", true, current_items_placed)));
update_edit_menu();
current_items_placed.clear();
}else if(!current_creatures_placed.empty()){
undo_list.add(action_ptr(new aPlaceEraseCreature(current_creatures_placed.size() > 1 ? "Place Creatures" : "Place Creature", true, current_creatures_placed)));
update_edit_menu();
current_items_placed.clear();
}
}
@@ -936,16 +941,10 @@ static bool handle_terrain_action(location the_point, bool ctrl_hit) {
set_string("Paste monster","Not while outdoors.");
break;
}
auto iter = std::find_if(town->creatures.begin(), town->creatures.end(), [](const cTownperson& who) {
return who.number == 0;
});
if(iter != town->creatures.end()) {
*iter = *monst;
iter->start_loc = spot_hit;
} else { // Placement failed
town->creatures.push_back(*monst);
town->creatures.back().start_loc = spot_hit;
}
place_creature(spot_hit, static_cast<mon_num_t>(mode_count), current_creatures_placed);
undo_list.add(action_ptr(new aPlaceEraseCreature("Paste Creature", true, current_creatures_placed)));
update_edit_menu();
current_creatures_placed.clear();
} else if(auto item = boost::get<cTown::cItem>(&clipboard)) {
if(!editing_town) {
set_string("Paste item","Not while outdoors.");
@@ -968,14 +967,7 @@ static bool handle_terrain_action(location the_point, bool ctrl_hit) {
// If we just placed this same creature here, forget it
if(!mouse_button_held || last_placement != spot_hit) {
mouse_button_held = true;
auto iter = std::find_if(town->creatures.begin(), town->creatures.end(), [](const cTownperson& who) {
return who.number == 0;
});
if(iter != town->creatures.end()) {
*iter = {spot_hit, static_cast<mon_num_t>(mode_count), scenario.scen_monsters[mode_count]};
} else { // Placement failed
town->creatures.push_back({spot_hit, static_cast<mon_num_t>(mode_count), scenario.scen_monsters[mode_count]});
}
place_creature(spot_hit, static_cast<mon_num_t>(mode_count), current_creatures_placed);
last_placement = spot_hit;
}
break;
@@ -1132,11 +1124,11 @@ static bool handle_terrain_action(location the_point, bool ctrl_hit) {
case MODE_ERASE_CREATURE: //delete monst
for(short x = 0; x < town->creatures.size(); x++)
if(monst_on_space(spot_hit,x)) {
undo_list.add(action_ptr(new aPlaceEraseCreature("Erase Creature", false, x, town->creatures[x])));
update_edit_menu();
town->creatures[x].number = 0;
break;
}
while(!town->creatures.empty() && town->creatures.back().number == 0)
town->creatures.pop_back();
overall_mode = MODE_DRAWING;
break;
case MODE_ERASE_ITEM: // delete item
@@ -2487,6 +2479,22 @@ void place_items_in_town() {
draw_terrain();
}
bool place_creature(location spot_hit, mon_num_t which, creature_changes_t& creatures_placed) {
for(short x = 0; x <= town->creatures.size(); x++){
if(x == town->creatures.size()){
town->creatures.resize(x+1);
town->creatures[x].number = 0;
}
if(town->creatures[x].number == 0) {
town->creatures[x] = {spot_hit, which, scenario.scen_monsters[which]};
creatures_placed[x] = town->creatures[x];
return true;
}
}
// Shouldn't be reached:
return false;
}
void place_edit_special(location loc) {
if(!editing_town && (loc.x == 0 || loc.x == 47 || loc.y == 0 || loc.y == 47)) {
cChoiceDlog("not-at-edge").show();

View File

@@ -28,8 +28,9 @@ void adjust_space(location l,stroke_ter_changes_t& stroke_changes);
void commit_stroke();
bool is_lava(short x,short y);
ter_num_t coord_to_ter(short x,short y);
bool place_item(location spot_hit,short which_item,bool property,bool always,short odds,std::map<size_t,cTown::cItem>& items_placed);
bool place_item(location spot_hit,short which_item,bool property,bool always,short odds,item_changes_t& items_placed);
void place_items_in_town();
bool place_creature(location spot_hit,mon_num_t which,creature_changes_t& creatures_placed);
void set_up_start_screen();
void set_up_main_screen();
void start_town_edit();

View File

@@ -91,6 +91,8 @@ static bool edit_placed_monst_event_filter(cDialog& me, std::string hit, cTownpe
me.toast(false);
} else if(hit == "del") {
me.toast(false);
undo_list.add(action_ptr(new aPlaceEraseCreature("Delete Creature", false, which, town->creatures[which])));
update_edit_menu();
town->creatures[which].number = 0;
} else if(hit == "type-edit") {
get_placed_monst_in_dlog(me, monst);

View File

@@ -134,3 +134,29 @@ bool aPlaceEraseItem::redo_me() {
}
return true;
}
aPlaceEraseCreature::aPlaceEraseCreature(std::string name, bool place, size_t index, cTownperson creature)
: cTerrainAction(name, creature.start_loc, !place)
, creatures({{index, creature}})
{}
aPlaceEraseCreature::aPlaceEraseCreature(std::string name, bool place, creature_changes_t creatures)
: cTerrainAction(name, creatures.begin()->second.start_loc, !place)
, creatures(creatures)
{}
bool aPlaceEraseCreature::undo_me() {
auto& town_creatures = scenario.towns[cur_town]->creatures;
for(auto change : creatures){
town_creatures[change.first].number = 0;
}
return true;
}
bool aPlaceEraseCreature::redo_me() {
auto& town_creatures = scenario.towns[cur_town]->creatures;
for(auto change : creatures){
town_creatures[change.first] = change.second;
}
return true;
}

View File

@@ -20,6 +20,7 @@ struct ter_change_t {
typedef std::map<location,ter_change_t,loc_compare> stroke_ter_changes_t;
typedef std::map<size_t, cTown::cItem> item_changes_t;
typedef std::map<size_t, cTownperson> creature_changes_t;
// Action that modified something in town or outdoor terrain, so we should show the modified area when undoing or redoing
class cTerrainAction : public cAction {
@@ -71,6 +72,17 @@ public:
aPlaceEraseItem(std::string name, bool place, size_t index, cTown::cItem item);
};
/// Action which places or erases creature(s) in a town
class aPlaceEraseCreature : public cTerrainAction {
bool placed;
creature_changes_t creatures;
bool undo_me() override;
bool redo_me() override;
public:
aPlaceEraseCreature(std::string name, bool place, creature_changes_t creatures);
aPlaceEraseCreature(std::string name, bool place, size_t index, cTownperson creature);
};
/// Action which adds a new town to the end of the list, or deletes the last one
class aCreateDeleteTown : public cAction {
bool created;