* Levels a selected (rectangle) area of land * @param flags for this command type * @param tile end tile of area-drag * @param start_tile start tile of area drag * @param diagonal Whether to use the Orthogonal (false) or Diagonal (true) iterator. * @param LevelMode Mode of leveling \c LevelMode. * @return the cost of this operation or an error */
| 313 | * @return the cost of this operation or an error |
| 314 | */ |
| 315 | std::tuple<CommandCost, Money, TileIndex> CmdLevelLand(DoCommandFlags flags, TileIndex tile, TileIndex start_tile, bool diagonal, LevelMode lm) |
| 316 | { |
| 317 | if (start_tile >= Map::Size()) return { CMD_ERROR, 0, INVALID_TILE }; |
| 318 | |
| 319 | /* remember level height */ |
| 320 | uint oldh = TileHeight(start_tile); |
| 321 | |
| 322 | /* compute new height */ |
| 323 | uint h = oldh; |
| 324 | switch (lm) { |
| 325 | case LM_LEVEL: break; |
| 326 | case LM_RAISE: h++; break; |
| 327 | case LM_LOWER: h--; break; |
| 328 | default: return { CMD_ERROR, 0, INVALID_TILE }; |
| 329 | } |
| 330 | |
| 331 | /* Check range of destination height */ |
| 332 | if (h > _settings_game.construction.map_height_limit) return { CommandCost(oldh == 0 ? STR_ERROR_ALREADY_AT_SEA_LEVEL : STR_ERROR_TOO_HIGH), 0, INVALID_TILE }; |
| 333 | |
| 334 | Money money = GetAvailableMoneyForCommand(); |
| 335 | CommandCost cost(EXPENSES_CONSTRUCTION); |
| 336 | CommandCost last_error(lm == LM_LEVEL ? STR_ERROR_ALREADY_LEVELLED : INVALID_STRING_ID); |
| 337 | bool had_success = false; |
| 338 | |
| 339 | const Company *c = Company::GetIfValid(_current_company); |
| 340 | int limit = (c == nullptr ? INT32_MAX : GB(c->terraform_limit, 16, 16)); |
| 341 | if (limit == 0) return { CommandCost(STR_ERROR_TERRAFORM_LIMIT_REACHED), 0, INVALID_TILE }; |
| 342 | |
| 343 | TileIndex error_tile = INVALID_TILE; |
| 344 | std::unique_ptr<TileIterator> iter = TileIterator::Create(tile, start_tile, diagonal); |
| 345 | for (; *iter != INVALID_TILE; ++(*iter)) { |
| 346 | TileIndex t = *iter; |
| 347 | uint curh = TileHeight(t); |
| 348 | while (curh != h) { |
| 349 | CommandCost ret; |
| 350 | std::tie(ret, std::ignore, error_tile) = Command<CMD_TERRAFORM_LAND>::Do(DoCommandFlags{flags}.Reset(DoCommandFlag::Execute), t, SLOPE_N, curh <= h); |
| 351 | if (ret.Failed()) { |
| 352 | last_error = std::move(ret); |
| 353 | |
| 354 | /* Did we reach the limit? */ |
| 355 | if (last_error.GetErrorMessage() == STR_ERROR_TERRAFORM_LIMIT_REACHED) limit = 0; |
| 356 | break; |
| 357 | } |
| 358 | |
| 359 | if (flags.Test(DoCommandFlag::Execute)) { |
| 360 | money -= ret.GetCost(); |
| 361 | if (money < 0) { |
| 362 | return { cost, ret.GetCost(), error_tile }; |
| 363 | } |
| 364 | Command<CMD_TERRAFORM_LAND>::Do(flags, t, SLOPE_N, curh <= h); |
| 365 | } else { |
| 366 | /* When we're at the terraform limit we better bail (unneeded) testing as well. |
| 367 | * This will probably cause the terraforming cost to be underestimated, but only |
| 368 | * when it's near the terraforming limit. Even then, the estimation is |
| 369 | * completely off due to it basically counting terraforming double, so it being |
| 370 | * cut off earlier might even give a better estimate in some cases. */ |
| 371 | if (--limit <= 0) { |
| 372 | had_success = true; |
nothing calls this directly
no test coverage detected