diff --git a/src/scenedit/scen.actions.cpp b/src/scenedit/scen.actions.cpp index 60e2bf01..bde89b81 100644 --- a/src/scenedit/scen.actions.cpp +++ b/src/scenedit/scen.actions.cpp @@ -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& 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 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(); diff --git a/src/scenedit/scen.actions.hpp b/src/scenedit/scen.actions.hpp index f929499f..1a2159a0 100644 --- a/src/scenedit/scen.actions.hpp +++ b/src/scenedit/scen.actions.hpp @@ -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& items_placed); void place_items_in_town(); void set_up_start_screen(); void set_up_main_screen(); diff --git a/src/scenedit/scen.undo.cpp b/src/scenedit/scen.undo.cpp index adb049f8..58eed218 100644 --- a/src/scenedit/scen.undo.cpp +++ b/src/scenedit/scen.undo.cpp @@ -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; +} diff --git a/src/scenedit/scen.undo.hpp b/src/scenedit/scen.undo.hpp index 5984f584..e4ba868c 100644 --- a/src/scenedit/scen.undo.hpp +++ b/src/scenedit/scen.undo.hpp @@ -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 stroke_ter_changes_t; +typedef std::map 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;