undo/redo paste terrain

This commit is contained in:
2025-06-03 11:28:17 -05:00
parent da988afb28
commit 6240d0a657
2 changed files with 59 additions and 50 deletions

View File

@@ -957,7 +957,12 @@ static bool handle_terrain_action(location the_point, bool ctrl_hit) {
} else if(auto patch = boost::get<vector2d<ter_num_t>>(&clipboard)) { } else if(auto patch = boost::get<vector2d<ter_num_t>>(&clipboard)) {
for(int x = 0; x < patch->width(); x++) for(int x = 0; x < patch->width(); x++)
for(int y = 0; y < patch->height(); y++) for(int y = 0; y < patch->height(); y++)
cur_area->terrain(spot_hit.x + x, spot_hit.y + y) = (*patch)[x][y]; set_terrain(loc(spot_hit.x + x, spot_hit.y + y), (*patch)[x][y], current_stroke_changes, false);
if(!current_stroke_changes.empty()){
undo_list.add(action_ptr(new aDrawTerrain("Paste Terrain", current_stroke_changes)));
update_edit_menu();
current_stroke_changes.clear();
}
} else { } else {
showError("Nothing to paste. Try copying something first."); showError("Nothing to paste. Try copying something first.");
} }
@@ -2190,7 +2195,7 @@ 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)
}}; }};
void set_terrain(location l,ter_num_t terrain_type,stroke_ter_changes_t& stroke_changes) { 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();
if(!cur_area->is_on_map(l)) return; if(!cur_area->is_on_map(l)) return;
@@ -2222,59 +2227,61 @@ void set_terrain(location l,ter_num_t terrain_type,stroke_ter_changes_t& stroke_
cur_area->terrain(l.x,l.y) = terrain_type; cur_area->terrain(l.x,l.y) = terrain_type;
location l2 = l; location l2 = l;
// Large objects (eg rubble) if(handle_special){
if(scenario.ter_types[terrain_type].obj_num > 0){ // Large objects (eg rubble)
int q = scenario.ter_types[terrain_type].obj_num; if(scenario.ter_types[terrain_type].obj_num > 0){
location obj_loc = scenario.ter_types[terrain_type].obj_pos; int q = scenario.ter_types[terrain_type].obj_num;
location obj_dim = scenario.ter_types[terrain_type].obj_size; location obj_loc = scenario.ter_types[terrain_type].obj_pos;
while(obj_loc.x > 0) l2.x-- , obj_loc.x--; location obj_dim = scenario.ter_types[terrain_type].obj_size;
while(obj_loc.y > 0) l2.y-- , obj_loc.y--; while(obj_loc.x > 0) l2.x-- , obj_loc.x--;
for(short i = 0; i < obj_dim.x; i++) while(obj_loc.y > 0) l2.y-- , obj_loc.y--;
for(short j = 0; j < obj_dim.y; j++){ for(short i = 0; i < obj_dim.x; i++)
location temp = loc(l2.x + i, l2.y + j); for(short j = 0; j < obj_dim.y; j++){
if(!cur_area->is_on_map(temp)) continue; location temp = loc(l2.x + i, l2.y + j);
if(!cur_area->is_on_map(temp)) continue;
ter_num_t object_part = find_object_part(q,i,j,terrain_type); ter_num_t object_part = find_object_part(q,i,j,terrain_type);
ter_num_t part_old = cur_area->terrain(temp.x, temp.y); ter_num_t part_old = cur_area->terrain(temp.x, temp.y);
if(stroke_changes.find(temp) != stroke_changes.end()){ if(stroke_changes.find(temp) != stroke_changes.end()){
part_old = stroke_changes[temp].old_num; part_old = stroke_changes[temp].old_num;
}
stroke_changes[temp] = {part_old, object_part};
cur_area->terrain(temp.x,temp.y) = object_part;
} }
stroke_changes[temp] = {part_old, object_part}; }
cur_area->terrain(temp.x,temp.y) = object_part;
}
}
// First make sure surrounding spaces have the correct ground types. // First make sure surrounding spaces have the correct ground types.
// This should handle the case of placing hills around mountains. // This should handle the case of placing hills around mountains.
unsigned int main_ground = scenario.ter_types[terrain_type].ground_type; unsigned int main_ground = scenario.ter_types[terrain_type].ground_type;
long trim_ground = scenario.ter_types[terrain_type].trim_ter; long trim_ground = scenario.ter_types[terrain_type].trim_ter;
for(int x = -1; x <= 1; x++) { for(int x = -1; x <= 1; x++) {
for(int y = -1; y <= 1; y++) { for(int y = -1; y <= 1; y++) {
location l3(l.x+x,l.y+y); location l3(l.x+x,l.y+y);
if(!cur_area->is_on_map(l3)) continue; if(!cur_area->is_on_map(l3)) continue;
ter_num_t ter_there = cur_area->terrain(l3.x,l3.y); ter_num_t ter_there = cur_area->terrain(l3.x,l3.y);
unsigned int ground_there = scenario.ter_types[ter_there].ground_type; unsigned int ground_there = scenario.ter_types[ter_there].ground_type;
if(ground_there != main_ground && ground_there != trim_ground) { if(ground_there != main_ground && ground_there != trim_ground) {
ter_num_t new_ter = scenario.get_ter_from_ground(trim_ground); ter_num_t new_ter = scenario.get_ter_from_ground(trim_ground);
if(new_ter > scenario.ter_types.size()) continue; if(new_ter > scenario.ter_types.size()) continue;
cTerrain& ter_type = scenario.ter_types[new_ter]; cTerrain& ter_type = scenario.ter_types[new_ter];
// We need to be very cautious here. // We need to be very cautious here.
// Only make the change if the terrain already there is the archetype for the ground type // Only make the change if the terrain already there is the archetype for the ground type
// that is the trim terrain of the terrain we're trying to place. // that is the trim terrain of the terrain we're trying to place.
// Otherwise it might overwrite important things, like buildings or forests. // Otherwise it might overwrite important things, like buildings or forests.
if(ter_there != scenario.get_ter_from_ground(ter_type.trim_ter)) if(ter_there != scenario.get_ter_from_ground(ter_type.trim_ter))
continue; continue;
stroke_changes[l3] = {ter_there, new_ter}; stroke_changes[l3] = {ter_there, new_ter};
cur_area->terrain(l3.x,l3.y) = new_ter; cur_area->terrain(l3.x,l3.y) = new_ter;
}
} }
} }
}
// Adjusting terrains with trim // Adjusting terrains with trim
for(location d : trim_diffs) { for(location d : trim_diffs) {
location l3(l.x+d.x, l.y+d.y); location l3(l.x+d.x, l.y+d.y);
if(!cur_area->is_on_map(l3)) continue; if(!cur_area->is_on_map(l3)) continue;
adjust_space(l3, stroke_changes); adjust_space(l3, stroke_changes);
}
} }
cTerrain& ter = scenario.ter_types[terrain_type]; cTerrain& ter = scenario.ter_types[terrain_type];
@@ -2288,6 +2295,7 @@ void set_terrain(location l,ter_num_t terrain_type,stroke_ter_changes_t& stroke_
mouse_button_held = false; mouse_button_held = false;
return; return;
} }
if(!handle_special) return;
auto& signs = cur_area->sign_locs; auto& signs = cur_area->sign_locs;
auto iter = std::find(signs.begin(), signs.end(), l); auto iter = std::find(signs.begin(), signs.end(), l);
if(iter == signs.end()) { if(iter == signs.end()) {
@@ -2313,6 +2321,7 @@ void set_terrain(location l,ter_num_t terrain_type,stroke_ter_changes_t& stroke_
} }
// Town entrances in the outdoors: // Town entrances in the outdoors:
else if(ter.special == eTerSpec::TOWN_ENTRANCE && !editing_town){ else if(ter.special == eTerSpec::TOWN_ENTRANCE && !editing_town){
if(!handle_special) return;
// Let the designer know the terrain was placed: // Let the designer know the terrain was placed:
draw_terrain(); draw_terrain();
redraw_screen(); redraw_screen();

View File

@@ -23,7 +23,7 @@ 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();
void set_terrain(location l,ter_num_t terrain_type,stroke_ter_changes_t& stroke_changes); 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();
bool is_lava(short x,short y); bool is_lava(short x,short y);