* Perform a 9x9 tiles circular search from the center of the town * in order to find a free tile to place a statue * @param t town to search in * @param flags Used to check if the statue must be built or not. * @return Empty cost or an error. */
| 3491 | * @return Empty cost or an error. |
| 3492 | */ |
| 3493 | static CommandCost TownActionBuildStatue(Town *t, DoCommandFlags flags) |
| 3494 | { |
| 3495 | if (!Object::CanAllocateItem()) return CommandCost(STR_ERROR_TOO_MANY_OBJECTS); |
| 3496 | |
| 3497 | static const int STATUE_NUMBER_INNER_TILES = 25; // Number of tiles int the center of the city, where we try to protect houses. |
| 3498 | |
| 3499 | TileIndex best_position = INVALID_TILE; ///< Best position found so far. |
| 3500 | uint tile_count = 0; ///< Number of tiles tried. |
| 3501 | for (auto tile : SpiralTileSequence(t->xy, 9)) { |
| 3502 | tile_count++; |
| 3503 | |
| 3504 | /* Statues can be build on slopes, just like houses. Only the steep slopes is a no go. */ |
| 3505 | if (IsSteepSlope(GetTileSlope(tile))) continue; |
| 3506 | /* Don't build statues under bridges. */ |
| 3507 | if (IsBridgeAbove(tile)) continue; |
| 3508 | |
| 3509 | /* A clear-able open space is always preferred. */ |
| 3510 | if ((IsTileType(tile, MP_CLEAR) || IsTileType(tile, MP_TREES)) && CheckClearTile(tile)) { |
| 3511 | best_position = tile; |
| 3512 | break; |
| 3513 | } |
| 3514 | |
| 3515 | bool house = IsTileType(tile, MP_HOUSE); |
| 3516 | |
| 3517 | /* Searching inside the inner circle. */ |
| 3518 | if (tile_count <= STATUE_NUMBER_INNER_TILES) { |
| 3519 | /* Save first house in inner circle. */ |
| 3520 | if (house && best_position == INVALID_TILE && CheckClearTile(tile)) { |
| 3521 | best_position = tile; |
| 3522 | } |
| 3523 | |
| 3524 | /* If we have reached the end of the inner circle, and have a saved house, terminate the search. */ |
| 3525 | if (tile_count == STATUE_NUMBER_INNER_TILES && best_position != INVALID_TILE) break; |
| 3526 | } |
| 3527 | |
| 3528 | /* Searching outside the circle, just pick the first possible spot. */ |
| 3529 | if (!house || !CheckClearTile(tile)) continue; |
| 3530 | best_position = tile; |
| 3531 | break; |
| 3532 | } |
| 3533 | if (best_position == INVALID_TILE) return CommandCost(STR_ERROR_STATUE_NO_SUITABLE_PLACE); |
| 3534 | |
| 3535 | if (flags.Test(DoCommandFlag::Execute)) { |
| 3536 | Backup<CompanyID> cur_company(_current_company, OWNER_NONE); |
| 3537 | Command<CMD_LANDSCAPE_CLEAR>::Do(DoCommandFlag::Execute, best_position); |
| 3538 | cur_company.Restore(); |
| 3539 | BuildObject(OBJECT_STATUE, best_position, _current_company, t); |
| 3540 | t->statues.Set(_current_company); // Once found and built, "inform" the Town. |
| 3541 | MarkTileDirtyByTile(best_position); |
| 3542 | } |
| 3543 | return CommandCost(); |
| 3544 | } |
| 3545 | |
| 3546 | /** |
| 3547 | * Perform the "fund new buildings" town action. |
nothing calls this directly
no test coverage detected