1
0
Fork 0

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

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