* Terraform the north corner of a tile to a specific height. * * @param ts TerraformerState. * @param tile Tile. * @param height Aimed height. * @return Error code or cost. */
| 97 | * @return Error code or cost. |
| 98 | */ |
| 99 | static std::tuple<CommandCost, TileIndex> TerraformTileHeight(TerraformerState *ts, TileIndex tile, int height) |
| 100 | { |
| 101 | assert(tile < Map::Size()); |
| 102 | |
| 103 | /* Check range of destination height */ |
| 104 | if (height < 0) return { CommandCost(STR_ERROR_ALREADY_AT_SEA_LEVEL), INVALID_TILE }; |
| 105 | if (height > _settings_game.construction.map_height_limit) return { CommandCost(STR_ERROR_TOO_HIGH), INVALID_TILE }; |
| 106 | |
| 107 | /* |
| 108 | * Check if the terraforming has any effect. |
| 109 | * This can only be true, if multiple corners of the start-tile are terraformed (i.e. the terraforming is done by towns/industries etc.). |
| 110 | * In this case the terraforming should fail. (Don't know why.) |
| 111 | */ |
| 112 | if (height == TerraformGetHeightOfTile(ts, tile)) return { CMD_ERROR, INVALID_TILE }; |
| 113 | |
| 114 | /* Check "too close to edge of map". Only possible when freeform-edges is off. */ |
| 115 | uint x = TileX(tile); |
| 116 | uint y = TileY(tile); |
| 117 | if (!_settings_game.construction.freeform_edges && ((x <= 1) || (y <= 1) || (x >= Map::MaxX() - 1) || (y >= Map::MaxY() - 1))) { |
| 118 | /* |
| 119 | * Determine a sensible error tile |
| 120 | */ |
| 121 | if (x == 1) x = 0; |
| 122 | if (y == 1) y = 0; |
| 123 | return { CommandCost(STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP), TileXY(x, y) }; |
| 124 | } |
| 125 | |
| 126 | /* Mark incident tiles that are involved in the terraforming. */ |
| 127 | TerraformAddDirtyTileAround(ts, tile); |
| 128 | |
| 129 | /* Store the height modification */ |
| 130 | TerraformSetHeightOfTile(ts, tile, height); |
| 131 | |
| 132 | CommandCost total_cost(EXPENSES_CONSTRUCTION); |
| 133 | |
| 134 | /* Increment cost */ |
| 135 | total_cost.AddCost(_price[PR_TERRAFORM]); |
| 136 | |
| 137 | /* Recurse to neighboured corners if height difference is larger than 1 */ |
| 138 | for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) { |
| 139 | TileIndex neighbour_tile = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDiagDir(dir)); |
| 140 | |
| 141 | /* Not using IsValidTile as we want to also change MP_VOID tiles, which IsValidTile excludes. */ |
| 142 | if (neighbour_tile == INVALID_TILE) continue; |
| 143 | |
| 144 | /* Get TileHeight of neighboured tile as of current terraform progress */ |
| 145 | int r = TerraformGetHeightOfTile(ts, neighbour_tile); |
| 146 | int height_diff = height - r; |
| 147 | |
| 148 | /* Is the height difference to the neighboured corner greater than 1? */ |
| 149 | if (abs(height_diff) > 1) { |
| 150 | /* Terraform the neighboured corner. The resulting height difference should be 1. */ |
| 151 | height_diff += (height_diff < 0 ? 1 : -1); |
| 152 | auto [cost, err_tile] = TerraformTileHeight(ts, neighbour_tile, r + height_diff); |
| 153 | if (cost.Failed()) return { cost, err_tile }; |
| 154 | total_cost.AddCost(cost.GetCost()); |
| 155 | } |
| 156 | } |
no test coverage detected