undo/redo edit town entrance

This commit is contained in:
2025-06-11 14:50:53 -05:00
parent 38d4701226
commit 6948453971
4 changed files with 67 additions and 42 deletions

View File

@@ -2296,6 +2296,37 @@ static const std::array<location,5> trim_diffs = {{
loc(0,0), loc(-1,0), loc(1,0), loc(0,-1), loc(0,1) loc(0,0), loc(-1,0), loc(1,0), loc(0,-1), loc(0,1)
}}; }};
long get_town_entrance(location l) {
auto& city_locs = current_terrain->city_locs;
auto iter = std::find(city_locs.begin(), city_locs.end(), l);
if(iter != city_locs.end()) return iter->spec;
return 0;
}
// Set, create, or delete the current outdoor section's city_loc for a given location
// Pass town_num -1 to remove the entrance from city_locs
void set_town_entrance(location l, long town_num) {
auto& city_locs = current_terrain->city_locs;
auto iter = std::find(city_locs.begin(), city_locs.end(), l);
if(iter != city_locs.end()){
// Erase town entrance:
if(town_num < 0){
city_locs.erase(iter);
}
// Overwrite town entrance:
else{
iter->spec = town_num;
}
}else{
// Add new town entrance:
if(town_num >= 0){
spec_loc_t loc = l;
loc.spec = town_num;
city_locs.push_back(loc);
}
}
}
void set_terrain(location l,ter_num_t terrain_type,stroke_ter_changes_t& stroke_changes, bool handle_special) { void set_terrain(location l,ter_num_t terrain_type,stroke_ter_changes_t& stroke_changes, bool handle_special) {
cArea* cur_area = get_current_area(); cArea* cur_area = get_current_area();
@@ -2317,10 +2348,10 @@ void set_terrain(location l,ter_num_t terrain_type,stroke_ter_changes_t& stroke_
if(!editing_town) { if(!editing_town) {
// Implicitly erase town entrances when a space is set from a town terrain to a non-town terrain // Implicitly erase town entrances when a space is set from a town terrain to a non-town terrain
if(old_ter.special == eTerSpec::TOWN_ENTRANCE && new_ter.special != eTerSpec::TOWN_ENTRANCE){ if(old_ter.special == eTerSpec::TOWN_ENTRANCE && new_ter.special != eTerSpec::TOWN_ENTRANCE){
for(short i = current_terrain->city_locs.size() - 1; i >= 0; i--) { long old_town_num = get_town_entrance(l);
if(current_terrain->city_locs[i] == l) undo_list.add(action_ptr(new aEditTownEntrance(spot_hit, old_town_num, -1)));
current_terrain->city_locs.erase(current_terrain->city_locs.begin() + i); update_edit_menu();
} set_town_entrance(l, -1);
} }
// Don't implicitly erase signs, because the designer may have entered text in them // Don't implicitly erase signs, because the designer may have entered text in them
} }
@@ -2664,44 +2695,13 @@ void town_entry(location spot_hit) {
showError("This space isn't a town entrance. Town entrances are marked by a small brown castle icon."); showError("This space isn't a town entrance. Town entrances are marked by a small brown castle icon.");
return; return;
} }
// clean up old town entries long old_town_num = get_town_entrance(spot_hit);
for(short i = 0; i < current_terrain->city_locs.size(); i++){ long town_num = pick_town_num("select-town-enter",old_town_num,scenario);
if(current_terrain->city_locs[i].spec >= 0) {
auto& city_loc = current_terrain->city_locs[i]; if(town_num >= 0 && town_num != old_town_num){
if(!get_current_area()->is_on_map(city_loc)) undo_list.add(action_ptr(new aEditTownEntrance(spot_hit, old_town_num, town_num)));
city_loc.spec = -1; update_edit_menu();
else{ set_town_entrance(spot_hit, town_num);
ter = current_terrain->terrain[city_loc.x][city_loc.y];
if(scenario.ter_types[ter].special != eTerSpec::TOWN_ENTRANCE)
city_loc.spec = -1;
}
}
}
auto iter = std::find(current_terrain->city_locs.begin(), current_terrain->city_locs.end(), spot_hit);
// Edit existing town entrance
if(iter != current_terrain->city_locs.end()) {
int town = pick_town_num("select-town-enter",iter->spec,scenario);
if(town >= 0) iter->spec = town;
} else {
iter = std::find_if(current_terrain->city_locs.begin(), current_terrain->city_locs.end(), [](const spec_loc_t& loc) {
return loc.spec < 0;
});
// Find unused town entrance and fill it
if(iter != current_terrain->city_locs.end()) {
int town = pick_town_num("select-town-enter",0,scenario);
if(town >= 0) {
*iter = spot_hit;
iter->spec = town;
}
}
// Add new town entrance at the back of list
else {
int town = pick_town_num("select-town-enter",0,scenario);
if(town >= 0) {
current_terrain->city_locs.emplace_back(spot_hit);
current_terrain->city_locs.back().spec = town;
}
}
} }
} }

View File

@@ -23,6 +23,8 @@ void change_rect_terrain(rectangle r,ter_num_t terrain_type,short probability,bo
void flood_fill_terrain(location start, ter_num_t terrain_type); void flood_fill_terrain(location start, ter_num_t terrain_type);
void frill_up_terrain(); void frill_up_terrain();
void unfrill_terrain(); void unfrill_terrain();
long get_town_entrance(location l);
void set_town_entrance(location l, long town_num);
void set_terrain(location l,ter_num_t terrain_type,stroke_ter_changes_t& stroke_changes,bool handle_special=true); void set_terrain(location l,ter_num_t terrain_type,stroke_ter_changes_t& stroke_changes,bool handle_special=true);
void adjust_space(location l,stroke_ter_changes_t& stroke_changes); void adjust_space(location l,stroke_ter_changes_t& stroke_changes);
void commit_stroke(); void commit_stroke();

View File

@@ -2,6 +2,7 @@
#include "scenario/scenario.hpp" #include "scenario/scenario.hpp"
#include "scenario/area.hpp" #include "scenario/area.hpp"
#include "scen.actions.hpp"
extern bool editing_town; extern bool editing_town;
extern short cur_town; extern short cur_town;
@@ -259,4 +260,15 @@ bool aEditSignText::redo_me() {
auto iter = std::find(signs.begin(), signs.end(), area.where); auto iter = std::find(signs.begin(), signs.end(), area.where);
iter->text = new_text; iter->text = new_text;
return true; return true;
}
// cTerrainAction makes sure current_terrain properly references the outdoor section where the edit happened
bool aEditTownEntrance::undo_me() {
set_town_entrance(area.where, old_town);
return true;
}
bool aEditTownEntrance::redo_me() {
set_town_entrance(area.where, new_town);
return true;
} }

View File

@@ -105,6 +105,17 @@ public:
cTerrainAction("Edit Sign Text", loc), old_text(old_text), new_text(new_text) {} cTerrainAction("Edit Sign Text", loc), old_text(old_text), new_text(new_text) {}
}; };
/// Action which edits town entrance
class aEditTownEntrance : public cTerrainAction {
long old_town;
long new_town;
bool undo_me() override;
bool redo_me() override;
public:
aEditTownEntrance(location loc, long old_town, long new_town) :
cTerrainAction("Edit Town Entrance", loc), old_town(old_town), new_town(new_town) {}
};
/// Action which adds a new town to the end of the list, or deletes the last one /// Action which adds a new town to the end of the list, or deletes the last one
class aCreateDeleteTown : public cAction { class aCreateDeleteTown : public cAction {
bool created; bool created;