(svn r11091) -Codechange: Partial rewrite of the road management code of towns, in order to make it more readable and with improved performance. (FS#1161 by skidd13)

This commit is contained in:
belugas 2007-09-12 23:56:21 +00:00
parent f2dc723da5
commit 1e4f8d7a23
2 changed files with 198 additions and 197 deletions

View File

@ -126,7 +126,7 @@ static inline RoadBits ComplementRoadBits(RoadBits r)
*/
static inline RoadBits DiagDirToRoadBits(DiagDirection d)
{
return (RoadBits)(1U << (3 ^ d));
return (RoadBits)(ROAD_NW << (3 ^ d));
}
/**

View File

@ -121,6 +121,28 @@ uint OriginalTileRandomiser(uint x, uint y)
return variant;
}
/**
* Return a random direction
*
* @return a random direction
*/
static inline DiagDirection RandomDiagDir()
{
return (DiagDirection)(3 & Random());
}
/**
* Move a TileIndex into a diagonal direction.
*
* @param tile The current tile
* @param dir The direction in which we want to step
* @return the moved tile
*/
static inline TileIndex AddDiagDirToTileIndex(TileIndex tile, DiagDirection dir)
{
return TILE_ADD(tile, TileOffsByDiagDir(dir));
}
/**
* House Tile drawing handler.
* Part of the tile loop process
@ -567,29 +589,6 @@ static void ChangeTileOwner_Town(TileIndex tile, PlayerID old_player, PlayerID n
/* not used */
}
static const TileIndexDiffC _roadblock_tileadd[] = {
{ 0, -1},
{ 1, 0},
{ 0, 1},
{-1, 0},
/* Store the first 3 elements again.
* Lets us rotate without using &3. */
{ 0, -1},
{ 1, 0},
{ 0, 1}
};
/**
* Distance multiplyer
* Defines the possible distances between 2 road tiles
*/
enum RoadBlockTitleDistance {
RB_TILE_DIST1 = 1, ///< 1 tile between
RB_TILE_DIST2, ///< 2 tiles between
};
static bool GrowTown(Town *t);
static void TownTickHandler(Town *t)
@ -627,7 +626,15 @@ void OnTick_Town()
}
}
static RoadBits GetTownRoadMask(TileIndex tile)
/**
* Return the RoadBits of a tile
*
* @note There are many other functions doing things like that.
* @note Needs to be checked for needlessness.
* @param tile The tile we want to analyse
* @return The roadbits of the given tile
*/
static RoadBits GetTownRoadBits(TileIndex tile)
{
TrackBits b = GetAnyRoadTrackBits(tile, ROADTYPE_ROAD);
RoadBits r = ROAD_NONE;
@ -649,22 +656,48 @@ static RoadBits GetTownRoadMask(TileIndex tile)
* @param dir target direction
* @param dist_multi distance multiplyer
* @return true if one of the neighboring tiles at the
* given distance is a road tile else
* given distance is a road tile else false
*/
static bool IsNeighborRoadTile(TileIndex tile, int dir, RoadBlockTitleDistance dist_multi)
static bool IsNeighborRoadTile(TileIndex tile, DiagDirection dir, uint dist_multi)
{
return (HASBIT(GetTownRoadMask(TILE_ADD(tile, dist_multi * ToTileIndexDiff(_roadblock_tileadd[dir + 1]))), dir ^ 2) ||
HASBIT(GetTownRoadMask(TILE_ADD(tile, dist_multi * ToTileIndexDiff(_roadblock_tileadd[dir + 3]))), dir ^ 2) ||
HASBIT(GetTownRoadMask(TILE_ADD(tile, dist_multi * (ToTileIndexDiff(_roadblock_tileadd[dir + 1]) + ToTileIndexDiff(_roadblock_tileadd[dir + 2])))), dir) ||
HASBIT(GetTownRoadMask(TILE_ADD(tile, dist_multi * (ToTileIndexDiff(_roadblock_tileadd[dir + 3]) + ToTileIndexDiff(_roadblock_tileadd[dir + 2])))), dir));
static TileIndexDiff tid_lt[3]; ///< lookup table for the used diff values
tid_lt[0] = TileOffsByDiagDir(ChangeDiagDir(dir, DIAGDIRDIFF_90RIGHT));
tid_lt[1] = TileOffsByDiagDir(ChangeDiagDir(dir, DIAGDIRDIFF_90LEFT));
tid_lt[2] = TileOffsByDiagDir(ReverseDiagDir(dir));
/* We add 1 to the distance because we want to get 1 for
* the min distance multiplyer and not 0.
* Therefore we start at 4. The 4 is used because
* there are 4 tiles per distance step to check.
*/
dist_multi = (dist_multi + 1) * 4;
for (uint pos = 4; pos < dist_multi; pos++) {
TileIndexDiff cur = 0;
/* For each even value of pos add the right TileIndexDiff
* for each uneven value the left TileIndexDiff
* for each with 2nd bit set (2,3,6,7,..) add the reversed TileIndexDiff
*/
cur += tid_lt[(pos & 1) ? 0 : 1];
if (pos & 2) cur += tid_lt[2];
cur = (uint)(pos / 4) * cur; ///< Multiply for the fitting distance
if (GetTownRoadBits(TILE_ADD(tile, cur)) & DiagDirToRoadBits((pos & 2) ? dir : ReverseDiagDir(dir))) return true;
}
return false;
}
static bool IsRoadAllowedHere(TileIndex tile, int dir)
/**
* Check if a Road is allowed on a given tile
*
* @param tile The target tile
* @param dir The direction in which we want to extend the town
* @return true if it is allowed else false
*/
static bool IsRoadAllowedHere(TileIndex tile, DiagDirection dir)
{
if (TileX(tile) < 2 || TileY(tile) < 2 || MapMaxX() <= TileX(tile) || MapMaxY() <= TileY(tile)) return false;
Slope k;
Slope slope;
Slope cur_slope, desired_slope;
/* If this assertion fails, it might be because the world contains
* land at the edges. This is not ok. */
@ -672,47 +705,44 @@ static bool IsRoadAllowedHere(TileIndex tile, int dir)
for (;;) {
/* Check if there already is a road at this point? */
if (GetAnyRoadTrackBits(tile, ROADTYPE_ROAD) == 0) {
if (GetTownRoadBits(tile) == ROAD_NONE) {
/* No, try to build one in the direction.
* if that fails clear the land, and if that fails exit.
* This is to make sure that we can build a road here later. */
if (CmdFailed(DoCommand(tile, (dir & ROAD_NW ? ROAD_X : ROAD_Y), 0, DC_AUTO, CMD_BUILD_ROAD)) &&
if (CmdFailed(DoCommand(tile, ((dir == DIAGDIR_NW || dir == DIAGDIR_SE) ? ROAD_X : ROAD_Y), 0, DC_AUTO, CMD_BUILD_ROAD)) &&
CmdFailed(DoCommand(tile, 0, 0, DC_AUTO, CMD_LANDSCAPE_CLEAR)))
return false;
}
slope = GetTileSlope(tile, NULL);
if (slope == SLOPE_FLAT) {
cur_slope = GetTileSlope(tile, NULL);
if (cur_slope == SLOPE_FLAT) {
no_slope:
/* Tile has no slope */
switch (_patches.town_layout) {
default: NOT_REACHED();
case TL_ORIGINAL: /* Disallow the road if any neighboring tile has a road (distance: 1) */
return !IsNeighborRoadTile(tile, dir, RB_TILE_DIST1);
return !IsNeighborRoadTile(tile, dir, 1);
case TL_BETTER_ROADS: /* Disallow the road if any neighboring tile has a road (distance: 1 and 2). */
return !(IsNeighborRoadTile(tile, dir, RB_TILE_DIST1) ||
IsNeighborRoadTile(tile, dir, RB_TILE_DIST2));
return !IsNeighborRoadTile(tile, dir, 2);
}
}
/* If the tile is not a slope in the right direction, then
* maybe terraform some. */
k = (dir & ROAD_NW) ? SLOPE_NE : SLOPE_NW;
if (k != slope && ComplementSlope(k) != slope) {
desired_slope = (dir == DIAGDIR_NW || dir == DIAGDIR_SE) ? SLOPE_NE : SLOPE_NW;
if (desired_slope != cur_slope && ComplementSlope(desired_slope) != cur_slope) {
uint32 r = Random();
if (CHANCE16I(1, 8, r) && !_generating_world) {
CommandCost res;
if (CHANCE16I(1, 16, r)) {
res = DoCommand(tile, slope, 0, DC_EXEC | DC_AUTO | DC_NO_WATER,
CMD_TERRAFORM_LAND);
res = DoCommand(tile, cur_slope, 0, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_TERRAFORM_LAND);
} else {
/* Note: Do not replace " ^ 0xF" with ComplementSlope(). The slope might be steep. */
res = DoCommand(tile, slope ^ 0xF, 1, DC_EXEC | DC_AUTO | DC_NO_WATER,
CMD_TERRAFORM_LAND);
res = DoCommand(tile, cur_slope ^ 0xF, 1, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_TERRAFORM_LAND);
}
if (CmdFailed(res) && CHANCE16I(1, 3, r)) {
/* We can consider building on the slope, though. */
@ -759,76 +789,60 @@ static void LevelTownLand(TileIndex tile)
*
* @param t current town
* @param tile tile in reference to the town
* @param dir The direction to which we are growing ATM
* @return the RoadBit of the current tile regarding
* the selected town layout
*/
static RoadBits GetTownRoadGridElement(Town* t, TileIndex tile)
static RoadBits GetTownRoadGridElement(Town* t, TileIndex tile, DiagDirection dir)
{
/* align the grid to the downtown */
TileIndexDiffC grid_pos = TileIndexToTileIndexDiffC(t->xy, tile); ///< Vector from downtown to the tile
/* lx, ly description:
* @li lx and ly are true if the tile is a crossing tile.
* @li lx xor ly are true if the tile is a straight road tile.
* @li lx and ly are false if the tile is a house tile.
*/
bool lx, ly;
RoadBits rcmd = ROAD_NONE;
switch (_patches.town_layout) {
default: NOT_REACHED();
case TL_2X2_GRID:
lx = ((grid_pos.x % 3) == 0);
ly = ((grid_pos.y % 3) == 0);
if ((grid_pos.x % 3) == 0) rcmd |= ROAD_Y;
if ((grid_pos.y % 3) == 0) rcmd |= ROAD_X;
break;
case TL_3X3_GRID:
lx = ((grid_pos.x % 4) == 0);
ly = ((grid_pos.y % 4) == 0);
if ((grid_pos.x % 4) == 0) rcmd |= ROAD_Y;
if ((grid_pos.y % 4) == 0) rcmd |= ROAD_X;
break;
}
/* generate the basic grid structure */
if (!lx && !ly) { ///< It is a house tile
return ROAD_NONE;
} else if (lx && !ly) { ///< It is a Y-dir road tile
return ROAD_Y;
} else if (!lx && ly) { ///< It is a X-dir road tile
return ROAD_X;
} else { ///< It is a crossing tile
/* Presets for junctions on slopes
* not nice :( */
switch (GetTileSlope(tile, NULL)) {
case SLOPE_W:
return ROAD_NW | ROAD_SW;
case SLOPE_S:
return ROAD_SE | ROAD_SW;
case SLOPE_SW:
return ROAD_Y | ROAD_SW;
case SLOPE_E:
return ROAD_NE | ROAD_SE;
case SLOPE_SE:
return ROAD_X | ROAD_SE;
case SLOPE_N:
return ROAD_NW | ROAD_NE;
case SLOPE_NW:
return ROAD_X | ROAD_NW;
case SLOPE_NE:
return ROAD_Y | ROAD_NE;
case SLOPE_STEEP_W:
case SLOPE_STEEP_N:
return ROAD_X;
case SLOPE_STEEP_S:
case SLOPE_STEEP_E:
return ROAD_Y;
default:
return ROAD_ALL;
}
/* Skip slope optimisations */
if (rcmd == ROAD_NONE) return rcmd;
RoadBits rb_template;
switch (GetTileSlope(tile, NULL)) {
default: rb_template = ROAD_ALL; break;
case SLOPE_W: rb_template = ROAD_NW | ROAD_SW; break;
case SLOPE_SW: rb_template = ROAD_Y | ROAD_SW; break;
case SLOPE_S: rb_template = ROAD_SE | ROAD_SW; break;
case SLOPE_SE: rb_template = ROAD_X | ROAD_SE; break;
case SLOPE_E: rb_template = ROAD_NE | ROAD_SE; break;
case SLOPE_NE: rb_template = ROAD_Y | ROAD_NE; break;
case SLOPE_N: rb_template = ROAD_NW | ROAD_NE; break;
case SLOPE_NW: rb_template = ROAD_X | ROAD_NW; break;
case SLOPE_STEEP_W:
case SLOPE_STEEP_S:
case SLOPE_STEEP_E:
case SLOPE_STEEP_N:
rb_template = (dir == DIAGDIR_NE || dir == DIAGDIR_SW) ? ROAD_X : ROAD_Y;
break;
}
/* Check for the right growth dir */
if (DiagDirToRoadBits(ReverseDiagDir(dir)) & (rcmd & rb_template)) return rb_template & rcmd;
return (dir == DIAGDIR_NE || dir == DIAGDIR_SW) ? ROAD_X : ROAD_Y;
}
/**
* Check there are enougth neighbor house tiles next to the current tile
* Check there are enough neighbor house tiles next to the current tile
*
* @param tile current tile
* @return true if there are more than 2 house tiles next
@ -844,8 +858,8 @@ static bool AreNeighborsHouseTiles(TileIndex tile)
}
/* Check the tiles E,N,W and S of the current tile. */
for (uint i = 0; i < 4; i++) {
if (IsTileType(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[i])), MP_HOUSE)) {
for (DiagDirection i = DIAGDIR_BEGIN; i < DIAGDIR_END; i++) {
if (IsTileType(AddDiagDirToTileIndex(tile, i), MP_HOUSE)) {
counter++;
}
@ -870,25 +884,20 @@ static bool AreNeighborsHouseTiles(TileIndex tile)
* @li Forbid roads, only build houses
* @li TL_NO_ROADS
*
* @param tile_ptr current tile
* @param mask current tiles RoadBits
* @param block road block
* @param t1 current town
* @param tile_ptr The current tile
* @param cur_rb The current tiles RoadBits
* @param target_dir The target road dir
* @param t1 The current town
*/
static void GrowTownInTile(TileIndex* tile_ptr, RoadBits mask, int block, Town* t1)
static void GrowTownInTile(TileIndex* tile_ptr, RoadBits cur_rb, DiagDirection target_dir, Town* t1)
{
RoadBits rcmd;
TileIndex tmptile;
DiagDirection i;
int j;
TileIndex tile = *tile_ptr;
RoadBits rcmd = ROAD_NONE; ///< RoadBits for the road construction command
TileIndex tmptile; ///< Dummy tile for various things
TileIndex tile = *tile_ptr; ///< The main tile on which we base our growth
TILE_ASSERT(tile);
if (mask == 0) {
int a;
int b;
if (cur_rb == ROAD_NONE) {
/* Tile has no road. First reset the status counter
* to say that this is the last iteration. */
_grow_town_result = 0;
@ -905,37 +914,29 @@ static void GrowTownInTile(TileIndex* tile_ptr, RoadBits mask, int block, Town*
case TL_3X3_GRID:
case TL_2X2_GRID:
rcmd = GetTownRoadGridElement(t1, tile);
if (rcmd == ROAD_NONE) {
return;
}
rcmd = GetTownRoadGridElement(t1, tile, target_dir);
if (rcmd == ROAD_NONE) return;
break;
case TL_BETTER_ROADS:
case TL_ORIGINAL:
if (!IsRoadAllowedHere(tile, block)) {
return;
}
if (!IsRoadAllowedHere(tile, target_dir)) return;
DiagDirection source_dir = ReverseDiagDir(target_dir);
/* Randomize new road block numbers */
a = block;
b = block ^ 2;
if (CHANCE16(1, 4)) {
do {
a = GB(Random(), 0, 2);
} while (a == b);
/* Randomize a new target dir */
do target_dir = RandomDiagDir(); while (target_dir == source_dir);
}
if (!IsRoadAllowedHere(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[a])), a)) {
if (!IsRoadAllowedHere(AddDiagDirToTileIndex(tile, target_dir), target_dir)) {
/* A road is not allowed to continue the randomized road,
* return if the road we're trying to build is curved. */
if (a != (b ^ 2)) {
return;
}
* return if the road we're trying to build is curved. */
if (target_dir != ReverseDiagDir(source_dir)) return;
/* Return if neither side of the new road is a house */
if (!IsTileType(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[a + 1])), MP_HOUSE) &&
!IsTileType(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[a + 3])), MP_HOUSE)) {
if (!IsTileType(AddDiagDirToTileIndex(tile, ChangeDiagDir(target_dir, DIAGDIRDIFF_90RIGHT)), MP_HOUSE) &&
!IsTileType(AddDiagDirToTileIndex(tile, ChangeDiagDir(target_dir, DIAGDIRDIFF_90LEFT)), MP_HOUSE)) {
return;
}
@ -943,13 +944,14 @@ static void GrowTownInTile(TileIndex* tile_ptr, RoadBits mask, int block, Town*
* at any side of the new road. */
}
rcmd = (RoadBits)((ROAD_NW << a) + (ROAD_NW << b));
rcmd = DiagDirToRoadBits(target_dir) | DiagDirToRoadBits(source_dir);
break;
}
} else if (block < 5 && !HASBIT(mask, block ^ 2)) {
} else if (target_dir < (DiagDirection)5 && !(cur_rb & DiagDirToRoadBits(ReverseDiagDir(target_dir)))) {
/* Continue building on a partial road.
* Always OK. */
* Should be allways OK, so we only generate
* the fitting RoadBits */
_grow_town_result = 0;
switch (_patches.town_layout) {
@ -960,18 +962,17 @@ static void GrowTownInTile(TileIndex* tile_ptr, RoadBits mask, int block, Town*
case TL_3X3_GRID:
case TL_2X2_GRID:
rcmd = GetTownRoadGridElement(t1, tile);
rcmd = GetTownRoadGridElement(t1, tile, target_dir);
break;
case TL_BETTER_ROADS:
case TL_ORIGINAL:
rcmd = (RoadBits)(ROAD_NW << (block ^ 2));
rcmd = DiagDirToRoadBits(ReverseDiagDir(target_dir));
break;
}
} else {
int i;
bool allow_house = false;
TileIndex tmptile2;
bool allow_house = false; ///< Value which decides if we want to construct a house
TileIndex tmptile2; ///< Yet another dummy tile
/* Reached a tunnel/bridge? Then continue at the other side of it. */
if (IsTileType(tile, MP_TUNNELBRIDGE)) {
@ -985,13 +986,13 @@ static void GrowTownInTile(TileIndex* tile_ptr, RoadBits mask, int block, Town*
/* Possibly extend the road in a direction.
* Randomize a direction and if it has a road, bail out. */
i = GB(Random(), 0, 2);
if (HASBIT(mask, i)) return;
target_dir = RandomDiagDir();
if (cur_rb & DiagDirToRoadBits(target_dir)) return;
/* This is the tile we will reach if we extend to this direction. */
tmptile = TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[i]));
tmptile = AddDiagDirToTileIndex(tile, target_dir);
/* Don't do it if it reaches to water. */
/* Don't walk into water. */
if (IsClearWaterTile(tmptile)) return;
switch (_patches.town_layout) {
@ -1003,19 +1004,19 @@ static void GrowTownInTile(TileIndex* tile_ptr, RoadBits mask, int block, Town*
case TL_3X3_GRID: /* Use 2x2 grid afterwards! */
/* Fill gap if house has enougth neighbors */
tmptile2 = TILE_ADD(tmptile, ToTileIndexDiff(_roadblock_tileadd[i]));
tmptile2 = AddDiagDirToTileIndex(tmptile, target_dir);
if (AreNeighborsHouseTiles(tmptile2) && BuildTownHouse(t1, tmptile2)) {
_grow_town_result = -1;
}
case TL_2X2_GRID:
rcmd = GetTownRoadGridElement(t1, tmptile);
rcmd = GetTownRoadGridElement(t1, tmptile, target_dir);
allow_house = (rcmd == ROAD_NONE);
break;
case TL_BETTER_ROADS: /* Use original afterwards! */
/* Fill gap if house has enougth neighbors */
tmptile2 = TILE_ADD(tmptile, ToTileIndexDiff(_roadblock_tileadd[i]));
tmptile2 = AddDiagDirToTileIndex(tmptile, target_dir);
if (AreNeighborsHouseTiles(tmptile2) && BuildTownHouse(t1, tmptile2)) {
_grow_town_result = -1;
}
@ -1023,11 +1024,11 @@ static void GrowTownInTile(TileIndex* tile_ptr, RoadBits mask, int block, Town*
case TL_ORIGINAL:
/* Allow a house at the edge. 60% chance or
* always ok if no road allowed. */
allow_house = (!IsRoadAllowedHere(tmptile, i) || CHANCE16(6, 10));
rcmd = DiagDirToRoadBits(target_dir);
allow_house = (!IsRoadAllowedHere(tmptile, target_dir) || CHANCE16(6, 10));
break;
}
if (allow_house) {
/* Build a house, but not if there already is a house there. */
if (!IsTileType(tmptile, MP_HOUSE)) {
@ -1044,19 +1045,19 @@ static void GrowTownInTile(TileIndex* tile_ptr, RoadBits mask, int block, Town*
}
_grow_town_result = 0;
rcmd = (RoadBits)(ROAD_NW << i);
}
/* Return if a water tile */
if (IsClearWaterTile(tile)) return;
DiagDirection bridge_dir; ///< The direction of a bridge we maybe want to build
/* Determine direction of slope,
* and build a road if not a special slope. */
switch (GetTileSlope(tile, NULL)) {
case SLOPE_SW: i = DIAGDIR_NE; break;
case SLOPE_SE: i = DIAGDIR_NW; break;
case SLOPE_NW: i = DIAGDIR_SE; break;
case SLOPE_NE: i = DIAGDIR_SW; break;
case SLOPE_SW: bridge_dir = DIAGDIR_NE; break;
case SLOPE_SE: bridge_dir = DIAGDIR_NW; break;
case SLOPE_NW: bridge_dir = DIAGDIR_SE; break;
case SLOPE_NE: bridge_dir = DIAGDIR_SW; break;
default:
build_road_and_exit:
@ -1067,38 +1068,33 @@ build_road_and_exit:
}
/* Check if the bridge is in the right direction */
if ((rcmd == ROAD_X && (i == DIAGDIR_NW || i == DIAGDIR_SE)) ||
(rcmd == ROAD_Y && (i == DIAGDIR_NE || i == DIAGDIR_SW))) {
goto build_road_and_exit;
}
if (!(rcmd & DiagDirToRoadBits(bridge_dir))) goto build_road_and_exit;
tmptile = tile;
/* Now it contains the direction of the slope */
j = -11; // max 11 tile long bridges
/* We are in the right direction */
uint32 bridge_length = 0; ///< This value stores the length of the possible bridge
tmptile = tile; ///< Now we use this dummy to store the other waterside
do {
if (++j == 0)
if (bridge_length++ >= 11) {
/* Max 11 tile long bridges */
goto build_road_and_exit;
tmptile = TILE_MASK(tmptile + TileOffsByDiagDir(i));
}
tmptile = TILE_MASK(tmptile + TileOffsByDiagDir(bridge_dir));
} while (IsClearWaterTile(tmptile));
/* no water tiles in between? */
if (j == -10)
goto build_road_and_exit;
if (bridge_length == 1) goto build_road_and_exit;
/* Quit if it selecting an appropiate bridge type fails a large number of times. */
j = 22;
do {
for (uint times = 0; times <= 22; times++) {
byte bridge_type = RandomRange(MAX_BRIDGES - 1);
/* Can we actually build the bridge? */
if (CmdSucceeded(DoCommand(tile, tmptile, bridge_type | ((0x80 | ROADTYPES_ROAD) << 8), DC_AUTO, CMD_BUILD_BRIDGE))) {
DoCommand(tile, tmptile, bridge_type | ((0x80 | ROADTYPES_ROAD) << 8), DC_EXEC | DC_AUTO, CMD_BUILD_BRIDGE);
_grow_town_result = -1;
/* obviously, if building any bridge would fail, there is no need to try other bridge-types */
_grow_town_result = -1;
return;
}
} while (--j != 0);
}
/* Quit if it selecting an appropiate bridge type fails a large number of times. */
}
/** Returns "growth" if a house was built, or no if the build failed.
@ -1108,7 +1104,10 @@ build_road_and_exit:
*/
static int GrowTownAtRoad(Town *t, TileIndex tile)
{
int block = 5; // special case
/* Special case.
* @see GrowTownInTile Check the else if
*/
DiagDirection target_dir = (DiagDirection)5; ///< The direction in which we want to extend the town
TILE_ASSERT(tile);
@ -1131,22 +1130,21 @@ static int GrowTownAtRoad(Town *t, TileIndex tile)
}
do {
/* Get a bitmask of the road blocks on a tile */
RoadBits mask = GetTownRoadMask(tile);
RoadBits cur_rb = GetTownRoadBits(tile); ///< The RoadBits of the current tile
/* Try to grow the town from this point */
GrowTownInTile(&tile, mask, block, t);
GrowTownInTile(&tile, cur_rb, target_dir, t);
/* Exclude the source position from the bitmask
* and return if no more road blocks available */
ClrBitT(mask, (block ^ 2));
if (mask == ROAD_NONE)
cur_rb &= ~DiagDirToRoadBits(ReverseDiagDir(target_dir));
if (cur_rb == ROAD_NONE)
return _grow_town_result;
/* Select a random bit from the blockmask, walk a step
* and continue the search from there. */
do block = Random() & 3; while (!HASBIT(mask, block));
tile += ToTileIndexDiff(_roadblock_tileadd[block]);
do target_dir = RandomDiagDir(); while (!(cur_rb & DiagDirToRoadBits(target_dir)));
tile = AddDiagDirToTileIndex(tile, target_dir);
if (IsTileType(tile, MP_ROAD)) {
/* Don't allow building over roads of other cities */
@ -1166,25 +1164,33 @@ static int GrowTownAtRoad(Town *t, TileIndex tile)
return (_grow_town_result == -2);
}
/** Generate a random road block
/**
* Generate a random road block.
* The probability of a straight road
* is somewhat higher than a curved. */
* is somewhat higher than a curved.
*
* @return A RoadBits value with 2 bits set
*/
static RoadBits GenRandomRoadBits()
{
uint32 r = Random();
uint a = GB(r, 0, 2);
uint b = GB(r, 8, 2);
if (a == b) b ^= 2;
return (RoadBits)((1 << a) + (1 << b));
return (RoadBits)((ROAD_NW << a) + (ROAD_NW << b));
}
/** Grow the town
* @Return true if a house was built, or no if the build failed. */
static bool GrowTown(Town *t)
{
TileIndex tile;
const TileIndexDiffC *ptr;
PlayerID old_player;
/* Let the town be a ghost town
* The player wanted it in such a way. Thus there he has it. ;)
* Never reached in editor mode. */
if (_patches.town_layout == TL_NO_ROADS && _generating_world) {
return false;
}
static const TileIndexDiffC _town_coord_mod[] = {
{-1, 0},
@ -1201,22 +1207,17 @@ static bool GrowTown(Town *t)
{ 2, -2},
{ 0, 0}
};
/* Let the town be a ghost town
* The player wanted it in such a way. Thus there he has it. ;)
* Never reached in editor mode. */
if (_patches.town_layout == TL_NO_ROADS && _generating_world) {
return false;
}
const TileIndexDiffC *ptr;
/* Current player is a town */
old_player = _current_player;
PlayerID old_player = _current_player;
_current_player = OWNER_TOWN;
TileIndex tile = t->xy; ///< The tile we are working with ATM
/* Find a road that we can base the construction on. */
tile = t->xy;
for (ptr = _town_coord_mod; ptr != endof(_town_coord_mod); ++ptr) {
if (GetAnyRoadTrackBits(tile, ROADTYPE_ROAD) != 0) {
if (GetTownRoadBits(tile) != ROAD_NONE) {
int r = GrowTownAtRoad(t, tile);
_current_player = old_player;
return r != 0;