diff --git a/docs/landscape.html b/docs/landscape.html
--- a/docs/landscape.html
+++ b/docs/landscape.html
@@ -11,12 +11,13 @@
m5 bits 7..5: update counter, incremented on every periodic processing for tile types,
@@ -722,8 +724,7 @@
- m1: owner (normally 10)
- - m2 bits 7..6: ground density
-
- m2 bits 5..4: ground
+
- m2 bits 8..6: ground
@@ -745,8 +746,14 @@
3 |
on shore (density must be 3) |
+
+
+ 4 |
+ on snow with rough land underneed |
+
+ - m2 bits 5..4: ground density
- m2 bits 3..0: update counter, incremented on every periodic processing.
on wraparound the growth status is updated (or, if it's 3, a random action is taken)
- m3 bits 7..0: type of trees:
diff --git a/docs/landscape_grid.html b/docs/landscape_grid.html
--- a/docs/landscape_grid.html
+++ b/docs/landscape_grid.html
@@ -68,7 +68,7 @@ the array so you can quickly see what is
XXXX XXXX |
~~~~ ~~~~ |
OOOO OOOO OOOO OOOO |
- OOOO OOOO |
+ OOOX OOOO |
XXXX XXOO |
XXXX XXXX |
XXOO OOXX |
@@ -79,7 +79,7 @@ the array so you can quickly see what is
-inherit- |
~~~~ ~~~~ |
XXXX XXXX XXXX XXXX |
- OOOO XXXX |
+ OOOX XXXX |
-inherit- |
-inherit- |
XXOO OOXX |
@@ -170,7 +170,7 @@ the array so you can quickly see what is
trees |
XXXX XXXX |
~~~~ ~~~~ |
- OOOO OOOO XXXX XXXX |
+ OOOO OOOX XXXX XXXX |
~~XX XXXX |
XXXX XXOO |
XXOO OXXX |
diff --git a/src/ai/api/ai_tile.cpp b/src/ai/api/ai_tile.cpp
--- a/src/ai/api/ai_tile.cpp
+++ b/src/ai/api/ai_tile.cpp
@@ -112,21 +112,21 @@
{
if (!::IsValidTile(tile)) return false;
- return (::IsTileType(tile, MP_CLEAR) && ::IsClearGround(tile, CLEAR_ROCKS));
+ return (::IsTileType(tile, MP_CLEAR) && ::GetRawClearGround(tile) == ::CLEAR_ROCKS);
}
/* static */ bool AITile::IsRoughTile(TileIndex tile)
{
if (!::IsValidTile(tile)) return false;
- return (::IsTileType(tile, MP_CLEAR) && ::IsClearGround(tile, CLEAR_ROUGH));
+ return (::IsTileType(tile, MP_CLEAR) && ::GetRawClearGround(tile) == ::CLEAR_ROUGH);
}
/* static */ bool AITile::IsSnowTile(TileIndex tile)
{
if (!::IsValidTile(tile)) return false;
- return (::IsTileType(tile, MP_CLEAR) && ::IsClearGround(tile, CLEAR_SNOW));
+ return (::IsTileType(tile, MP_CLEAR) && ::IsSnowTile(tile));
}
/* static */ bool AITile::IsDesertTile(TileIndex tile)
diff --git a/src/clear_cmd.cpp b/src/clear_cmd.cpp
--- a/src/clear_cmd.cpp
+++ b/src/clear_cmd.cpp
@@ -158,11 +158,11 @@ static void TileLoopClearAlps(TileIndex
if (k < 0) {
/* Below the snow line, do nothing if no snow. */
- if (!IsClearGround(tile, CLEAR_SNOW)) return;
+ if (!IsSnowTile(tile)) return;
} else {
/* At or above the snow line, make snow tile if needed. */
- if (!IsClearGround(tile, CLEAR_SNOW)) {
- SetClearGroundDensity(tile, CLEAR_SNOW, 0);
+ if (!IsSnowTile(tile)) {
+ MakeSnow(tile);
MarkTileDirtyByTile(tile);
return;
}
@@ -177,7 +177,7 @@ static void TileLoopClearAlps(TileIndex
AddClearDensity(tile, -1);
} else {
/* Density at the required level. */
- if (k < 0) SetClearGroundDensity(tile, CLEAR_GRASS, 3);
+ if (k < 0) ClearSnow(tile);
}
MarkTileDirtyByTile(tile);
}
diff --git a/src/clear_map.h b/src/clear_map.h
--- a/src/clear_map.h
+++ b/src/clear_map.h
@@ -29,6 +29,30 @@ enum ClearGround {
/**
+ * Test if a tile is covered with snow.
+ * @param t the tile to check
+ * @pre IsTileType(t, MP_CLEAR)
+ * @return whether the tile is covered with snow.
+ */
+static inline bool IsSnowTile(TileIndex t)
+{
+ assert(IsTileType(t, MP_CLEAR));
+ return HasBit(_m[t].m3, 4);
+}
+
+/**
+ * Get the type of clear tile but never return CLEAR_SNOW.
+ * @param t the tile to get the clear ground type of
+ * @pre IsTileType(t, MP_CLEAR)
+ * @return the ground type
+ */
+static inline ClearGround GetRawClearGround(TileIndex t)
+{
+ assert(IsTileType(t, MP_CLEAR));
+ return (ClearGround)GB(_m[t].m5, 2, 3);
+}
+
+/**
* Get the type of clear tile.
* @param t the tile to get the clear ground type of
* @pre IsTileType(t, MP_CLEAR)
@@ -36,8 +60,8 @@ enum ClearGround {
*/
static inline ClearGround GetClearGround(TileIndex t)
{
- assert(IsTileType(t, MP_CLEAR));
- return (ClearGround)GB(_m[t].m5, 2, 3);
+ if (IsSnowTile(t)) return CLEAR_SNOW;
+ return GetRawClearGround(t);
}
/**
@@ -76,6 +100,18 @@ static inline void AddClearDensity(TileI
_m[t].m5 += d;
}
+/**
+ * Set the density of a non-field clear tile.
+ * @param t the tile to set the density of
+ * @param d the new density
+ * @pre IsTileType(t, MP_CLEAR)
+ */
+static inline void SetClearDensity(TileIndex t, uint d)
+{
+ assert(IsTileType(t, MP_CLEAR));
+ SB(_m[t].m5, 0, 2, d);
+}
+
/**
* Get the counter used to advance to the next clear density/field type.
@@ -269,4 +305,32 @@ static inline void MakeField(TileIndex t
_me[t].m7 = 0;
}
+/**
+ * Make a snow tile.
+ * @param t the tile to make snowy
+ * @pre GetClearGround(t) != CLEAR_SNOW
+ */
+static inline void MakeSnow(TileIndex t)
+{
+ assert(GetClearGround(t) != CLEAR_SNOW);
+ SetBit(_m[t].m3, 4);
+ if (GetClearGround(t) == CLEAR_FIELDS) {
+ SetClearGroundDensity(t, CLEAR_GRASS, 0);
+ } else {
+ SetClearDensity(t, 0);
+ }
+}
+
+/**
+ * Clear the snow from a tile and return it to it's previous type.
+ * @param t the tile to clear of snow
+ * @pre GetClearGround(t) == CLEAR_SNOW
+ */
+static inline void ClearSnow(TileIndex t)
+{
+ assert(GetClearGround(t) == CLEAR_SNOW);
+ ClrBit(_m[t].m3, 4);
+ SetClearDensity(t, 3);
+}
+
#endif /* CLEAR_MAP_H */
diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp
--- a/src/saveload/afterload.cpp
+++ b/src/saveload/afterload.cpp
@@ -120,7 +120,7 @@ void SetWaterClassDependingOnSurrounding
case MP_TREES:
/* trees on shore */
- has_water |= (GetTreeGround(neighbour) == TREE_GROUND_SHORE);
+ has_water |= (GB(_m[neighbour].m2, 4, 2) == TREE_GROUND_SHORE);
break;
default: break;
@@ -1437,8 +1437,8 @@ bool AfterLoadGame()
if (CheckSavegameVersion(81)) {
for (TileIndex t = 0; t < map_size; t++) {
if (GetTileType(t) == MP_TREES) {
- TreeGround groundType = GetTreeGround(t);
- if (groundType != TREE_GROUND_SNOW_DESERT) SetTreeGroundDensity(t, groundType, 3);
+ TreeGround groundType = (TreeGround)GB(_m[t].m2, 4, 2);
+ if (groundType != TREE_GROUND_SNOW_DESERT) SB(_m[t].m2, 6, 2, 3);
}
}
}
@@ -1976,6 +1976,27 @@ bool AfterLoadGame()
}
}
+ /* The bits for the tree ground and tree density have
+ * been swapped (m2 bits 7..6 and 5..4. */
+ if (CheckSavegameVersion(135)) {
+ for (TileIndex t = 0; t < map_size; t++) {
+ if (IsTileType(t, MP_CLEAR)) {
+ if (GetRawClearGround(t) == CLEAR_SNOW) {
+ SetClearGroundDensity(t, CLEAR_GRASS, GetClearDensity(t));
+ SetBit(_m[t].m3, 4);
+ } else {
+ ClrBit(_m[t].m3, 4);
+ }
+ }
+ if (IsTileType(t, MP_TREES)) {
+ uint density = GB(_m[t].m2, 6, 2);
+ uint ground = GB(_m[t].m2, 4, 2);
+ uint counter = GB(_m[t].m2, 0, 4);
+ _m[t].m2 = ground << 6 | density << 4 | counter;
+ }
+ }
+ }
+
/* Road stops is 'only' updating some caches */
AfterLoadRoadStops();
AfterLoadLabelMaps();
diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp
--- a/src/saveload/saveload.cpp
+++ b/src/saveload/saveload.cpp
@@ -47,7 +47,7 @@
#include "saveload_internal.h"
-extern const uint16 SAVEGAME_VERSION = 134;
+extern const uint16 SAVEGAME_VERSION = 135;
SavegameType _savegame_type; ///< type of savegame we are loading
diff --git a/src/smallmap_gui.cpp b/src/smallmap_gui.cpp
--- a/src/smallmap_gui.cpp
+++ b/src/smallmap_gui.cpp
@@ -374,7 +374,7 @@ static inline uint32 GetSmallMapVegetati
return GetIndustrySpec(Industry::GetByTile(tile)->type)->check_proc == CHECK_FOREST ? MKCOLOUR(0xD0D0D0D0) : MKCOLOUR(0xB5B5B5B5);
case MP_TREES:
- if (GetTreeGround(tile) == TREE_GROUND_SNOW_DESERT) {
+ if (GetTreeGround(tile) == TREE_GROUND_SNOW_DESERT || GetTreeGround(tile) == TREE_GROUND_ROUGH_SNOW) {
return (_settings_game.game_creation.landscape == LT_ARCTIC) ? MKCOLOUR(0x98575798) : MKCOLOUR(0xC25757C2);
}
return MKCOLOUR(0x54575754);
diff --git a/src/tree_cmd.cpp b/src/tree_cmd.cpp
--- a/src/tree_cmd.cpp
+++ b/src/tree_cmd.cpp
@@ -68,7 +68,7 @@ static bool CanPlantTreesOnTile(TileInde
return !IsBridgeAbove(tile) && IsCoast(tile) && !IsSlopeWithOneCornerRaised(GetTileSlope(tile, NULL));
case MP_CLEAR:
- return !IsBridgeAbove(tile) && !IsClearGround(tile, CLEAR_FIELDS) && !IsClearGround(tile, CLEAR_ROCKS) &&
+ return !IsBridgeAbove(tile) && !IsClearGround(tile, CLEAR_FIELDS) && GetRawClearGround(tile) != CLEAR_ROCKS &&
(allow_desert || !IsClearGround(tile, CLEAR_DESERT));
default: return false;
@@ -101,10 +101,12 @@ static void PlantTreesOnTile(TileIndex t
case MP_CLEAR:
switch (GetClearGround(tile)) {
- case CLEAR_GRASS: ground = TREE_GROUND_GRASS; density = GetClearDensity(tile); break;
- case CLEAR_ROUGH: ground = TREE_GROUND_ROUGH; break;
- default: ground = TREE_GROUND_SNOW_DESERT; density = GetClearDensity(tile); break;
+ case CLEAR_GRASS: ground = TREE_GROUND_GRASS; break;
+ case CLEAR_ROUGH: ground = TREE_GROUND_ROUGH; break;
+ case CLEAR_SNOW: ground = GetRawClearGround(tile) == CLEAR_ROUGH ? TREE_GROUND_ROUGH_SNOW : TREE_GROUND_SNOW_DESERT; break;
+ default: ground = TREE_GROUND_SNOW_DESERT; break;
}
+ if (GetClearGround(tile) != CLEAR_ROUGH) density = GetClearDensity(tile);
break;
default: NOT_REACHED();
@@ -163,7 +165,7 @@ static void PlaceTree(TileIndex tile, ui
/* Rerandomize ground, if neither snow nor shore */
TreeGround ground = GetTreeGround(tile);
- if (ground != TREE_GROUND_SNOW_DESERT && ground != TREE_GROUND_SHORE) {
+ if (ground != TREE_GROUND_SNOW_DESERT && ground != TREE_GROUND_ROUGH_SNOW && ground != TREE_GROUND_SHORE) {
SetTreeGroundDensity(tile, (TreeGround)GB(r, 28, 1), 3);
}
@@ -469,7 +471,7 @@ static void DrawTile_Trees(TileInfo *ti)
uint index = GB(tmp, 0, 2) + (GetTreeType(ti->tile) << 2);
/* different tree styles above one of the grounds */
- if (GetTreeGround(ti->tile) == TREE_GROUND_SNOW_DESERT &&
+ if ((GetTreeGround(ti->tile) == TREE_GROUND_SNOW_DESERT || GetTreeGround(ti->tile) == TREE_GROUND_ROUGH_SNOW) &&
GetTreeDensity(ti->tile) >= 2 &&
IsInsideMM(index, TREE_SUB_ARCTIC << 2, TREE_RAINFOREST << 2)) {
index += 164 - (TREE_SUB_ARCTIC << 2);
@@ -599,14 +601,19 @@ static void TileLoopTreesAlps(TileIndex
int k = GetTileZ(tile) - GetSnowLine() + TILE_HEIGHT;
if (k < 0) {
- if (GetTreeGround(tile) != TREE_GROUND_SNOW_DESERT) return;
- SetTreeGroundDensity(tile, TREE_GROUND_GRASS, 3);
+ switch (GetTreeGround(tile)) {
+ case TREE_GROUND_SNOW_DESERT: SetTreeGroundDensity(tile, TREE_GROUND_GRASS, 3); break;
+ case TREE_GROUND_ROUGH_SNOW: SetTreeGroundDensity(tile, TREE_GROUND_ROUGH, 3); break;
+ default: return;
+ }
} else {
uint density = min((uint)k / TILE_HEIGHT, 3);
- if (GetTreeGround(tile) != TREE_GROUND_SNOW_DESERT ||
- GetTreeDensity(tile) != density) {
- SetTreeGroundDensity(tile, TREE_GROUND_SNOW_DESERT, density);
+ if (GetTreeGround(tile) != TREE_GROUND_SNOW_DESERT && GetTreeGround(tile) != TREE_GROUND_ROUGH_SNOW) {
+ TreeGround tg = GetTreeGround(tile) == TREE_GROUND_ROUGH ? TREE_GROUND_ROUGH_SNOW : TREE_GROUND_SNOW_DESERT;
+ SetTreeGroundDensity(tile, tg, density);
+ } else if (GetTreeDensity(tile) != density) {
+ SetTreeGroundDensity(tile, GetTreeGround(tile), density);
} else {
if (GetTreeDensity(tile) == 3) {
uint32 r = Random();
@@ -709,8 +716,17 @@ static void TileLoop_Trees(TileIndex til
case TREE_GROUND_SHORE: MakeShore(tile); break;
case TREE_GROUND_GRASS: MakeClear(tile, CLEAR_GRASS, GetTreeDensity(tile)); break;
case TREE_GROUND_ROUGH: MakeClear(tile, CLEAR_ROUGH, 3); break;
+ case TREE_GROUND_ROUGH_SNOW:
+ MakeClear(tile, CLEAR_ROUGH, 3);
+ MakeSnow(tile);
+ break;
default: // snow or desert
- MakeClear(tile, _settings_game.game_creation.landscape == LT_TROPIC ? CLEAR_DESERT : CLEAR_SNOW, GetTreeDensity(tile));
+ if (_settings_game.game_creation.landscape == LT_TROPIC) {
+ MakeClear(tile, CLEAR_DESERT, GetTreeDensity(tile));
+ } else {
+ MakeClear(tile, CLEAR_GRASS, GetTreeDensity(tile));
+ MakeSnow(tile);
+ }
break;
}
}
diff --git a/src/tree_map.h b/src/tree_map.h
--- a/src/tree_map.h
+++ b/src/tree_map.h
@@ -58,6 +58,7 @@ enum TreeGround {
TREE_GROUND_ROUGH = 1, ///< some rough tile
TREE_GROUND_SNOW_DESERT = 2, ///< a desert or snow tile, depend on landscape
TREE_GROUND_SHORE = 3, ///< shore
+ TREE_GROUND_ROUGH_SNOW = 4, ///< a snow tile that is rough underneed
};
@@ -91,7 +92,7 @@ static inline TreeType GetTreeType(TileI
static inline TreeGround GetTreeGround(TileIndex t)
{
assert(IsTileType(t, MP_TREES));
- return (TreeGround)GB(_m[t].m2, 4, 2);
+ return (TreeGround)GB(_m[t].m2, 6, 3);
}
/**
@@ -116,7 +117,7 @@ static inline TreeGround GetTreeGround(T
static inline uint GetTreeDensity(TileIndex t)
{
assert(IsTileType(t, MP_TREES));
- return GB(_m[t].m2, 6, 2);
+ return GB(_m[t].m2, 4, 2);
}
/**
@@ -133,8 +134,8 @@ static inline uint GetTreeDensity(TileIn
static inline void SetTreeGroundDensity(TileIndex t, TreeGround g, uint d)
{
assert(IsTileType(t, MP_TREES)); // XXX incomplete
- SB(_m[t].m2, 4, 2, g);
- SB(_m[t].m2, 6, 2, d);
+ SB(_m[t].m2, 4, 2, d);
+ SB(_m[t].m2, 6, 3, g);
}
/**
@@ -277,7 +278,7 @@ static inline void MakeTree(TileIndex t,
{
SetTileType(t, MP_TREES);
SetTileOwner(t, OWNER_NONE);
- _m[t].m2 = density << 6 | ground << 4 | 0;
+ _m[t].m2 = ground << 6 | density << 4 | 0;
_m[t].m3 = type;
_m[t].m4 = 0 << 5 | 0 << 2;
_m[t].m5 = count << 6 | growth;
|