* Plant a tree. * @param flags type of operation * @param tile end tile of area-drag * @param start_tile start tile of area-drag of tree plantation * @param tree_to_plant tree type, TREE_INVALID means random. * @param diagonal Whether to use the Orthogonal (false) or Diagonal (true) iterator. * @return the cost of this operation or an error */
| 502 | * @return the cost of this operation or an error |
| 503 | */ |
| 504 | CommandCost CmdPlantTree(DoCommandFlags flags, TileIndex tile, TileIndex start_tile, uint8_t tree_to_plant, bool diagonal) |
| 505 | { |
| 506 | StringID msg = INVALID_STRING_ID; |
| 507 | CommandCost cost(EXPENSES_OTHER); |
| 508 | |
| 509 | if (start_tile >= Map::Size()) return CMD_ERROR; |
| 510 | /* Check the tree type within the current climate */ |
| 511 | if (tree_to_plant != TREE_INVALID && !IsInsideBS(tree_to_plant, _tree_base_by_landscape[to_underlying(_settings_game.game_creation.landscape)], _tree_count_by_landscape[to_underlying(_settings_game.game_creation.landscape)])) return CMD_ERROR; |
| 512 | |
| 513 | Company *c = (_game_mode != GM_EDITOR) ? Company::GetIfValid(_current_company) : nullptr; |
| 514 | int limit = (c == nullptr ? INT32_MAX : GB(c->tree_limit, 16, 16)); |
| 515 | |
| 516 | std::unique_ptr<TileIterator> iter = TileIterator::Create(tile, start_tile, diagonal); |
| 517 | for (; *iter != INVALID_TILE; ++(*iter)) { |
| 518 | TileIndex current_tile = *iter; |
| 519 | switch (GetTileType(current_tile)) { |
| 520 | case MP_TREES: |
| 521 | /* no more space for trees? */ |
| 522 | if (GetTreeCount(current_tile) == 4) { |
| 523 | msg = STR_ERROR_TREE_ALREADY_HERE; |
| 524 | continue; |
| 525 | } |
| 526 | |
| 527 | /* Test tree limit. */ |
| 528 | if (--limit < 1) { |
| 529 | msg = STR_ERROR_TREE_PLANT_LIMIT_REACHED; |
| 530 | break; |
| 531 | } |
| 532 | |
| 533 | if (flags.Test(DoCommandFlag::Execute)) { |
| 534 | AddTreeCount(current_tile, 1); |
| 535 | MarkTileDirtyByTile(current_tile); |
| 536 | if (c != nullptr) c->tree_limit -= 1 << 16; |
| 537 | } |
| 538 | /* 2x as expensive to add more trees to an existing tile */ |
| 539 | cost.AddCost(_price[PR_BUILD_TREES] * 2); |
| 540 | break; |
| 541 | |
| 542 | case MP_WATER: |
| 543 | if (!IsCoast(current_tile) || IsSlopeWithOneCornerRaised(GetTileSlope(current_tile))) { |
| 544 | msg = STR_ERROR_CAN_T_BUILD_ON_WATER; |
| 545 | continue; |
| 546 | } |
| 547 | [[fallthrough]]; |
| 548 | |
| 549 | case MP_CLEAR: { |
| 550 | if (IsBridgeAbove(current_tile)) { |
| 551 | msg = STR_ERROR_SITE_UNSUITABLE; |
| 552 | continue; |
| 553 | } |
| 554 | |
| 555 | TreeType treetype = (TreeType)tree_to_plant; |
| 556 | /* Be a bit picky about which trees go where. */ |
| 557 | if (_settings_game.game_creation.landscape == LandscapeType::Tropic && treetype != TREE_INVALID && ( |
| 558 | /* No cacti outside the desert */ |
| 559 | (treetype == TREE_CACTUS && GetTropicZone(current_tile) != TROPICZONE_DESERT) || |
| 560 | /* No rainforest trees outside the rainforest, except in the editor mode where it makes those tiles rainforest tile */ |
| 561 | (IsInsideMM(treetype, TREE_RAINFOREST, TREE_CACTUS) && GetTropicZone(current_tile) != TROPICZONE_RAINFOREST && _game_mode != GM_EDITOR) || |
nothing calls this directly
no test coverage detected