From 6013b327f7d54f9d5a331b105011c238da97046f Mon Sep 17 00:00:00 2001 From: ludde Date: Wed, 13 Jul 2005 19:51:31 +0000 Subject: [PATCH] (svn r2560) Fix: various minor code changes. Added RandomTile/RandomTileSeed functions to generate a random tile. Changed landscape routines so they don't assume that the Y map side is a power of two. (support for this is not complete, though) Changed some frequently used map macros to not compute the values each time. Silence some warnings on MSVC. --- clear_cmd.c | 4 ++-- disaster_cmd.c | 6 +++--- functions.h | 3 +++ industry_cmd.c | 2 +- landscape.c | 3 +-- main_gui.c | 4 ++-- map.c | 53 +++++++++++++++++++++++++++---------------------- map.h | 34 +++++++++++++++++++++---------- misc.c | 24 ++++++++++------------ openttd.c | 12 +++++------ saveload.c | 6 +++--- stdafx.h | 2 ++ town_cmd.c | 2 +- tree_cmd.c | 8 ++++---- unmovable_cmd.c | 5 +---- 15 files changed, 92 insertions(+), 76 deletions(-) diff --git a/clear_cmd.c b/clear_cmd.c index 45c6f72d7d..773d058674 100644 --- a/clear_cmd.c +++ b/clear_cmd.c @@ -774,7 +774,7 @@ void GenerateClearTile(void) /* add hills */ i = ScaleByMapSize((Random() & 0x3FF) + 0x400); do { - tile = TILE_MASK(Random()); + tile = RandomTile(); if (IsTileType(tile, MP_CLEAR)) _m[tile].m5 = (byte)((_m[tile].m5 & ~(3<<2)) | (1<<2)); } while (--i); @@ -783,7 +783,7 @@ void GenerateClearTile(void) i = ScaleByMapSize((Random() & 0x7F) + 0x80); do { r = Random(); - tile = TILE_MASK(r); + tile = RandomTileSeed(r); if (IsTileType(tile, MP_CLEAR)) { j = ((r >> 16) & 0xF) + 5; for(;;) { diff --git a/disaster_cmd.c b/disaster_cmd.c index 19609f7dd9..90e005df5d 100644 --- a/disaster_cmd.c +++ b/disaster_cmd.c @@ -269,7 +269,7 @@ static void DisasterTick_UFO(Vehicle *v) return; } if (++v->age < 6) { - v->dest_tile = TILE_MASK(Random()); + v->dest_tile = RandomTile(); return; } v->current_order.station = 1; @@ -571,12 +571,12 @@ static void DisasterTick_4(Vehicle *v) } if (++v->age < 6) { - v->dest_tile = TILE_MASK(Random()); + v->dest_tile = RandomTile(); return; } v->current_order.station = 1; - tile_org = tile = TILE_MASK(Random()); + tile_org = tile = RandomTile(); do { if (IsTileType(tile, MP_RAILWAY) && (_m[tile].m5 & ~3) != 0xC0 && IS_HUMAN_PLAYER(GetTileOwner(tile))) diff --git a/functions.h b/functions.h index a34525f287..4960eb338a 100644 --- a/functions.h +++ b/functions.h @@ -101,6 +101,9 @@ void NORETURN CDECL error(const char *str, ...); #else uint32 Random(void); uint RandomRange(uint max); + + static inline TileIndex RandomTileSeed(uint32 r) { return TILE_MASK(r); } + static inline TileIndex RandomTile(void) { return TILE_MASK(Random()); } #endif void InitPlayerRandoms(void); diff --git a/industry_cmd.c b/industry_cmd.c index 511f40c542..fab71b42c3 100644 --- a/industry_cmd.c +++ b/industry_cmd.c @@ -1660,7 +1660,7 @@ static void PlaceInitialIndustry(byte type, int amount) do { int i = 2000; do { - if (CreateNewIndustry(TILE_MASK(Random()), type) != NULL) + if (CreateNewIndustry(RandomTile(), type) != NULL) break; } while (--i != 0); } while (--num); diff --git a/landscape.c b/landscape.c index e47a63ba94..31f134e93e 100644 --- a/landscape.c +++ b/landscape.c @@ -422,12 +422,11 @@ void RunTileLoop(void) _cur_tileloop_tile = tile; } -void InitializeLandscape(uint log_x, uint log_y) +void InitializeLandscape() { uint map_size; uint i; - InitMap(log_x, log_y); map_size = MapSize(); for (i = 0; i < map_size; i++) { diff --git a/main_gui.c b/main_gui.c index e2c05df3b0..9a62ef0657 100644 --- a/main_gui.c +++ b/main_gui.c @@ -42,7 +42,7 @@ static int _rename_what; static byte _terraform_size = 1; static byte _last_built_railtype; -extern void GenerateWorld(int mode, uint log_x, uint log_y); +extern void GenerateWorld(int mode, uint size_x, uint size_y); extern void GenerateIndustries(void); extern void GenerateTowns(void); @@ -1080,7 +1080,7 @@ static void ResetLandscape(void) _random_seeds[0][0] = InteractiveRandom(); _random_seeds[0][1] = InteractiveRandom(); - GenerateWorld(1, _patches.map_x, _patches.map_y); + GenerateWorld(1, 1<<_patches.map_x, 1<<_patches.map_y); MarkWholeScreenDirty(); } diff --git a/map.c b/map.c index 6330c660ea..2eeaa8af1c 100644 --- a/map.c +++ b/map.c @@ -5,28 +5,35 @@ #include "map.h" uint _map_log_x; -uint _map_log_y; +uint _map_size_x; +uint _map_size_y; +uint _map_tile_mask; +uint _map_size; Tile* _m = NULL; -void InitMap(uint log_x, uint log_y) +void AllocateMap(uint size_x, uint size_y) { - uint map_size; - - if (log_x < 6 || log_x > 11 || log_y < 6 || log_y > 11) + // Make sure that the map size is within the limits and that + // the x axis size is a power of 2. + if (size_x < 64 || size_x > 2048 || + size_y < 64 || size_y > 2048 || + (size_x&(size_x-1)) != 0 || + (size_y&(size_y-1)) != 0) error("Invalid map size"); - DEBUG(map, 1)("Allocating map of size %dx%d", log_x, log_y); + DEBUG(map, 1)("Allocating map of size %dx%d", size_x, size_y); - _map_log_x = log_x; - _map_log_y = log_y; - - // XXX - MSVC6 workaround - map_size = 1 << (log_x + log_y); + _map_log_x = FindFirstBit(size_x); + _map_size_x = size_x; + _map_size_y = size_y; + _map_size = size_x * size_y; + _map_tile_mask = _map_size - 1; + // free/malloc uses less memory than realloc. free(_m); - _m = malloc(map_size * sizeof(*_m)); + _m = malloc(_map_size * sizeof(*_m)); // XXX TODO handle memory shortage more gracefully if (_m == NULL) error("Failed to allocate memory for the map"); @@ -70,23 +77,21 @@ TileIndex TileAdd(TileIndex tile, TileIndexDiff add, uint ScaleByMapSize(uint n) { - int shift = (int)MapLogX() - 8 + (int)MapLogY() - 8; - - if (shift < 0) - return (n + (1 << -shift) - 1) >> -shift; - else - return n << shift; + // First shift by 12 to prevent integer overflow for large values of n. + // >>12 is safe since the min mapsize is 64x64 + // Add (1<<4)-1 to round upwards. + return (n * (MapSize() >> 12) + (1<<4) - 1) >> 4; } +// Scale relative to the circumference of the map uint ScaleByMapSize1D(uint n) { - int shift = ((int)MapLogX() - 8 + (int)MapLogY() - 8) / 2; - - if (shift < 0) - return (n + (1 << -shift) - 1) >> -shift; - else - return n << shift; + // Normal circumference for the X+Y is 256+256 = 1<<9 + // Note, not actually taking the full circumference into account, + // just half of it. + // (1<<9) - 1 is there to scale upwards. + return (n * (MapSizeX() + MapSizeY()) + (1<<9) - 1) >> 9; } diff --git a/map.h b/map.h index 95370c14e3..02513ddd03 100644 --- a/map.h +++ b/map.h @@ -3,8 +3,17 @@ #include "stdafx.h" -#define TILE_MASK(x) ((x) & ((1 << (MapLogX() + MapLogY())) - 1)) +// Putting externs inside inline functions seems to confuse the aliasing +// checking on MSVC6. Never use those variables directly. +extern uint _map_log_x; +extern uint _map_size_x; +extern uint _map_size_y; +extern uint _map_tile_mask; +extern uint _map_size; + +#define TILE_MASK(x) ((x) & _map_tile_mask) #define TILE_ASSERT(x) assert(TILE_MASK(x) == (x)); +#define RANDOM_TILE(r) TILE_MASK(r) typedef struct Tile { byte type_height; @@ -20,17 +29,18 @@ extern Tile* _m; void InitMap(uint log_x, uint log_y); +void AllocateMap(uint size_x, uint size_y); + // binary logarithm of the map size, try to avoid using this one -static inline uint MapLogX(void) { extern uint _map_log_x; return _map_log_x; } -static inline uint MapLogY(void) { extern uint _map_log_y; return _map_log_y; } +static inline uint MapLogX(void) { return _map_log_x; } /* The size of the map */ -static inline uint MapSizeX(void) { return 1 << MapLogX(); } -static inline uint MapSizeY(void) { return 1 << MapLogY(); } +static inline uint MapSizeX(void) { return _map_size_x; } +static inline uint MapSizeY(void) { return _map_size_y; } /* The maximum coordinates */ -static inline uint MapMaxX(void) { return MapSizeX() - 1; } -static inline uint MapMaxY(void) { return MapSizeY() - 1; } +static inline uint MapMaxX(void) { return _map_size_x - 1; } +static inline uint MapMaxY(void) { return _map_size_y - 1; } /* The number of tiles in the map */ -static inline uint MapSize(void) { return MapSizeX() * MapSizeY(); } +static inline uint MapSize(void) { return _map_size; } // Scale a number relative to the map size uint ScaleByMapSize(uint); // Scale relative to the number of tiles @@ -41,12 +51,16 @@ typedef int32 TileIndexDiff; static inline TileIndex TileXY(uint x, uint y) { - return (y << MapLogX()) + x; + return (y * MapSizeX()) + x; } static inline TileIndexDiff TileDiffXY(int x, int y) { - return (y << MapLogX()) + x; + // Multiplication gives much better optimization on MSVC than shifting. + // 0 << shift isn't optimized to 0 properly. + // Typically x and y are constants, and then this doesn't result + // in any actual multiplication in the assembly code.. + return (y * MapSizeX()) + x; } static inline TileIndex TileVirtXY(uint x, uint y) diff --git a/misc.c b/misc.c index 9bb3cbb55a..9e87baf975 100644 --- a/misc.c +++ b/misc.c @@ -174,7 +174,7 @@ void InitializeAirportGui(void); void InitializeDock(void); void InitializeDockGui(void); void InitializeIndustries(void); -void InitializeLandscape(uint log_x, uint log_y); +void InitializeLandscape(void); void InitializeTowns(void); void InitializeTrees(void); void InitializeSigns(void); @@ -197,10 +197,13 @@ void GenerateTrees(void); void ConvertGroundTilesIntoWaterTiles(void); -void InitializeGame(uint log_x, uint log_y) +void InitializeGame(uint size_x, uint size_y) { - // Initialize the autoreplace array. Needs to be cleared between each game uint i; + + AllocateMap(size_x, size_y); + + // Initialize the autoreplace array. Needs to be cleared between each game for (i = 0; i < lengthof(_autoreplace_array); i++) _autoreplace_array[i] = i; @@ -229,7 +232,7 @@ void InitializeGame(uint log_x, uint log_y) InitializeOrders(); InitNewsItemStructs(); - InitializeLandscape(log_x, log_y); + InitializeLandscape(); InitializeClearLand(); InitializeRail(); InitializeRailGui(); @@ -261,7 +264,7 @@ void InitializeGame(uint log_x, uint log_y) ResetObjectToPlace(); } -void GenerateWorld(int mode, uint log_x, uint log_y) +void GenerateWorld(int mode, uint size_x, uint size_y) { int i; @@ -269,7 +272,7 @@ void GenerateWorld(int mode, uint log_x, uint log_y) _current_player = OWNER_NONE; _generating_world = true; - InitializeGame(log_x, log_y); + InitializeGame(size_x, size_y); SetObjectToPlace(SPR_CURSOR_ZZZ, 0, 0, 0); // Must start economy early because of the costs. @@ -851,15 +854,8 @@ static void Save_MAPS(void) static void Load_MAPS(void) { - uint bits_x = 0; - uint bits_y = 0; - SlGlobList(_map_dimensions); - - for (; _map_dim_x > 1; _map_dim_x >>= 1) ++bits_x; - for (; _map_dim_y > 1; _map_dim_y >>= 1) ++bits_y; - - InitMap(bits_x, bits_y); + AllocateMap(_map_dim_x, _map_dim_y); } diff --git a/openttd.c b/openttd.c index 0a63fe3266..9abf6e78a9 100644 --- a/openttd.c +++ b/openttd.c @@ -42,7 +42,7 @@ #include #endif /* GPMI */ -void GenerateWorld(int mode, uint log_x, uint log_y); +void GenerateWorld(int mode, uint size_x, uint size_y); void CallLandscapeTick(void); void IncreaseDate(void); void RunOtherPlayersLoop(void); @@ -484,7 +484,7 @@ static void LoadIntroGame(void) sprintf(filename, "%sopntitle.dat", _path.second_data_dir); if (SaveOrLoad(filename, SL_LOAD) != SL_OK) #endif - GenerateWorld(1, 6, 6); // if failed loading, make empty world. + GenerateWorld(1, 64, 64); // if failed loading, make empty world. } _pause = 0; @@ -678,7 +678,7 @@ int ttd_main(int argc, char* argv[]) InitPlayerRandoms(); - GenerateWorld(1, 6, 6); // Make the viewport initialization happy + GenerateWorld(1, 64, 64); // Make the viewport initialization happy #ifdef ENABLE_NETWORK if ((network) && (_network_available)) { @@ -763,7 +763,7 @@ static void MakeNewGame(void) SetupColorsAndInitialWindow(); // Randomize world - GenerateWorld(0, _patches.map_x, _patches.map_y); + GenerateWorld(0, 1<<_patches.map_x, 1<<_patches.map_y); // In a dedicated server, the server does not play if (_network_dedicated) { @@ -795,7 +795,7 @@ static void MakeNewEditorWorld(void) SetupColorsAndInitialWindow(); // Startup the game system - GenerateWorld(1, _patches.map_x, _patches.map_y); + GenerateWorld(1, 1<<_patches.map_x, 1<<_patches.map_y); _local_player = OWNER_NONE; MarkWholeScreenDirty(); @@ -977,7 +977,7 @@ void SwitchMode(int new_mode) break; case SM_GENRANDLAND: /* Generate random land within scenario editor */ - GenerateWorld(2, _patches.map_x, _patches.map_y); + GenerateWorld(2, 1<<_patches.map_x, 1<<_patches.map_y); // XXX: set date _local_player = OWNER_NONE; MarkWholeScreenDirty(); diff --git a/saveload.c b/saveload.c index b120f05352..d2fc3748f1 100644 --- a/saveload.c +++ b/saveload.c @@ -1183,7 +1183,7 @@ static const SaveLoadFormat *GetSavegameFormat(const char *s) } // actual loader/saver function -void InitializeGame(uint log_x, uint log_y); +void InitializeGame(uint size_x, uint size_y); extern bool AfterLoadGame(uint version); extern void BeforeSaveGame(void); extern bool LoadOldSaveGame(const char *file); @@ -1307,7 +1307,7 @@ int SaveOrLoad(const char *filename, int mode) /* Load a TTDLX or TTDPatch game */ if (mode == SL_OLD_LOAD) { - InitializeGame(8, 8); // set a mapsize of 256x256 for TTDPatch games or it might get confused + InitializeGame(256, 256); // set a mapsize of 256x256 for TTDPatch games or it might get confused if (!LoadOldSaveGame(filename)) return SL_REINIT; AfterLoadGame(0); return SL_OK; @@ -1426,7 +1426,7 @@ int SaveOrLoad(const char *filename, int mode) /* Old maps were hardcoded to 256x256 and thus did not contain * any mapsize information. Pre-initialize to 256x256 to not to * confuse old games */ - InitializeGame(8, 8); + InitializeGame(256, 256); SlLoadChunks(); fmt->uninit_read(); diff --git a/stdafx.h b/stdafx.h index c7c1aa83d9..414e06ea92 100644 --- a/stdafx.h +++ b/stdafx.h @@ -8,6 +8,8 @@ #pragma warning(disable: 4100) // parameter not used #pragma warning(disable: 4244) // conversion #pragma warning(disable: 4245) // conversion +#pragma warning(disable: 4305) // 'initializing' : truncation from 'const int ' to 'char ' +#pragma warning(disable: 4018) // warning C4018: '==' : signed/unsigned mismatch #pragma warning(disable: 4201) // nameless union #pragma warning(disable: 4514) // removed unref inline #pragma warning(disable: 4127) // constant conditional expression diff --git a/town_cmd.c b/town_cmd.c index 13df9d103c..20e29569ed 100644 --- a/town_cmd.c +++ b/town_cmd.c @@ -1072,7 +1072,7 @@ Town *CreateRandomTown(uint attempts) do { // Generate a tile index not too close from the edge - tile = TILE_MASK(Random()); + tile = RandomTile(); if (DistanceFromEdge(tile) < 20) continue; diff --git a/tree_cmd.c b/tree_cmd.c index 66939a7d5a..1792056700 100644 --- a/tree_cmd.c +++ b/tree_cmd.c @@ -96,7 +96,7 @@ static void PlaceMoreTrees(void) { int i = ScaleByMapSize((Random() & 0x1F) + 25); do { - DoPlaceMoreTrees(TILE_MASK(Random())); + DoPlaceMoreTrees(RandomTile()); } while (--i); } @@ -109,7 +109,7 @@ void PlaceTreesRandomly(void) i = ScaleByMapSize(1000); do { r = Random(); - tile = TILE_MASK(r); + tile = RandomTileSeed(r); /* Only on clear tiles, and NOT on farm-tiles or rocks */ if (IsTileType(tile, MP_CLEAR) && (_m[tile].m5 & 0x1F) != 0x0F && (_m[tile].m5 & 0x1C) != 8) { PlaceTree(tile, r, 0); @@ -122,7 +122,7 @@ void PlaceTreesRandomly(void) do { r = Random(); - tile = TILE_MASK(r); + tile = RandomTileSeed(r); if (IsTileType(tile, MP_CLEAR) && GetMapExtraBits(tile) == 2) { PlaceTree(tile, r, 0); } @@ -602,7 +602,7 @@ void OnTick_Trees(void) /* place a tree at a random rainforest spot */ if (_opt.landscape == LT_DESERT && - (r=Random(),tile=TILE_MASK(r),GetMapExtraBits(tile)==2) && + (r=Random(),tile=RandomTileSeed(r),GetMapExtraBits(tile)==2) && IsTileType(tile, MP_CLEAR) && (m=_m[tile].m5&0x1C, m<=4) && (tree=GetRandomTreeType(tile, r>>24)) >= 0) { diff --git a/unmovable_cmd.c b/unmovable_cmd.c index f18ebaa081..e44649bcec 100644 --- a/unmovable_cmd.c +++ b/unmovable_cmd.c @@ -347,10 +347,7 @@ void GenerateUnmovables(void) i = ScaleByMapSize(1000); j = ScaleByMapSize(40); // maximum number of radio towers on the map do { - r = Random(); - tile = r % MapSize(); -// TILE_MASK seems to be not working correctly. Radio masts accumulate in one area. -// tile = TILE_MASK(r); + tile = RandomTile(); if (IsTileType(tile, MP_CLEAR) && GetTileSlope(tile, &h) == 0 && h >= 32) { if(!checkRadioTowerNearby(tile)) continue;