diff --git a/src/clear_cmd.cpp b/src/clear_cmd.cpp --- a/src/clear_cmd.cpp +++ b/src/clear_cmd.cpp @@ -16,6 +16,7 @@ #include "tunnel_map.h" #include "bridge_map.h" #include "bridge.h" +#include "landscape.h" #include "variables.h" #include "table/sprites.h" #include "unmovable_map.h" @@ -620,7 +621,7 @@ void TileLoopClearHelper(TileIndex tile) /* convert into snowy tiles */ static void TileLoopClearAlps(TileIndex tile) { - int k = GetTileZ(tile) - _opt.snow_line + TILE_HEIGHT; + int k = GetTileZ(tile) - GetSnowLine() + TILE_HEIGHT; if (k < 0) { // well below the snow line if (!IsClearGround(tile, CLEAR_SNOW)) return; diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -12,6 +12,7 @@ #include "table/sprites.h" #include "map.h" #include "tile.h" +#include "landscape.h" #include "viewport.h" #include "command.h" #include "industry.h" @@ -814,7 +815,7 @@ static void PlantFarmField(TileIndex til int type; if (_opt.landscape == LT_HILLY) { - if (GetTileZ(tile) + TILE_HEIGHT * 2 >= _opt.snow_line) + if (GetTileZ(tile) + TILE_HEIGHT * 2 >= GetSnowLine()) return; } @@ -1016,7 +1017,7 @@ static bool CheckNewIndustry_NULL(TileIn static bool CheckNewIndustry_Forest(TileIndex tile) { if (_opt.landscape == LT_HILLY) { - if (GetTileZ(tile) < _opt.snow_line + TILE_HEIGHT * 2U) { + if (GetTileZ(tile) < HighestSnowLine() + TILE_HEIGHT * 2U) { _error_message = STR_4831_FOREST_CAN_ONLY_BE_PLANTED; return false; } @@ -1048,7 +1049,7 @@ static bool CheckNewIndustry_OilRig(Tile static bool CheckNewIndustry_Farm(TileIndex tile) { if (_opt.landscape == LT_HILLY) { - if (GetTileZ(tile) + TILE_HEIGHT * 2 >= _opt.snow_line) { + if (GetTileZ(tile) + TILE_HEIGHT * 2 >= HighestSnowLine()) { _error_message = STR_0239_SITE_UNSUITABLE; return false; } diff --git a/src/landscape.cpp b/src/landscape.cpp --- a/src/landscape.cpp +++ b/src/landscape.cpp @@ -5,6 +5,7 @@ #include "bridge_map.h" #include "heightmap.h" #include "clear_map.h" +#include "date.h" #include "functions.h" #include "map.h" #include "player.h" @@ -14,6 +15,7 @@ #include #include "viewport.h" #include "command.h" +#include "landscape.h" #include "vehicle.h" #include "variables.h" #include "void_map.h" @@ -61,6 +63,7 @@ const Slope _inclined_tileh[] = { SLOPE_NWS, SLOPE_WSE, SLOPE_SEN, SLOPE_ENW }; +SnowLine *_snow_line = NULL; uint GetPartialZ(int x, int y, Slope corners) { @@ -302,6 +305,62 @@ void GetTileDesc(TileIndex tile, TileDes _tile_type_procs[GetTileType(tile)]->get_tile_desc_proc(tile, td); } +/** + * Has a snow line table already been loaded. + * @return true if the table has been loaded already. + */ +bool IsSnowLineSet(void) +{ + return _snow_line != NULL; +} + +/** + * Set a variable snow line, as loaded from a newgrf file. + * @param table the 12 * 32 byte table containing the snowline for each day + */ +void SetSnowLine(byte table[SNOW_LINE_MONTHS][SNOW_LINE_DAYS]) +{ + _snow_line = CallocT(1); + memcpy(_snow_line->table, table, sizeof(_snow_line->table)); + + for (uint i = 0; i < SNOW_LINE_MONTHS; i++) { + for (uint j = 0; j < SNOW_LINE_DAYS; j++) { + _snow_line->highest_value = max(_snow_line->highest_value, table[i][j]); + } + } +} + +/** + * Get the current snow line, either variable or static. + * @return the snow line height. + */ +byte GetSnowLine(void) +{ + if (_snow_line == NULL) return _opt.snow_line; + + YearMonthDay ymd; + ConvertDateToYMD(_date, &ymd); + return _snow_line->table[ymd.month][ymd.day]; +} + +/** + * Get the highest possible snow line height, either variable or static. + * @return the highest snow line height. + */ +byte HighestSnowLine(void) +{ + return _snow_line == NULL ? _opt.snow_line : _snow_line->highest_value; +} + +/** + * Clear the variable snow line table and free the memory. + */ +void ClearSnowLine(void) +{ + free(_snow_line); + _snow_line = NULL; +} + /** Clear a piece of landscape * @param tile tile to clear * @param flags of operation to conduct diff --git a/src/landscape.h b/src/landscape.h new file mode 100644 --- /dev/null +++ b/src/landscape.h @@ -0,0 +1,19 @@ +/* $Id$ */ + +/** @file landscape.h */ + +enum { + SNOW_LINE_MONTHS = 12, + SNOW_LINE_DAYS = 32, +}; + +struct SnowLine { + byte table[SNOW_LINE_MONTHS][SNOW_LINE_DAYS]; + byte highest_value; +}; + +bool IsSnowLineSet(void); +void SetSnowLine(byte table[SNOW_LINE_MONTHS][SNOW_LINE_DAYS]); +byte GetSnowLine(void); +byte HighestSnowLine(void); +void ClearSnowLine(void); diff --git a/src/newgrf.cpp b/src/newgrf.cpp --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -27,6 +27,7 @@ #include "fontcache.h" #include "date.h" #include "currency.h" +#include "landscape.h" #include "sound.h" #include "newgrf_config.h" #include "newgrf_house.h" @@ -1510,6 +1511,22 @@ static bool GlobalVarChangeInfo(uint gvi break; case 0x10: // 12 * 32 * B Snow line height table + if (numinfo > 1 || IsSnowLineSet()) { + grfmsg(1, "GlobalVarChangeInfo: The snowline can only be set once (%d)", numinfo); + } else if (len < SNOW_LINE_MONTHS * SNOW_LINE_DAYS) { + grfmsg(1, "GlobalVarChangeInfo: Not enough entries set in the snowline table (%d)", len); + } else { + byte table[SNOW_LINE_MONTHS][SNOW_LINE_DAYS]; + + for (uint i = 0; i < SNOW_LINE_MONTHS; i++) { + for (uint j = 0; j < SNOW_LINE_DAYS; j++) { + table[i][j] = grf_load_byte(&buf); + } + } + SetSnowLine(table); + } + break; + default: ret = true; } @@ -3973,6 +3990,9 @@ static void ResetNewGRFData() ResetStationClasses(); ResetCustomStations(); + /* Reset the snowline table. */ + ClearSnowLine(); + /* Reset NewGRF files */ ResetNewGRF(); diff --git a/src/newgrf_house.cpp b/src/newgrf_house.cpp --- a/src/newgrf_house.cpp +++ b/src/newgrf_house.cpp @@ -8,6 +8,7 @@ #include "variables.h" #include "debug.h" #include "viewport.h" +#include "landscape.h" #include "date.h" #include "town.h" #include "town_map.h" @@ -252,7 +253,7 @@ static uint32 GetTerrainType(TileIndex t { switch (_opt.landscape) { case LT_DESERT: return GetTropicZone(tile) == TROPICZONE_DESERT ? 1 : 2; - case LT_HILLY: return GetTileZ(tile) >= _opt.snow_line ? 4 : 0; + case LT_HILLY: return GetTileZ(tile) >= GetSnowLine() ? 4 : 0; default: return 0; } } diff --git a/src/newgrf_spritegroup.cpp b/src/newgrf_spritegroup.cpp --- a/src/newgrf_spritegroup.cpp +++ b/src/newgrf_spritegroup.cpp @@ -4,6 +4,7 @@ #include "openttd.h" #include "variables.h" #include "macros.h" +#include "landscape.h" #include "oldpool.h" #include "newgrf_callbacks.h" #include "newgrf_spritegroup.h" @@ -91,7 +92,7 @@ static inline uint32 GetVariable(const R case 0x1A: return UINT_MAX; case 0x1B: return GB(_display_opt, 0, 6); case 0x1C: return object->last_value; - case 0x20: return _opt.landscape == LT_HILLY ? _opt.snow_line : 0xFF; + case 0x20: return _opt.landscape == LT_HILLY ? GetSnowLine() : 0xFF; /* Not a common variable, so evalute the feature specific variables */ default: return object->GetVariable(object, variable, parameter, available); diff --git a/src/newgrf_station.cpp b/src/newgrf_station.cpp --- a/src/newgrf_station.cpp +++ b/src/newgrf_station.cpp @@ -6,6 +6,7 @@ #include "openttd.h" #include "variables.h" #include "functions.h" +#include "landscape.h" #include "debug.h" #include "sprite.h" #include "table/sprites.h" @@ -370,7 +371,7 @@ static uint32 StationGetVariable(const R case 0x40: return GetPlatformInfoHelper(tile, false, false, false); case 0x41: return GetPlatformInfoHelper(tile, true, false, false); case 0x42: /* Terrain and rail type */ - return ((_opt.landscape == LT_HILLY && GetTileZ(tile) > _opt.snow_line) ? 4 : 0) | + return ((_opt.landscape == LT_HILLY && GetTileZ(tile) > GetSnowLine()) ? 4 : 0) | (_opt.landscape == LT_DESERT ? GetTropicZone(tile) : 0) | (GetRailType(tile) << 8); case 0x43: return st->owner; /* Station owner */ diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -12,6 +12,7 @@ #include "table/sprites.h" #include "table/strings.h" #include "map.h" +#include "landscape.h" #include "tile.h" #include "town_map.h" #include "tunnel_map.h" @@ -1738,7 +1739,7 @@ static void TileLoop_Track(TileIndex til switch (_opt.landscape) { case LT_HILLY: - if (GetTileZ(tile) > _opt.snow_line) { + if (GetTileZ(tile) > GetSnowLine()) { new_ground = RAIL_GROUND_ICE_DESERT; goto set_ground; } diff --git a/src/road_cmd.cpp b/src/road_cmd.cpp --- a/src/road_cmd.cpp +++ b/src/road_cmd.cpp @@ -12,6 +12,7 @@ #include "table/strings.h" #include "functions.h" #include "map.h" +#include "landscape.h" #include "tile.h" #include "town_map.h" #include "vehicle.h" @@ -864,7 +865,7 @@ static void TileLoop_Road(TileIndex tile { switch (_opt.landscape) { case LT_HILLY: - if (IsOnSnow(tile) != (GetTileZ(tile) > _opt.snow_line)) { + if (IsOnSnow(tile) != (GetTileZ(tile) > GetSnowLine())) { ToggleSnow(tile); MarkTileDirtyByTile(tile); } diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -11,6 +11,7 @@ #include "table/strings.h" #include "table/sprites.h" #include "map.h" +#include "landscape.h" #include "tile.h" #include "town_map.h" #include "tunnel_map.h" @@ -1700,7 +1701,7 @@ static void UpdateTownGrowRate(Town *t) } if (_opt.landscape == LT_HILLY) { - if (TilePixelHeight(t->xy) >= _opt.snow_line && t->act_food == 0 && t->population > 90) + if (TilePixelHeight(t->xy) >= GetSnowLine() && t->act_food == 0 && t->population > 90) return; } else if (_opt.landscape == LT_DESERT) { if (GetTropicZone(t->xy) == TROPICZONE_DESERT && (t->act_food==0 || t->act_water==0) && t->population > 60) diff --git a/src/tree_cmd.cpp b/src/tree_cmd.cpp --- a/src/tree_cmd.cpp +++ b/src/tree_cmd.cpp @@ -9,6 +9,7 @@ #include "table/tree_land.h" #include "functions.h" #include "map.h" +#include "landscape.h" #include "tile.h" #include "tree_map.h" #include "viewport.h" @@ -53,7 +54,7 @@ static void PlaceTree(TileIndex tile, ui MakeTree(tile, tree, GB(r, 22, 2), min(GB(r, 16, 3), 6), TREE_GROUND_GRASS, 0); // above snowline? - if (_opt.landscape == LT_HILLY && GetTileZ(tile) > _opt.snow_line) { + if (_opt.landscape == LT_HILLY && GetTileZ(tile) > GetSnowLine()) { SetTreeGroundDensity(tile, TREE_GROUND_SNOW_DESERT, 3); SetTreeCounter(tile, (TreeGround)GB(r, 24, 3)); } else { @@ -150,7 +151,7 @@ void PlaceTreesRandomly() j = GetTileZ(tile) / TILE_HEIGHT * 2; while (j--) { /* Above snowline more trees! */ - if (_opt.landscape == LT_HILLY && ht > _opt.snow_line) { + if (_opt.landscape == LT_HILLY && ht > GetSnowLine()) { PlaceTreeAtSameHeight(tile, ht); PlaceTreeAtSameHeight(tile, ht); }; @@ -496,7 +497,7 @@ static void TileLoopTreesDesert(TileInde static void TileLoopTreesAlps(TileIndex tile) { - int k = GetTileZ(tile) - _opt.snow_line + TILE_HEIGHT; + int k = GetTileZ(tile) - GetSnowLine() + TILE_HEIGHT; if (k < 0) { if (GetTreeGround(tile) != TREE_GROUND_SNOW_DESERT) return; diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp --- a/src/tunnelbridge_cmd.cpp +++ b/src/tunnelbridge_cmd.cpp @@ -14,6 +14,7 @@ #include "table/strings.h" #include "functions.h" #include "map.h" +#include "landscape.h" #include "tile.h" #include "tunnel_map.h" #include "unmovable_map.h" @@ -1178,7 +1179,7 @@ static void TileLoop_TunnelBridge(TileIn bool snow_or_desert = IsTunnelTile(tile) ? HasTunnelSnowOrDesert(tile) : HasBridgeSnowOrDesert(tile); switch (_opt.landscape) { case LT_HILLY: - if (snow_or_desert != (GetTileZ(tile) > _opt.snow_line)) { + if (snow_or_desert != (GetTileZ(tile) > GetSnowLine())) { if (IsTunnelTile(tile)) { SetTunnelSnowOrDesert(tile, !snow_or_desert); } else {