(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.
This commit is contained in:
ludde 2005-07-13 19:51:31 +00:00
parent 4b006aa6cf
commit 6013b327f7
15 changed files with 92 additions and 76 deletions

View File

@ -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(;;) {

View File

@ -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)))

View File

@ -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);

View File

@ -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);

View File

@ -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++) {

View File

@ -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();
}

53
map.c
View File

@ -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;
}

34
map.h
View File

@ -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)

24
misc.c
View File

@ -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);
}

View File

@ -42,7 +42,7 @@
#include <gpmi/packages/paths.h>
#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();

View File

@ -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();

View File

@ -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

View File

@ -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;

View File

@ -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) {

View File

@ -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;