Make basic placing/erasing items undoable

This commit is contained in:
2025-06-02 20:38:49 -05:00
parent ab3a6d8e7f
commit fb9efa734d
4 changed files with 61 additions and 21 deletions

View File

@@ -712,12 +712,18 @@ static bool handle_rb_action(location the_point, bool option_hit) {
stroke_ter_changes_t current_stroke_changes;
std::string current_stroke_type;
item_changes_t current_items_placed;
void commit_stroke() {
if(!current_stroke_changes.empty()){
undo_list.add(action_ptr(new aDrawTerrain("Draw Terrain (" + current_stroke_type + ")", current_stroke_changes)));
update_edit_menu();
current_stroke_changes.clear();
current_stroke_type = "";
}else if(!current_items_placed.empty()){
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();
}
}
@@ -896,16 +902,7 @@ static bool handle_terrain_action(location the_point, bool ctrl_hit) {
// If we just placed this item there, forget it
if(!mouse_button_held || last_placement != spot_hit) {
mouse_button_held = true;
auto iter = std::find_if(town->preset_items.begin(), town->preset_items.end(), [](const cTown::cItem& item) {
return item.code < 0;
});
if(iter != town->preset_items.end()) {
*iter = {spot_hit, mode_count, scenario.scen_items[mode_count]};
if(container_there(spot_hit)) iter->contained = true;
} else {
town->preset_items.push_back({spot_hit, mode_count, scenario.scen_items[mode_count]});
if(container_there(spot_hit)) town->preset_items.back().contained = true;
}
place_item(spot_hit, mode_count, false, false, 100, current_items_placed);
last_placement = spot_hit;
}
break;
@@ -1154,11 +1151,12 @@ static bool handle_terrain_action(location the_point, bool ctrl_hit) {
for(short x = 0; x < town->preset_items.size(); x++)
if((spot_hit.x == town->preset_items[x].loc.x) &&
(spot_hit.y == town->preset_items[x].loc.y) && (town->preset_items[x].code >= 0)) {
undo_list.add(action_ptr(new aPlaceEraseItem("Erase Item", false, x, town->preset_items[x])));
update_edit_menu();
town->preset_items[x].code = -1;
break;
}
while(!town->preset_items.empty() && town->preset_items.back().code == -1)
town->preset_items.pop_back();
overall_mode = MODE_DRAWING;
break;
case MODE_SET_TOWN_START:
@@ -2444,7 +2442,7 @@ void adjust_space(location l, stroke_ter_changes_t& stroke_changes) {
}
}
bool place_item(location spot_hit,short which_item,bool property,bool always,short odds) {
bool place_item(location spot_hit,short which_item,bool property,bool always,short odds,std::map<size_t,cTown::cItem>& items_placed) {
// odds 0 - 100, with 100 always
if((which_item < 0) || (which_item >= scenario.scen_items.size()))
return true;
@@ -2462,6 +2460,8 @@ bool place_item(location spot_hit,short which_item,bool property,bool always,sho
town->preset_items[x].contained = container_there(spot_hit);
town->preset_items[x].property = property;
town->preset_items[x].always_there = always;
items_placed[x] = town->preset_items[x];
return true;
}
}
@@ -2471,6 +2471,7 @@ bool place_item(location spot_hit,short which_item,bool property,bool always,sho
void place_items_in_town() {
location l;
std::map<size_t, cTown::cItem> items_placed;
for(short i = 0; i < town->max_dim; i++)
for(short j = 0; j < town->max_dim; j++) {
l.x = i;
@@ -2481,7 +2482,7 @@ void place_items_in_town() {
for(short x = 0; x < 10; x++)
place_item(l,scenario.storage_shortcuts[k].item_num[x],
scenario.storage_shortcuts[k].property,false,
scenario.storage_shortcuts[k].item_odds[x]);
scenario.storage_shortcuts[k].item_odds[x],items_placed);
}
}
draw_terrain();

View File

@@ -28,7 +28,7 @@ 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);
bool place_item(location spot_hit,short which_item,bool property,bool always,short odds,std::map<size_t,cTown::cItem>& items_placed);
void place_items_in_town();
void set_up_start_screen();
void set_up_main_screen();

View File

@@ -16,17 +16,17 @@ extern void start_out_edit();
extern void redraw_screen();
extern void set_current_town(int,bool first_restore = false);
cTerrainAction::cTerrainAction(std::string name, short town_num, location where) : cAction(name) {
cTerrainAction::cTerrainAction(std::string name, short town_num, location where, bool reversed) : cAction(name, reversed) {
area.is_town = true;
area.town_num = town_num;
area.where = where;
}
cTerrainAction::cTerrainAction(std::string name, location out_sec, location where) : cAction(name) {
cTerrainAction::cTerrainAction(std::string name, location out_sec, location where, bool reversed) : cAction(name, reversed) {
area.is_town = false;
area.out_sec = out_sec;
area.where = where;
}
cTerrainAction::cTerrainAction(std::string name, location where) : cAction(name) {
cTerrainAction::cTerrainAction(std::string name, location where, bool reversed) : cAction(name, reversed) {
area.is_town = editing_town;
// One of these two will be ignored
area.town_num = cur_town;
@@ -108,3 +108,29 @@ bool aDrawTerrain::redo_me() {
}
return true;
}
aPlaceEraseItem::aPlaceEraseItem(std::string name, bool place, size_t index, cTown::cItem item)
: cTerrainAction(name, item.loc, !place)
, items({{index, item}})
{}
aPlaceEraseItem::aPlaceEraseItem(std::string name, bool place, item_changes_t items)
: cTerrainAction(name, items.begin()->second.loc, !place)
, items(items)
{}
bool aPlaceEraseItem::undo_me() {
auto& town_items = scenario.towns[cur_town]->preset_items;
for(auto change : items){
town_items[change.first].code = -1;
}
return true;
}
bool aPlaceEraseItem::redo_me() {
auto& town_items = scenario.towns[cur_town]->preset_items;
for(auto change : items){
town_items[change.first] = change.second;
}
return true;
}

View File

@@ -3,6 +3,7 @@
#include "location.hpp"
#include "tools/undo.hpp"
#include "scenario/town.hpp"
struct area_ref_t {
bool is_town;
@@ -18,13 +19,14 @@ 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;
// Action that modified something in town or outdoor terrain, so we should show the modified area when undoing or redoing
class cTerrainAction : public cAction {
public:
cTerrainAction(std::string name, short town_num, location where);
cTerrainAction(std::string name, location out_sec, location where);
cTerrainAction(std::string name, location where);
cTerrainAction(std::string name, short town_num, location where, bool reversed = false);
cTerrainAction(std::string name, location out_sec, location where, bool reversed = false);
cTerrainAction(std::string name, location where, bool reversed = false);
void undo();
void redo();
bool undo_me() = 0;
@@ -58,6 +60,17 @@ private:
const stroke_ter_changes_t changes;
};
/// Action which places or erases item(s) in a town
class aPlaceEraseItem : public cTerrainAction {
bool placed;
item_changes_t items;
bool undo_me() override;
bool redo_me() override;
public:
aPlaceEraseItem(std::string name, bool place, item_changes_t items);
aPlaceEraseItem(std::string name, bool place, size_t index, cTown::cItem item);
};
/// Action which adds a new town to the end of the list, or deletes the last one
class aCreateDeleteTown : public cAction {
bool created;