diff --git a/src/terraform_cmd.cpp b/src/terraform_cmd.cpp --- a/src/terraform_cmd.cpp +++ b/src/terraform_cmd.cpp @@ -321,6 +321,86 @@ CommandCost CmdTerraformLand(TileIndex t /* Finally mark the dirty tiles dirty */ for (TileIndexSet::const_iterator it = ts.dirty_tiles.begin(); it != ts.dirty_tiles.end(); it++) { MarkTileDirtyByTile(*it); + + int height = TerraformGetHeightOfTile(&ts, *it); + + /* Now, if we alter the height of the map edge, we need to take care + * about repainting the affected areas outside map as well. + * Remember: + * Outside map, we assume that our landscape descends to + * height zero as fast as possible. + * Those simulated tiles (they don't exist as datastructure, + * only as concept in code) need to be repainted properly, + * otherwise we will get ugly glitches. + * + * Furthermore, note that we have to take care about the possibility, + * that landscape was higher before the change, + * so also tiles a bit outside need to be repainted. + */ + int x = TileX(*it); + int y = TileY(*it); + if (x == 0) { + if (y == 0) { + /* Height of the northern corner is altered. */ + for (int cx = 0; cx >= -height - 1; cx--) { + for (int cy = 0; cy >= -height - 1; cy--) { + /* This means, tiles in the sector north of that + * corner need to be repainted. + */ + if (cx + cy >= -height - 2) { + /* But only tiles that actually might have changed. */ + MarkTileDirtyByTileOutsideMap(cx, cy); + } + } + } + } else if (y < (int)MapMaxY()) { + for (int cx = 0; cx >= -height - 1; cx--) { + MarkTileDirtyByTileOutsideMap(cx, y); + } + } else { + for (int cx = 0; cx >= -height - 1; cx--) { + for (int cy = (int)MapMaxY(); cy <= (int)MapMaxY() + height + 1; cy++) { + if (cx + ((int)MapMaxY() - cy) >= -height - 2) { + MarkTileDirtyByTileOutsideMap(cx, cy); + } + } + } + } + } else if (x < (int)MapMaxX()) { + if (y == 0) { + for (int cy = 0; cy >= -height - 1; cy--) { + MarkTileDirtyByTileOutsideMap(x, cy); + } + } else if (y < (int)MapMaxY()) { + /* Nothing to be done here, we are inside the map. */ + } else { + for (int cy = (int)MapMaxY(); cy <= (int)MapMaxY() + height + 1; cy++) { + MarkTileDirtyByTileOutsideMap(x, cy); + } + } + } else { + if (y == 0) { + for (int cx = (int)MapMaxX(); cx <= (int)MapMaxX() + height + 1; cx++) { + for (int cy = 0; cy >= -height - 1; cy--) { + if (((int)MapMaxX() - cx) + cy >= -height - 2) { + MarkTileDirtyByTileOutsideMap(cx, cy); + } + } + } + } else if (y < (int)MapMaxY()) { + for (int cx = (int)MapMaxX(); cx <= (int)MapMaxX() + height + 1; cx++) { + MarkTileDirtyByTileOutsideMap(cx, y); + } + } else { + for (int cx = (int)MapMaxX(); cx <= (int)MapMaxX() + height + 1; cx++) { + for (int cy = (int)MapMaxY(); cy <= (int)MapMaxY() + height + 1; cy++) { + if (((int)MapMaxX() - cx) + ((int)MapMaxY() - cy) >= -height - 2) { + MarkTileDirtyByTileOutsideMap(cx, cy); + } + } + } + } + } } if (c != NULL) c->terraform_limit -= ts.tile_to_new_height.size() << 16; diff --git a/src/viewport.cpp b/src/viewport.cpp --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -2139,6 +2139,20 @@ void MarkTileDirtyByTile(TileIndex tile) ); } +void MarkTileDirtyByTileOutsideMap(int x, int y) +{ + Point pt = RemapCoords(x * TILE_SIZE, y * TILE_SIZE, GetTilePixelZOutsideMap(x, y)); + /* Since tiles painted outside the map don't contain buildings, trees, etc., + * this reduced area for repainting should suffice. If not, adjust the offsets + * used below. */ + MarkAllViewportsDirty( + pt.x - TILE_SIZE + 1, + pt.y, + pt.x + TILE_SIZE - 1, + pt.y + TILE_SIZE + TILE_HEIGHT - 1 + ); +} + /** * Marks the selected tiles as dirty. * diff --git a/src/viewport_func.h b/src/viewport_func.h --- a/src/viewport_func.h +++ b/src/viewport_func.h @@ -80,6 +80,7 @@ extern Point _tile_fract_coords; void MarkTileDirtyByTile(TileIndex tile); int GetRowAtTile(int viewport_y, Point tile, bool bridge_correct); +void MarkTileDirtyByTileOutsideMap(int x, int y); Point GetViewportStationMiddle(const ViewPort *vp, const Station *st);