OpenTTD Source 20250312-master-gcdcc6b491d
tree_cmd.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
7
10#include "stdafx.h"
11#include "clear_map.h"
12#include "landscape.h"
13#include "tree_map.h"
14#include "viewport_func.h"
15#include "command_func.h"
16#include "town.h"
17#include "genworld.h"
18#include "clear_func.h"
19#include "company_func.h"
20#include "sound_func.h"
21#include "water.h"
22#include "company_base.h"
24#include "core/random_func.hpp"
25#include "newgrf_generic.h"
27#include "tree_cmd.h"
28#include "landscape_cmd.h"
29
30#include "table/strings.h"
31#include "table/tree_land.h"
32#include "table/clear_land.h"
33
34#include "safeguards.h"
35
46
54
57
58static const uint16_t DEFAULT_TREE_STEPS = 1000;
59static const uint16_t DEFAULT_RAINFOREST_TREE_STEPS = 15000;
60static const uint16_t EDITOR_TREE_DIV = 5;
61
70static bool CanPlantTreesOnTile(TileIndex tile, bool allow_desert)
71{
72 switch (GetTileType(tile)) {
73 case MP_WATER:
74 return !IsBridgeAbove(tile) && IsCoast(tile) && !IsSlopeWithOneCornerRaised(GetTileSlope(tile));
75
76 case MP_CLEAR:
77 return !IsBridgeAbove(tile) && !IsClearGround(tile, CLEAR_FIELDS) && !IsClearGround(tile, CLEAR_ROCKS) &&
78 (allow_desert || !IsClearGround(tile, CLEAR_DESERT));
79
80 default: return false;
81 }
82}
83
95static void PlantTreesOnTile(TileIndex tile, TreeType treetype, uint count, TreeGrowthStage growth)
96{
97 assert(treetype != TREE_INVALID);
98 assert(CanPlantTreesOnTile(tile, true));
99
100 TreeGround ground;
101 uint density = 3;
102
103 switch (GetTileType(tile)) {
104 case MP_WATER:
105 ground = TREE_GROUND_SHORE;
107 break;
108
109 case MP_CLEAR: {
110 ClearGround clearground = GetClearGround(tile);
111 if (IsSnowTile(tile)) {
113 } else {
114 switch (clearground) {
115 case CLEAR_GRASS: ground = TREE_GROUND_GRASS; break;
116 case CLEAR_ROUGH: ground = TREE_GROUND_ROUGH; break;
117 default: ground = TREE_GROUND_SNOW_DESERT; break;
118 }
119 }
120 if (clearground != CLEAR_ROUGH) density = GetClearDensity(tile);
121 break;
122 }
123
124 default: NOT_REACHED();
125 }
126
127 MakeTree(tile, treetype, count, growth, ground, density);
128}
129
141static TreeType GetRandomTreeType(TileIndex tile, uint seed)
142{
144 case LandscapeType::Temperate:
145 return static_cast<TreeType>(seed * TREE_COUNT_TEMPERATE / 256 + TREE_TEMPERATE);
146
147 case LandscapeType::Arctic:
148 return static_cast<TreeType>(seed * TREE_COUNT_SUB_ARCTIC / 256 + TREE_SUB_ARCTIC);
149
150 case LandscapeType::Tropic:
151 switch (GetTropicZone(tile)) {
152 case TROPICZONE_NORMAL: return static_cast<TreeType>(seed * TREE_COUNT_SUB_TROPICAL / 256 + TREE_SUB_TROPICAL);
153 case TROPICZONE_DESERT: return static_cast<TreeType>((seed > 12) ? TREE_INVALID : TREE_CACTUS);
154 default: return static_cast<TreeType>(seed * TREE_COUNT_RAINFOREST / 256 + TREE_RAINFOREST);
155 }
156
157 default:
158 return static_cast<TreeType>(seed * TREE_COUNT_TOYLAND / 256 + TREE_TOYLAND);
159 }
160}
161
171static void PlaceTree(TileIndex tile, uint32_t r)
172{
173 TreeType tree = GetRandomTreeType(tile, GB(r, 24, 8));
174
175 if (tree != TREE_INVALID) {
176 PlantTreesOnTile(tile, tree, GB(r, 22, 2), static_cast<TreeGrowthStage>(std::min<uint8_t>(GB(r, 16, 3), 6)));
178
179 /* Rerandomize ground, if neither snow nor shore */
180 TreeGround ground = GetTreeGround(tile);
181 if (ground != TREE_GROUND_SNOW_DESERT && ground != TREE_GROUND_ROUGH_SNOW && ground != TREE_GROUND_SHORE) {
182 SetTreeGroundDensity(tile, (TreeGround)GB(r, 28, 1), 3);
183 }
184 }
185}
186
188 int amplitude;
189 float phase;
190 int frequency;
191};
192
200static void CreateStarShapedPolygon(int radius, std::span<const BlobHarmonic> harmonics, std::span<Point> shape)
201{
202 float theta = 0;
203 float step = (M_PI * 2) / std::size(shape);
204
205 /* Divide a circle into a number of equally spaced divisions. */
206 for (Point &vertex : shape) {
207
208 /* Add up the values of each harmonic at this segment.*/
209 float deviation = std::accumulate(std::begin(harmonics), std::end(harmonics), 0.f, [theta](float d, const BlobHarmonic &harmonic) -> float {
210 return d + sinf((theta + harmonic.phase) * harmonic.frequency) * harmonic.amplitude;
211 });
212
213 /* Smooth out changes. */
214 float adjusted_radius = (radius / 2.f) + (deviation / 2);
215
216 /* Add to the final polygon. */
217 vertex.x = cosf(theta) * adjusted_radius;
218 vertex.y = sinf(theta) * adjusted_radius;
219
220 /* Proceed to the next segment. */
221 theta += step;
222 }
223}
224
231static void CreateRandomStarShapedPolygon(int radius, std::span<Point> shape)
232{
233 /* Valid values for the phase of blob harmonics are between 0 and Tau. we can get a value in the correct range
234 * from Random() by dividing the maximum possible value by the desired maximum, and then dividing the random
235 * value by the result. */
236 static constexpr float PHASE_DIVISOR = static_cast<float>(INT32_MAX / M_PI * 2);
237
238 /* These values are ones found in testing that result in suitable-looking polygons that did not self-intersect
239 * and fit within a square of radius * radius dimensions. */
240 std::initializer_list<BlobHarmonic> harmonics = {
241 {radius / 2, Random() / PHASE_DIVISOR, 1},
242 {radius / 4, Random() / PHASE_DIVISOR, 2},
243 {radius / 8, Random() / PHASE_DIVISOR, 3},
244 {radius / 16, Random() / PHASE_DIVISOR, 4},
245 };
246
247 CreateStarShapedPolygon(radius, harmonics, shape);
248}
249
259static bool IsPointInTriangle(int x, int y, const Point &v1, const Point &v2, const Point &v3)
260{
261 const int s = ((v1.x - v3.x) * (y - v3.y)) - ((v1.y - v3.y) * (x - v3.x));
262 const int t = ((v2.x - v1.x) * (y - v1.y)) - ((v2.y - v1.y) * (x - v1.x));
263
264 if ((s < 0) != (t < 0) && s != 0 && t != 0) return false;
265
266 const int d = (v3.x - v2.x) * (y - v2.y) - (v3.y - v2.y) * (x - v2.x);
267 return (d < 0) == (s + t <= 0);
268}
269
278static bool IsPointInStarShapedPolygon(int x, int y, std::span<Point> shape)
279{
280 for (auto it = std::begin(shape); it != std::end(shape); /* nothing */) {
281 const Point &v1 = *it;
282 ++it;
283 const Point &v2 = (it == std::end(shape)) ? shape.front() : *it;
284
285 if (IsPointInTriangle(x, y, v1, v2, {0, 0})) return true;
286 }
287
288 return false;
289}
290
297static void PlaceTreeGroups(uint num_groups)
298{
299 static constexpr uint GROVE_SEGMENTS = 16;
300 static constexpr uint GROVE_RADIUS = 16;
301
302 /* Shape in which trees may be contained. Array is here to reduce allocations. */
303 std::array<Point, GROVE_SEGMENTS> grove;
304
305 do {
306 TileIndex center_tile = RandomTile();
307
308 CreateRandomStarShapedPolygon(GROVE_RADIUS, grove);
309
310 for (uint i = 0; i < DEFAULT_TREE_STEPS; i++) {
312
313 uint32_t r = Random();
314 int x = GB(r, 0, 5) - GROVE_RADIUS;
315 int y = GB(r, 8, 5) - GROVE_RADIUS;
316 TileIndex cur_tile = TileAddWrap(center_tile, x, y);
317
318 if (cur_tile == INVALID_TILE) continue;
319 if (!CanPlantTreesOnTile(cur_tile, true)) continue;
320 if (!IsPointInStarShapedPolygon(x, y, grove)) continue;
321
322 PlaceTree(cur_tile, r);
323 }
324
325 } while (--num_groups);
326}
327
337static void PlaceTreeAtSameHeight(TileIndex tile, int height)
338{
339 for (uint i = 0; i < DEFAULT_TREE_STEPS; i++) {
340 uint32_t r = Random();
341 int x = GB(r, 0, 5) - 16;
342 int y = GB(r, 8, 5) - 16;
343 TileIndex cur_tile = TileAddWrap(tile, x, y);
344 if (cur_tile == INVALID_TILE) continue;
345
346 /* Keep in range of the existing tree */
347 if (abs(x) + abs(y) > 16) continue;
348
349 /* Clear tile, no farm-tiles or rocks */
350 if (!CanPlantTreesOnTile(cur_tile, true)) continue;
351
352 /* Not too much height difference */
353 if (Delta(GetTileZ(cur_tile), height) > 2) continue;
354
355 /* Place one tree and quit */
356 PlaceTree(cur_tile, r);
357 break;
358 }
359}
360
367{
368 int i, j, ht;
369 uint8_t max_height = _settings_game.construction.map_height_limit;
370
372 if (_game_mode == GM_EDITOR) i /= EDITOR_TREE_DIV;
373 do {
374 uint32_t r = Random();
375 TileIndex tile = RandomTileSeed(r);
376
378
379 if (CanPlantTreesOnTile(tile, true)) {
380 PlaceTree(tile, r);
382
383 /* Place a number of trees based on the tile height.
384 * This gives a cool effect of multiple trees close together.
385 * It is almost real life ;) */
386 ht = GetTileZ(tile);
387 /* The higher we get, the more trees we plant */
388 j = GetTileZ(tile) * 2;
389 /* Above snowline more trees! */
390 if (_settings_game.game_creation.landscape == LandscapeType::Arctic && ht > GetSnowLine()) j *= 3;
391 /* Scale generation by maximum map height. */
392 if (max_height > MAP_HEIGHT_LIMIT_ORIGINAL) j = j * MAP_HEIGHT_LIMIT_ORIGINAL / max_height;
393 while (j--) {
394 PlaceTreeAtSameHeight(tile, ht);
395 }
396 }
397 } while (--i);
398
399 /* place extra trees at rainforest area */
400 if (_settings_game.game_creation.landscape == LandscapeType::Tropic) {
402 if (_game_mode == GM_EDITOR) i /= EDITOR_TREE_DIV;
403
404 do {
405 uint32_t r = Random();
406 TileIndex tile = RandomTileSeed(r);
407
409
410 if (GetTropicZone(tile) == TROPICZONE_RAINFOREST && CanPlantTreesOnTile(tile, false)) {
411 PlaceTree(tile, r);
412 }
413 } while (--i);
414 }
415}
416
429uint PlaceTreeGroupAroundTile(TileIndex tile, TreeType treetype, uint radius, uint count, bool set_zone)
430{
431 assert(_game_mode == GM_EDITOR); // Due to InteractiveRandom being used in this function
432 assert(treetype < TREE_TOYLAND + TREE_COUNT_TOYLAND);
433 const bool allow_desert = treetype == TREE_CACTUS;
434 uint planted = 0;
435
436 for (; count > 0; count--) {
437 /* Simple quasi-normal distribution with range [-radius; radius) */
438 auto mkcoord = [&]() -> int32_t {
439 const uint32_t rand = InteractiveRandom();
440 const int32_t dist = GB<int32_t>(rand, 0, 8) + GB<int32_t>(rand, 8, 8) + GB<int32_t>(rand, 16, 8) + GB<int32_t>(rand, 24, 8);
441 const int32_t scu = dist * radius / 512;
442 return scu - radius;
443 };
444 const int32_t xofs = mkcoord();
445 const int32_t yofs = mkcoord();
446 const TileIndex tile_to_plant = TileAddWrap(tile, xofs, yofs);
447 if (tile_to_plant != INVALID_TILE) {
448 if (IsTileType(tile_to_plant, MP_TREES) && GetTreeCount(tile_to_plant) < 4) {
449 AddTreeCount(tile_to_plant, 1);
451 MarkTileDirtyByTile(tile_to_plant, 0);
452 planted++;
453 } else if (CanPlantTreesOnTile(tile_to_plant, allow_desert)) {
454 PlantTreesOnTile(tile_to_plant, treetype, 0, TreeGrowthStage::Grown);
455 MarkTileDirtyByTile(tile_to_plant, 0);
456 planted++;
457 }
458 }
459 }
460
461 if (set_zone && IsInsideMM(treetype, TREE_RAINFOREST, TREE_CACTUS)) {
462 for (TileIndex t : TileArea(tile).Expand(radius)) {
463 if (GetTileType(t) != MP_VOID && DistanceSquare(tile, t) < radius * radius) SetTropicZone(t, TROPICZONE_RAINFOREST);
464 }
465 }
466
467 return planted;
468}
469
477{
478 uint i, total;
479
481
483 case TP_ORIGINAL: i = _settings_game.game_creation.landscape == LandscapeType::Arctic ? 15 : 6; break;
484 case TP_IMPROVED: i = _settings_game.game_creation.landscape == LandscapeType::Arctic ? 4 : 2; break;
485 default: NOT_REACHED();
486 }
487
490 total *= i;
491 uint num_groups = (_settings_game.game_creation.landscape != LandscapeType::Toyland) ? Map::ScaleBySize(GB(Random(), 0, 5) + 25) : 0;
492 total += num_groups * DEFAULT_TREE_STEPS;
494
495 if (num_groups != 0) PlaceTreeGroups(num_groups);
496
497 for (; i != 0; i--) {
499 }
500}
501
511CommandCost CmdPlantTree(DoCommandFlags flags, TileIndex tile, TileIndex start_tile, uint8_t tree_to_plant, bool diagonal)
512{
515
516 if (start_tile >= Map::Size()) return CMD_ERROR;
517 /* Check the tree type within the current climate */
518 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;
519
520 Company *c = (_game_mode != GM_EDITOR) ? Company::GetIfValid(_current_company) : nullptr;
521 int limit = (c == nullptr ? INT32_MAX : GB(c->tree_limit, 16, 16));
522
523 std::unique_ptr<TileIterator> iter = TileIterator::Create(tile, start_tile, diagonal);
524 for (; *iter != INVALID_TILE; ++(*iter)) {
525 TileIndex current_tile = *iter;
526 switch (GetTileType(current_tile)) {
527 case MP_TREES:
528 /* no more space for trees? */
529 if (GetTreeCount(current_tile) == 4) {
530 msg = STR_ERROR_TREE_ALREADY_HERE;
531 continue;
532 }
533
534 /* Test tree limit. */
535 if (--limit < 1) {
536 msg = STR_ERROR_TREE_PLANT_LIMIT_REACHED;
537 break;
538 }
539
540 if (flags.Test(DoCommandFlag::Execute)) {
541 AddTreeCount(current_tile, 1);
542 MarkTileDirtyByTile(current_tile);
543 if (c != nullptr) c->tree_limit -= 1 << 16;
544 }
545 /* 2x as expensive to add more trees to an existing tile */
546 cost.AddCost(_price[PR_BUILD_TREES] * 2);
547 break;
548
549 case MP_WATER:
550 if (!IsCoast(current_tile) || IsSlopeWithOneCornerRaised(GetTileSlope(current_tile))) {
551 msg = STR_ERROR_CAN_T_BUILD_ON_WATER;
552 continue;
553 }
554 [[fallthrough]];
555
556 case MP_CLEAR: {
557 if (IsBridgeAbove(current_tile)) {
558 msg = STR_ERROR_SITE_UNSUITABLE;
559 continue;
560 }
561
562 TreeType treetype = (TreeType)tree_to_plant;
563 /* Be a bit picky about which trees go where. */
564 if (_settings_game.game_creation.landscape == LandscapeType::Tropic && treetype != TREE_INVALID && (
565 /* No cacti outside the desert */
566 (treetype == TREE_CACTUS && GetTropicZone(current_tile) != TROPICZONE_DESERT) ||
567 /* No rainforest trees outside the rainforest, except in the editor mode where it makes those tiles rainforest tile */
568 (IsInsideMM(treetype, TREE_RAINFOREST, TREE_CACTUS) && GetTropicZone(current_tile) != TROPICZONE_RAINFOREST && _game_mode != GM_EDITOR) ||
569 /* And no subtropical trees in the desert/rainforest */
570 (IsInsideMM(treetype, TREE_SUB_TROPICAL, TREE_TOYLAND) && GetTropicZone(current_tile) != TROPICZONE_NORMAL))) {
571 msg = STR_ERROR_TREE_WRONG_TERRAIN_FOR_TREE_TYPE;
572 continue;
573 }
574
575 /* Test tree limit. */
576 if (--limit < 1) {
577 msg = STR_ERROR_TREE_PLANT_LIMIT_REACHED;
578 break;
579 }
580
581 if (IsTileType(current_tile, MP_CLEAR)) {
582 /* Remove fields or rocks. Note that the ground will get barrened */
583 switch (GetClearGround(current_tile)) {
584 case CLEAR_FIELDS:
585 case CLEAR_ROCKS: {
586 CommandCost ret = Command<CMD_LANDSCAPE_CLEAR>::Do(flags, current_tile);
587 if (ret.Failed()) return ret;
588 cost.AddCost(ret);
589 break;
590 }
591
592 default: break;
593 }
594 }
595
596 if (_game_mode != GM_EDITOR && Company::IsValidID(_current_company)) {
598 if (t != nullptr) ChangeTownRating(t, RATING_TREE_UP_STEP, RATING_TREE_MAXIMUM, flags);
599 }
600
601 if (flags.Test(DoCommandFlag::Execute)) {
602 if (treetype == TREE_INVALID) {
603 treetype = GetRandomTreeType(current_tile, GB(Random(), 24, 8));
604 if (treetype == TREE_INVALID) treetype = TREE_CACTUS;
605 }
606
607 /* Plant full grown trees in scenario editor */
608 PlantTreesOnTile(current_tile, treetype, 0, _game_mode == GM_EDITOR ? TreeGrowthStage::Grown : TreeGrowthStage::Growing1);
609 MarkTileDirtyByTile(current_tile);
610 if (c != nullptr) c->tree_limit -= 1 << 16;
611
612 /* When planting rainforest-trees, set tropiczone to rainforest in editor. */
613 if (_game_mode == GM_EDITOR && IsInsideMM(treetype, TREE_RAINFOREST, TREE_CACTUS)) {
615 }
616 }
617 cost.AddCost(_price[PR_BUILD_TREES]);
618 break;
619 }
620
621 default:
622 msg = STR_ERROR_SITE_UNSUITABLE;
623 break;
624 }
625
626 /* Tree limit used up? No need to check more. */
627 if (limit < 0) break;
628 }
629
630 if (cost.GetCost() == 0) {
631 return CommandCost(msg);
632 } else {
633 return cost;
634 }
635}
636
638 uint8_t x, y;
639};
640
641static void DrawTile_Trees(TileInfo *ti)
642{
643 switch (GetTreeGround(ti->tile)) {
644 case TREE_GROUND_SHORE: DrawShoreTile(ti->tileh); break;
645 case TREE_GROUND_GRASS: DrawClearLandTile(ti, GetTreeDensity(ti->tile)); break;
646 case TREE_GROUND_ROUGH: DrawHillyLandTile(ti); break;
647 default: DrawGroundSprite(_clear_land_sprites_snow_desert[GetTreeDensity(ti->tile)] + SlopeToSpriteOffset(ti->tileh), PAL_NONE); break;
648 }
649
650 /* Do not draw trees when the invisible trees setting is set */
651 if (IsInvisibilitySet(TO_TREES)) return;
652
653 uint tmp = CountBits(ti->tile.base() + ti->x + ti->y);
654 uint index = GB(tmp, 0, 2) + (GetTreeType(ti->tile) << 2);
655
656 /* different tree styles above one of the grounds */
658 GetTreeDensity(ti->tile) >= 2 &&
659 IsInsideMM(index, TREE_SUB_ARCTIC << 2, TREE_RAINFOREST << 2)) {
660 index += 164 - (TREE_SUB_ARCTIC << 2);
661 }
662
663 assert(index < lengthof(_tree_layout_sprite));
664
665 const PalSpriteID *s = _tree_layout_sprite[index];
666 const TreePos *d = _tree_layout_xy[GB(tmp, 2, 2)];
667
668 /* combine trees into one sprite object */
670
671 TreeListEnt te[4];
672
673 /* put the trees to draw in a list */
674 uint trees = GetTreeCount(ti->tile);
675
676 for (uint i = 0; i < trees; i++) {
677 SpriteID sprite = s[0].sprite + (i == trees - 1 ? static_cast<uint>(GetTreeGrowth(ti->tile)) : 3);
678 PaletteID pal = s[0].pal;
679
680 te[i].sprite = sprite;
681 te[i].pal = pal;
682 te[i].x = d->x;
683 te[i].y = d->y;
684 s++;
685 d++;
686 }
687
688 /* draw them in a sorted way */
689 int z = ti->z + GetSlopeMaxPixelZ(ti->tileh) / 2;
690
691 for (; trees > 0; trees--) {
692 uint min = te[0].x + te[0].y;
693 uint mi = 0;
694
695 for (uint i = 1; i < trees; i++) {
696 if ((uint)(te[i].x + te[i].y) < min) {
697 min = te[i].x + te[i].y;
698 mi = i;
699 }
700 }
701
702 AddSortableSpriteToDraw(te[mi].sprite, te[mi].pal, ti->x + te[mi].x, ti->y + te[mi].y, 16 - te[mi].x, 16 - te[mi].y, 0x30, z, IsTransparencySet(TO_TREES), -te[mi].x, -te[mi].y);
703
704 /* replace the removed one with the last one */
705 te[mi] = te[trees - 1];
706 }
707
709}
710
711
712static int GetSlopePixelZ_Trees(TileIndex tile, uint x, uint y, bool)
713{
714 auto [tileh, z] = GetTilePixelSlope(tile);
715
716 return z + GetPartialPixelZ(x & 0xF, y & 0xF, tileh);
717}
718
719static Foundation GetFoundation_Trees(TileIndex, Slope)
720{
721 return FOUNDATION_NONE;
722}
723
724static CommandCost ClearTile_Trees(TileIndex tile, DoCommandFlags flags)
725{
726 uint num;
727
730 if (t != nullptr) ChangeTownRating(t, RATING_TREE_DOWN_STEP, RATING_TREE_MINIMUM, flags);
731 }
732
733 num = GetTreeCount(tile);
734 if (IsInsideMM(GetTreeType(tile), TREE_RAINFOREST, TREE_CACTUS)) num *= 4;
735
736 if (flags.Test(DoCommandFlag::Execute)) DoClearSquare(tile);
737
738 return CommandCost(EXPENSES_CONSTRUCTION, num * _price[PR_CLEAR_TREES]);
739}
740
741static void GetTileDesc_Trees(TileIndex tile, TileDesc &td)
742{
743 TreeType tt = GetTreeType(tile);
744
746 td.str = STR_LAI_TREE_NAME_RAINFOREST;
747 } else {
748 td.str = tt == TREE_CACTUS ? STR_LAI_TREE_NAME_CACTUS_PLANTS : STR_LAI_TREE_NAME_TREES;
749 }
750
751 td.owner[0] = GetTileOwner(tile);
752}
753
754static void TileLoopTreesDesert(TileIndex tile)
755{
756 switch (GetTropicZone(tile)) {
761 }
762 break;
763
765 static const SoundFx forest_sounds[] = {
770 };
771 uint32_t r = Random();
772
773 if (Chance16I(1, 200, r) && _settings_client.sound.ambient) SndPlayTileFx(forest_sounds[GB(r, 16, 2)], tile);
774 break;
775 }
776
777 default: break;
778 }
779}
780
781static void TileLoopTreesAlps(TileIndex tile)
782{
783 int k = GetTileZ(tile) - GetSnowLine() + 1;
784
785 if (k < 0) {
786 switch (GetTreeGround(tile)) {
789 default: return;
790 }
791 } else {
792 uint density = std::min<uint>(k, 3);
793
796 SetTreeGroundDensity(tile, tg, density);
797 } else if (GetTreeDensity(tile) != density) {
798 SetTreeGroundDensity(tile, GetTreeGround(tile), density);
799 } else {
800 if (GetTreeDensity(tile) == 3) {
801 uint32_t r = Random();
802 if (Chance16I(1, 200, r) && _settings_client.sound.ambient) {
803 SndPlayTileFx((r & 0x80000000) ? SND_39_ARCTIC_SNOW_2 : SND_34_ARCTIC_SNOW_1, tile);
804 }
805 }
806 return;
807 }
808 }
810}
811
812static bool CanPlantExtraTrees(TileIndex tile)
813{
814 return ((_settings_game.game_creation.landscape == LandscapeType::Tropic && GetTropicZone(tile) == TROPICZONE_RAINFOREST) ?
816 _settings_game.construction.extra_tree_placement == ETP_SPREAD_ALL);
817}
818
819static void TileLoop_Trees(TileIndex tile)
820{
821 if (GetTreeGround(tile) == TREE_GROUND_SHORE) {
822 TileLoop_Water(tile);
823 } else {
825 case LandscapeType::Tropic: TileLoopTreesDesert(tile); break;
826 case LandscapeType::Arctic: TileLoopTreesAlps(tile); break;
827 default: break;
828 }
829 }
830
831 AmbientSoundEffect(tile);
832
833 /* TimerGameTick::counter is incremented by 256 between each call, so ignore lower 8 bits.
834 * Also, we use a simple hash to spread the updates evenly over the map.
835 * 11 and 9 are just some co-prime numbers for better spread.
836 */
837 uint32_t cycle = 11 * TileX(tile) + 9 * TileY(tile) + (TimerGameTick::counter >> 8);
838
839 /* Handle growth of grass (under trees/on MP_TREES tiles) at every 8th processings, like it's done for grass on MP_CLEAR tiles. */
840 if ((cycle & 7) == 7 && GetTreeGround(tile) == TREE_GROUND_GRASS) {
841 uint density = GetTreeDensity(tile);
842 if (density < 3) {
843 SetTreeGroundDensity(tile, TREE_GROUND_GRASS, density + 1);
845 }
846 }
847
849
850 static const uint32_t TREE_UPDATE_FREQUENCY = 16; // How many tile updates happen for one tree update
851 if (cycle % TREE_UPDATE_FREQUENCY != TREE_UPDATE_FREQUENCY - 1) return;
852
853 switch (GetTreeGrowth(tile)) {
854 case TreeGrowthStage::Grown: // regular sized tree
855 if (_settings_game.game_creation.landscape == LandscapeType::Tropic &&
856 GetTreeType(tile) != TREE_CACTUS &&
858 AddTreeGrowth(tile, 1);
859 } else {
860 switch (GB(Random(), 0, 3)) {
861 case 0: // start destructing
862 AddTreeGrowth(tile, 1);
863 break;
864
865 case 1: // add a tree
866 if (GetTreeCount(tile) < 4 && CanPlantExtraTrees(tile)) {
867 AddTreeCount(tile, 1);
869 break;
870 }
871 [[fallthrough]];
872
873 case 2: { // add a neighbouring tree
874 if (!CanPlantExtraTrees(tile)) break;
875
876 TreeType treetype = GetTreeType(tile);
877
878 tile += TileOffsByDir(static_cast<Direction>(Random() % DIR_END));
879
880 /* Cacti don't spread */
881 if (!CanPlantTreesOnTile(tile, false)) return;
882
883 /* Don't plant trees, if ground was freshly cleared */
884 if (IsTileType(tile, MP_CLEAR) && GetClearGround(tile) == CLEAR_GRASS && GetClearDensity(tile) != 3) return;
885
887
888 break;
889 }
890
891 default:
892 return;
893 }
894 }
895 break;
896
897 case TreeGrowthStage::Dead: // final stage of tree destruction
898 if (!CanPlantExtraTrees(tile)) {
899 /* if trees can't spread just plant a new one to prevent deforestation */
901 } else if (GetTreeCount(tile) > 1) {
902 /* more than one tree, delete it */
903 AddTreeCount(tile, -1);
905 } else {
906 /* just one tree, change type into MP_CLEAR */
907 switch (GetTreeGround(tile)) {
908 case TREE_GROUND_SHORE: MakeShore(tile); break;
909 case TREE_GROUND_GRASS: MakeClear(tile, CLEAR_GRASS, GetTreeDensity(tile)); break;
910 case TREE_GROUND_ROUGH: MakeClear(tile, CLEAR_ROUGH, 3); break;
912 uint density = GetTreeDensity(tile);
913 MakeClear(tile, CLEAR_ROUGH, 3);
914 MakeSnow(tile, density);
915 break;
916 }
917 default: // snow or desert
918 if (_settings_game.game_creation.landscape == LandscapeType::Tropic) {
920 } else {
921 uint density = GetTreeDensity(tile);
922 MakeClear(tile, CLEAR_GRASS, 3);
923 MakeSnow(tile, density);
924 }
925 break;
926 }
927 }
928 break;
929
930 default:
931 AddTreeGrowth(tile, 1);
932 break;
933 }
934
936}
937
945{
946 /* Ensure _trees_tick_ctr can be decremented past zero only once for the largest map size. */
947 static_assert(2 * (MAX_MAP_SIZE_BITS - MIN_MAP_SIZE_BITS) - 4 <= std::numeric_limits<uint8_t>::digits);
948
949 /* byte underflow */
950 uint8_t old_trees_tick_ctr = _trees_tick_ctr;
952 return old_trees_tick_ctr <= _trees_tick_ctr;
953}
954
959static void PlantRandomTree(bool rainforest)
960{
961 uint32_t r = Random();
962 TileIndex tile = RandomTileSeed(r);
963
964 if (rainforest && GetTropicZone(tile) != TROPICZONE_RAINFOREST) return;
965 if (!CanPlantTreesOnTile(tile, false)) return;
966
967 TreeType tree = GetRandomTreeType(tile, GB(r, 24, 8));
968 if (tree == TREE_INVALID) return;
969
971}
972
973void OnTick_Trees()
974{
975 /* Don't spread trees if that's not allowed */
977
978 /* Skip some tree ticks for map sizes below 256 * 256. 64 * 64 is 16 times smaller, so
979 * this is the maximum number of ticks that are skipped. Number of ticks to skip is
980 * inversely proportional to map size, so that is handled to create a mask. */
981 int skip = Map::ScaleBySize(16);
982 if (skip < 16 && (TimerGameTick::counter & (16 / skip - 1)) != 0) return;
983
984 /* place a tree at a random rainforest spot */
985 if (_settings_game.game_creation.landscape == LandscapeType::Tropic) {
986 for (uint c = Map::ScaleBySize(1); c > 0; c--) {
987 PlantRandomTree(true);
988 }
989 }
990
992
993 /* place a tree at a random spot */
994 PlantRandomTree(false);
995}
996
997static TrackStatus GetTileTrackStatus_Trees(TileIndex, TransportType, uint, DiagDirection)
998{
999 return 0;
1000}
1001
1002static void ChangeTileOwner_Trees(TileIndex, Owner, Owner)
1003{
1004 /* not used */
1005}
1006
1007void InitializeTrees()
1008{
1009 _trees_tick_ctr = 0;
1010}
1011
1012static CommandCost TerraformTile_Trees(TileIndex tile, DoCommandFlags flags, int, Slope)
1013{
1014 return Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile);
1015}
1016
1017
1018extern const TileTypeProcs _tile_type_trees_procs = {
1019 DrawTile_Trees, // draw_tile_proc
1020 GetSlopePixelZ_Trees, // get_slope_z_proc
1021 ClearTile_Trees, // clear_tile_proc
1022 nullptr, // add_accepted_cargo_proc
1023 GetTileDesc_Trees, // get_tile_desc_proc
1024 GetTileTrackStatus_Trees, // get_tile_track_status_proc
1025 nullptr, // click_tile_proc
1026 nullptr, // animate_tile_proc
1027 TileLoop_Trees, // tile_loop_proc
1028 ChangeTileOwner_Trees, // change_tile_owner_proc
1029 nullptr, // add_produced_cargo_proc
1030 nullptr, // vehicle_enter_tile_proc
1031 GetFoundation_Trees, // get_foundation_proc
1032 TerraformTile_Trees, // terraform_tile_proc
1033};
constexpr uint CountBits(T value)
Counts the number of set bits in a variable.
debug_inline static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
bool IsBridgeAbove(Tile t)
checks if a bridge is set above the ground of this tile
Definition bridge_map.h:45
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
Common return value for all commands.
void AddCost(const Money &cost)
Adds the given cost to the cost of the command.
Money GetCost() const
The costs as made up to this moment.
bool Failed() const
Did this command fail?
Enum-as-bit-set wrapper.
static std::unique_ptr< TileIterator > Create(TileIndex corner1, TileIndex corner2, bool diagonal)
Create either an OrthogonalTileIterator or DiagonalTileIterator given the diagonal parameter.
Definition tilearea.cpp:291
static TickCounter counter
Monotonic counter, in ticks, since start of game.
Functions related to clear (MP_CLEAR) land.
Tables with sprites for clear land and fences.
Map accessors for 'clear' tiles.
bool IsClearGround(Tile t, ClearGround ct)
Set the type of clear tile.
Definition clear_map.h:59
void MakeSnow(Tile t, uint density=0)
Make a snow tile.
Definition clear_map.h:288
ClearGround
Ground types.
Definition clear_map.h:19
@ CLEAR_GRASS
0-3
Definition clear_map.h:20
@ CLEAR_FIELDS
3
Definition clear_map.h:23
@ CLEAR_DESERT
1,3
Definition clear_map.h:25
@ CLEAR_ROUGH
3
Definition clear_map.h:21
@ CLEAR_ROCKS
3
Definition clear_map.h:22
void MakeClear(Tile t, ClearGround g, uint density)
Make a clear tile.
Definition clear_map.h:247
ClearGround GetClearGround(Tile t)
Get the type of clear tile.
Definition clear_map.h:47
bool IsSnowTile(Tile t)
Test if a tile is covered with snow.
Definition clear_map.h:35
uint GetClearDensity(Tile t)
Get the density of a non-field clear tile.
Definition clear_map.h:71
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
@ Execute
execute the given command
Definition of stuff that is very close to a company, like the company struct itself.
CompanyID _current_company
Company currently doing an action.
Functions related to companies.
Direction
Defines the 8 directions on the map.
@ DIR_END
Used to iterate.
DiagDirection
Enumeration for diagonal directions.
@ EXPENSES_CONSTRUCTION
Construction costs.
@ EXPENSES_OTHER
Other expenses.
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23)
Definition enum_type.hpp:17
Functions related to world/map generation.
void IncreaseGeneratingWorldProgress(GenWorldProgress cls)
Increases the current stage of the world generation with one.
@ GWP_TREE
Generate trees.
Definition genworld.h:69
void SetGeneratingWorldProgress(GenWorldProgress cls, uint total)
Set the total of a stage of the world generation.
static constexpr uint MAP_HEIGHT_LIMIT_ORIGINAL
Original map height limit.
Definition genworld.h:52
All geometry types in OpenTTD.
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:17
uint32_t PaletteID
The number of the palette.
Definition gfx_type.h:18
uint8_t GetSnowLine()
Get the current snow line, either variable or static.
void MarkTileDirtyByTile(TileIndex tile, int bridge_level_offset, int tile_height_override)
Mark a tile given by its index dirty for repaint.
uint GetPartialPixelZ(int x, int y, Slope corners)
Determines height at given coordinate of a slope.
Functions related to OTTD's landscape.
Command definitions related to landscape (slopes etc.).
@ Random
Randomise borders.
uint DistanceSquare(TileIndex t0, TileIndex t1)
Gets the 'Square' distance between the two given tiles.
Definition map.cpp:159
TileIndex TileAddWrap(TileIndex tile, int addx, int addy)
This function checks if we add addx/addy to tile, if we do wrap around the edges.
Definition map.cpp:93
TileIndex RandomTileSeed(uint32_t r)
Get a random tile out of a given seed.
Definition map_func.h:652
#define RandomTile()
Get a valid random tile.
Definition map_func.h:663
TileIndexDiff TileOffsByDir(Direction dir)
Convert a Direction to a TileIndexDiff.
Definition map_func.h:583
static debug_inline uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition map_func.h:424
static debug_inline uint TileX(TileIndex tile)
Get the X component of a tile.
Definition map_func.h:414
static const uint MIN_MAP_SIZE_BITS
Minimal and maximal map width and height.
Definition map_type.h:37
static const uint MAX_MAP_SIZE_BITS
Maximal size of map is equal to 2 ^ MAX_MAP_SIZE_BITS.
Definition map_type.h:38
constexpr bool IsInsideBS(const T x, const size_t base, const size_t size)
Checks if a value is between a window started at some base point.
constexpr bool IsInsideMM(const size_t x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
constexpr T abs(const T a)
Returns the absolute value of (scalar) variable.
Definition math_func.hpp:23
constexpr T Delta(const T a, const T b)
Returns the (absolute) difference between two (scalar) variables.
Functions related to generic callbacks.
void AmbientSoundEffect(TileIndex tile)
Play an ambient sound effect for an empty tile.
Pseudo random number generator.
bool Chance16I(const uint32_t a, const uint32_t b, const uint32_t r)
Checks if a given randomize-number is below a given probability.
A number of safeguards to prevent using unsafe methods.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:58
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:57
bool IsSlopeWithOneCornerRaised(Slope s)
Tests if a specific slope has exactly one corner raised.
Definition slope_func.h:88
uint SlopeToSpriteOffset(Slope s)
Returns the Sprite offset for a given Slope.
Definition slope_func.h:415
static constexpr int GetSlopeMaxPixelZ(Slope s)
Returns the height of the highest corner of a slope relative to TileZ (= minimal height)
Definition slope_func.h:173
Slope
Enumeration for the slope-type.
Definition slope_type.h:48
Foundation
Enumeration for Foundations.
Definition slope_type.h:93
@ FOUNDATION_NONE
The tile has no foundation, the slope remains unchanged.
Definition slope_type.h:94
Functions related to sound.
SoundFx
Sound effects from baseset.
Definition sound_type.h:45
@ SND_39_ARCTIC_SNOW_2
57 == 0x39 Tree ambient: arctic snow (2): heavy wind
Definition sound_type.h:104
@ SND_44_RAINFOREST_3
68 == 0x44 Tree ambient: rainforest ambient (3): monkeys
Definition sound_type.h:115
@ SND_34_ARCTIC_SNOW_1
52 == 0x34 Tree ambient: arctic snow (1): wind
Definition sound_type.h:99
@ SND_43_RAINFOREST_2
67 == 0x43 Tree ambient: rainforest ambient (2): lion
Definition sound_type.h:114
@ SND_42_RAINFOREST_1
66 == 0x42 Tree ambient: rainforest ambient (1): bird (1)
Definition sound_type.h:113
@ SND_48_RAINFOREST_4
72 == 0x48 Tree ambient: rainforest ambient (4): bird (2)
Definition sound_type.h:119
Definition of base types and functions in a cross-platform compatible way.
#define lengthof(array)
Return the length of an fixed size array.
Definition stdafx.h:277
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
SoundSettings sound
sound effect settings
uint32_t tree_limit
Amount of trees we can (still) plant (times 65536).
uint8_t extra_tree_placement
(dis)allow building extra trees in-game
uint8_t map_height_limit
the maximum allowed heightlevel
uint8_t dist_local_authority
distance for town local authority, default 20
uint8_t tree_placer
the tree placer algorithm
LandscapeType landscape
the landscape we're currently in
EconomySettings economy
settings to change the economy
ConstructionSettings construction
construction of things in-game
GameCreationSettings game_creation
settings used during the creation of a game (map)
static uint ScaleBySize(uint n)
Scales the given value by the map size, where the given value is for a 256 by 256 map.
Definition map_func.h:327
static debug_inline uint Size()
Get the size of the map.
Definition map_func.h:287
OrthogonalTileArea & Expand(int rad)
Expand a tile area by rad tiles in each direction, keeping within map bounds.
Definition tilearea.cpp:123
Combination of a palette sprite and a 'real' sprite.
Definition gfx_type.h:22
SpriteID sprite
The 'real' sprite.
Definition gfx_type.h:23
PaletteID pal
The palette (use PAL_NONE) if not needed)
Definition gfx_type.h:24
Coordinates of a point in 2D.
static bool IsValidID(auto index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
static Titem * GetIfValid(auto index)
Returns Titem with given index.
bool ambient
Play ambient, industry and town sounds.
Tile description for the 'land area information' tool.
Definition tile_cmd.h:52
StringID str
Description of the tile.
Definition tile_cmd.h:53
std::array< Owner, 4 > owner
Name of the owner(s)
Definition tile_cmd.h:55
Tile information, used while rendering the tile.
Definition tile_cmd.h:43
int z
Height.
Definition tile_cmd.h:48
int x
X position of the tile in unit coordinates.
Definition tile_cmd.h:44
Slope tileh
Slope of the tile.
Definition tile_cmd.h:46
TileIndex tile
Tile index.
Definition tile_cmd.h:47
int y
Y position of the tile in unit coordinates.
Definition tile_cmd.h:45
Set of callback functions for performing tile operations of a given tile type.
Definition tile_cmd.h:159
Town data structure.
Definition town.h:52
int GetTileZ(TileIndex tile)
Get bottom height of the tile.
Definition tile_map.cpp:116
Owner GetTileOwner(Tile tile)
Returns the owner of a tile.
Definition tile_map.h:178
static debug_inline TileType GetTileType(Tile tile)
Get the tiletype of a given tile.
Definition tile_map.h:96
std::tuple< Slope, int > GetTilePixelSlope(TileIndex tile)
Return the slope of a given tile.
Definition tile_map.h:289
TropicZone GetTropicZone(Tile tile)
Get the tropic zone.
Definition tile_map.h:238
static debug_inline bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition tile_map.h:150
Slope GetTileSlope(TileIndex tile)
Return the slope of a given tile inside the map.
Definition tile_map.h:279
void SetTropicZone(Tile tile, TropicZone type)
Set the tropic zone.
Definition tile_map.h:225
@ TROPICZONE_RAINFOREST
Rainforest tile.
Definition tile_type.h:79
@ TROPICZONE_DESERT
Tile is desert.
Definition tile_type.h:78
@ TROPICZONE_NORMAL
Normal tropiczone.
Definition tile_type.h:77
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:95
@ MP_TREES
Tile got trees.
Definition tile_type.h:52
@ MP_CLEAR
A tile without any structures, i.e. grass, rocks, farm fields etc.
Definition tile_type.h:48
@ MP_WATER
Water tile.
Definition tile_type.h:54
@ MP_VOID
Invisible tiles at the SW and SE border.
Definition tile_type.h:55
OrthogonalTileArea TileArea
Shorthand for the much more common orthogonal tile area.
Definition of the tick-based game-timer.
Base of the town class.
void ChangeTownRating(Town *t, int add, int max, DoCommandFlags flags)
Changes town rating of the current company.
Town * ClosestTownFromTile(TileIndex tile, uint threshold)
Return the town closest (in distance or ownership) to a given tile, within a given threshold.
bool IsTransparencySet(TransparencyOption to)
Check if the transparency option bit is set and if we aren't in the game menu (there's never transpar...
bool IsInvisibilitySet(TransparencyOption to)
Check if the invisibility option bit is set and if we aren't in the game menu (there's never transpar...
@ TO_TREES
trees
TransportType
Available types of transport.
uint PlaceTreeGroupAroundTile(TileIndex tile, TreeType treetype, uint radius, uint count, bool set_zone)
Place some trees in a radius around a tile.
Definition tree_cmd.cpp:429
static void PlantTreesOnTile(TileIndex tile, TreeType treetype, uint count, TreeGrowthStage growth)
Creates a tree tile Ground type and density is preserved.
Definition tree_cmd.cpp:95
static TreeType GetRandomTreeType(TileIndex tile, uint seed)
Get a random TreeType for the given tile based on a given seed.
Definition tree_cmd.cpp:141
static bool IsPointInTriangle(int x, int y, const Point &v1, const Point &v2, const Point &v3)
Returns true if the given coordinates lie within a triangle.
Definition tree_cmd.cpp:259
void GenerateTrees()
Place new trees.
Definition tree_cmd.cpp:476
static void CreateStarShapedPolygon(int radius, std::span< const BlobHarmonic > harmonics, std::span< Point > shape)
Creates a star-shaped polygon originating from (0, 0) as defined by the given harmonics.
Definition tree_cmd.cpp:200
static const uint16_t EDITOR_TREE_DIV
Game editor tree generation divisor factor.
Definition tree_cmd.cpp:60
static bool CanPlantTreesOnTile(TileIndex tile, bool allow_desert)
Tests if a tile can be converted to MP_TREES This is true for clear ground without farms or rocks.
Definition tree_cmd.cpp:70
void PlaceTreesRandomly()
Place some trees randomly.
Definition tree_cmd.cpp:366
static const uint16_t DEFAULT_TREE_STEPS
Default number of attempts for placing trees.
Definition tree_cmd.cpp:58
static const uint16_t DEFAULT_RAINFOREST_TREE_STEPS
Default number of attempts for placing extra trees at rainforest in tropic.
Definition tree_cmd.cpp:59
static bool IsPointInStarShapedPolygon(int x, int y, std::span< Point > shape)
Returns true if the given coordinates lie within a star shaped polygon.
Definition tree_cmd.cpp:278
static void PlantRandomTree(bool rainforest)
Place a random tree on a random tile.
Definition tree_cmd.cpp:959
CommandCost CmdPlantTree(DoCommandFlags flags, TileIndex tile, TileIndex start_tile, uint8_t tree_to_plant, bool diagonal)
Plant a tree.
Definition tree_cmd.cpp:511
static void PlaceTreeAtSameHeight(TileIndex tile, int height)
Place a tree at the same height as an existing tree.
Definition tree_cmd.cpp:337
static void CreateRandomStarShapedPolygon(int radius, std::span< Point > shape)
Creates a random star-shaped polygon originating from (0, 0).
Definition tree_cmd.cpp:231
uint8_t _trees_tick_ctr
Determines when to consider building more trees.
Definition tree_cmd.cpp:56
TreePlacer
List of tree placer algorithm.
Definition tree_cmd.cpp:41
@ TP_IMPROVED
A 'improved' algorithm.
Definition tree_cmd.cpp:44
@ TP_NONE
No tree placer algorithm.
Definition tree_cmd.cpp:42
@ TP_ORIGINAL
The original algorithm.
Definition tree_cmd.cpp:43
static void PlaceTree(TileIndex tile, uint32_t r)
Make a random tree tile of the given tile.
Definition tree_cmd.cpp:171
static void PlaceTreeGroups(uint num_groups)
Creates a number of tree groups.
Definition tree_cmd.cpp:297
ExtraTreePlacement
Where to place trees while in-game?
Definition tree_cmd.cpp:48
@ ETP_SPREAD_RAINFOREST
Grow trees on tiles that have them, only spread to new ones in rainforests.
Definition tree_cmd.cpp:50
@ ETP_NO_SPREAD
Grow trees on tiles that have them but don't spread to new ones.
Definition tree_cmd.cpp:49
@ ETP_NO_GROWTH_NO_SPREAD
Don't grow trees and don't spread them at all.
Definition tree_cmd.cpp:52
@ ETP_SPREAD_ALL
Grow trees and spread them without restrictions.
Definition tree_cmd.cpp:51
bool DecrementTreeCounter()
Decrement the tree tick counter.
Definition tree_cmd.cpp:944
Command definitions related to tree tiles.
Sprites to use and how to display them for tree tiles.
Map accessors for tree tiles.
static const uint TREE_COUNT_RAINFOREST
number of tree types for the 'rainforest part' of a sub-tropic map.
Definition tree_map.h:43
uint GetTreeCount(Tile t)
Returns the number of trees on a tile.
Definition tree_map.h:163
TreeGrowthStage GetTreeGrowth(Tile t)
Returns the tree growth stage.
Definition tree_map.h:195
static const uint TREE_COUNT_SUB_TROPICAL
number of tree types for the 'sub-tropic part' of a sub-tropic map.
Definition tree_map.h:44
static const uint TREE_COUNT_TOYLAND
number of tree types on a toyland map.
Definition tree_map.h:45
void MakeTree(Tile t, TreeType type, uint count, TreeGrowthStage growth, TreeGround ground, uint density)
Make a tree-tile.
Definition tree_map.h:244
void SetTreeGrowth(Tile t, TreeGrowthStage g)
Sets the tree growth stage of a tile.
Definition tree_map.h:226
TreeGround GetTreeGround(Tile t)
Returns the groundtype for tree tiles.
Definition tree_map.h:102
TreeType
List of tree types along all landscape types.
Definition tree_map.h:25
@ TREE_RAINFOREST
tree on the 'green part' on a sub-tropical map
Definition tree_map.h:28
@ TREE_TOYLAND
tree on a toyland map
Definition tree_map.h:31
@ TREE_SUB_ARCTIC
tree on a sub_arctic landscape
Definition tree_map.h:27
@ TREE_SUB_TROPICAL
tree on a sub-tropical map, non-rainforest, non-desert
Definition tree_map.h:30
@ TREE_TEMPERATE
temperate tree
Definition tree_map.h:26
@ TREE_CACTUS
a cactus for the 'desert part' on a sub-tropical map
Definition tree_map.h:29
@ TREE_INVALID
An invalid tree.
Definition tree_map.h:32
void AddTreeCount(Tile t, int c)
Add a amount to the tree-count value of a tile with trees.
Definition tree_map.h:180
TreeGround
Enumeration for ground types of tiles with trees.
Definition tree_map.h:52
@ TREE_GROUND_GRASS
normal grass
Definition tree_map.h:53
@ TREE_GROUND_SHORE
shore
Definition tree_map.h:56
@ TREE_GROUND_ROUGH_SNOW
A snow tile that is rough underneath.
Definition tree_map.h:57
@ TREE_GROUND_SNOW_DESERT
a desert or snow tile, depend on landscape
Definition tree_map.h:55
@ TREE_GROUND_ROUGH
some rough tile
Definition tree_map.h:54
static const uint TREE_COUNT_SUB_ARCTIC
number of tree types on a sub arctic map.
Definition tree_map.h:42
TreeType GetTreeType(Tile t)
Returns the treetype of a tile.
Definition tree_map.h:87
void SetTreeGroundDensity(Tile t, TreeGround g, uint d)
Set the density and ground type of a tile with trees.
Definition tree_map.h:144
void AddTreeGrowth(Tile t, int a)
Add a value to the tree growth stage.
Definition tree_map.h:210
uint GetTreeDensity(Tile t)
Returns the 'density' of a tile with trees.
Definition tree_map.h:127
TreeGrowthStage
Enumeration for tree growth stages.
Definition tree_map.h:65
@ Grown
Fully grown tree.
@ Dead
Dead tree.
@ Growing1
First stage of growth.
static const uint TREE_COUNT_TEMPERATE
number of tree types on a temperate map.
Definition tree_map.h:41
void StartSpriteCombine()
Starts a block of sprites, which are "combined" into a single bounding box.
Definition viewport.cpp:769
void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w, int h, int dz, int z, bool transparent, int bb_offset_x, int bb_offset_y, int bb_offset_z, const SubSprite *sub)
Draw a (transparent) sprite at given coordinates with a given bounding box.
Definition viewport.cpp:673
void EndSpriteCombine()
Terminates a block of sprites started by StartSpriteCombine.
Definition viewport.cpp:779
void DrawGroundSprite(SpriteID image, PaletteID pal, const SubSprite *sub, int extra_offs_x, int extra_offs_y)
Draws a ground sprite for the current tile.
Definition viewport.cpp:589
Functions related to (drawing on) viewports.
Functions related to water (management)
void TileLoop_Water(TileIndex tile)
Let a water tile floods its diagonal adjoining tiles called from tunnelbridge_cmd,...
void ClearNeighbourNonFloodingStates(TileIndex tile)
Clear non-flooding state of the tiles around a tile.
Definition water_cmd.cpp:97
void MakeShore(Tile t)
Helper function to make a coast tile.
Definition water_map.h:381
bool IsCoast(Tile t)
Is it a coast tile?
Definition water_map.h:201