(svn r9779) -Feature: Add the possiblity to choose different road patterns for towns to use.

Possible patterns are : 
No Road (not available in scenario editor)
Original (for the nostalgics)
Better Roads (same as original, but based on distance of 2 tiles instead of one)
2x2 grids
3x3 grids
Patch by skiddl13
This commit is contained in:
belugas
2007-05-04 16:27:13 +00:00
parent 449e76c05a
commit aff49954bf
9 changed files with 374 additions and 44 deletions

View File

@@ -555,6 +555,14 @@ static const TileIndexDiffC _roadblock_tileadd[] = {
{ 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);
@@ -607,6 +615,23 @@ static RoadBits GetTownRoadMask(TileIndex tile)
return r;
}
/**
* Check if a neighboring tile has a road
*
* @param tile curent 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
*/
static bool NeighborIsRoadTile(TileIndex tile, int dir, RoadBlockTitleDistance 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 bool IsRoadAllowedHere(TileIndex tile, int dir)
{
Slope k;
@@ -630,16 +655,17 @@ static bool IsRoadAllowedHere(TileIndex tile, int dir)
slope = GetTileSlope(tile, NULL);
if (slope == SLOPE_FLAT) {
no_slope:
/* Tile has no slope
* Disallow the road if any neighboring tile has a road. */
if (HASBIT(GetTownRoadMask(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[dir + 1]))), dir ^ 2) ||
HASBIT(GetTownRoadMask(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[dir + 3]))), dir ^ 2) ||
HASBIT(GetTownRoadMask(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[dir + 1]) + ToTileIndexDiff(_roadblock_tileadd[dir + 2]))), dir) ||
HASBIT(GetTownRoadMask(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[dir + 3]) + ToTileIndexDiff(_roadblock_tileadd[dir + 2]))), dir))
return false;
/* Tile has no slope */
switch (_patches.town_layout) {
default: NOT_REACHED();
/* Otherwise allow */
return true;
case TL_ORIGINAL: /* Disallow the road if any neighboring tile has a road (distance: 1) */
return !NeighborIsRoadTile(tile, dir, RB_TILE_DIST1);
case TL_BETTER_ROADS: /* Disallow the road if any neighboring tile has a road (distance: 1 and 2). */
return !(NeighborIsRoadTile(tile, dir, RB_TILE_DIST1) ||
NeighborIsRoadTile(tile, dir, RB_TILE_DIST2));
}
}
/* If the tile is not a slope in the right direction, then
@@ -698,6 +724,127 @@ static void LevelTownLand(TileIndex tile)
}
}
/**
* Generate the RoadBits of a grid tile
*
* @param t current town
* @param tile tile in reference to the town
* @return the RoadBit of the current tile regarding
* the selected town layout
*/
static RoadBits GetTownRoadGridElement(Town* t, TileIndex tile)
{
/* 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;
switch (_patches.town_layout) {
default: NOT_REACHED();
case TL_2X2_GRID:
lx = ((grid_pos.x % 3) == 0);
ly = ((grid_pos.y % 3) == 0);
break;
case TL_3X3_GRID:
lx = ((grid_pos.x % 4) == 0);
ly = ((grid_pos.y % 4) == 0);
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;
}
}
}
/**
* Check there are enougth neighbor house tiles next to the current tile
*
* @param tile current tile
* @return true if there are more than 2 house tiles next
* to the current one
*/
static bool NeighborsAreHouseTiles(TileIndex tile)
{
uint counter = 0; ///< counts the house neighbor tiles
/* We can't look further than that. */
if (TileX(tile) < 1 || TileY(tile) < 1) {
return false;
}
/* 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)) {
counter++;
}
/* If there are enougth neighbor's stop it here */
if (counter >= 3) {
return true;
}
}
return false;
}
/**
* Grows the given town.
* There are at the moment 3 possible way's for
* the town expansion:
* @li Generate a random tile and check if there is a road allowed
* @li TL_ORIGINAL
* @li TL_BETTER_ROADS
* @li Check if the town geometry allows a road and which one
* @li TL_2X2_GRID
* @li TL_3X3_GRID
* @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
*/
static void GrowTownInTile(TileIndex* tile_ptr, RoadBits mask, int block, Town* t1)
{
RoadBits rcmd;
@@ -720,39 +867,81 @@ static void GrowTownInTile(TileIndex* tile_ptr, RoadBits mask, int block, Town*
LevelTownLand(tile);
/* Is a road allowed here? */
if (!IsRoadAllowedHere(tile, block)) return;
switch (_patches.town_layout) {
default: NOT_REACHED();
/* Randomize new road block numbers */
a = block;
b = block ^ 2;
if (CHANCE16(1, 4)) {
do {
a = GB(Random(), 0, 2);
} while (a == b);
}
if (!IsRoadAllowedHere(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[a])), a)) {
/* 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 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))
case TL_NO_ROADS: /* Disallow Roads */
return;
/* That means that the road is only allowed if there is a house
* at any side of the new road. */
case TL_3X3_GRID:
case TL_2X2_GRID:
rcmd = GetTownRoadGridElement(t1, tile);
if (rcmd == ROAD_NONE) {
return;
}
break;
case TL_BETTER_ROADS:
case TL_ORIGINAL:
if (!IsRoadAllowedHere(tile, block)) {
return;
}
/* Randomize new road block numbers */
a = block;
b = block ^ 2;
if (CHANCE16(1, 4)) {
do {
a = GB(Random(), 0, 2);
} while (a == b);
}
if (!IsRoadAllowedHere(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[a])), a)) {
/* 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 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)) {
return;
}
/* That means that the road is only allowed if there is a house
* at any side of the new road. */
}
rcmd = (RoadBits)((1 << a) + (1 << b));
break;
}
rcmd = (RoadBits)((1 << a) + (1 << b));
} else if (block < 5 && !HASBIT(mask, block ^ 2)) {
/* Continue building on a partial road.
* Always OK. */
_grow_town_result = 0;
rcmd = (RoadBits)(1 << (block ^ 2));
switch (_patches.town_layout) {
default: NOT_REACHED();
case TL_NO_ROADS: /* Disallow Roads */
return;
case TL_3X3_GRID:
case TL_2X2_GRID:
rcmd = GetTownRoadGridElement(t1, tile);
break;
case TL_BETTER_ROADS:
case TL_ORIGINAL:
rcmd = (RoadBits)(1 << (block ^ 2));
break;
}
} else {
int i;
bool allow_house = false;
TileIndex tmptile2;
/* Reached a tunnel/bridge? Then continue at the other side of it. */
if (IsTileType(tile, MP_TUNNELBRIDGE)) {
@@ -775,17 +964,51 @@ static void GrowTownInTile(TileIndex* tile_ptr, RoadBits mask, int block, Town*
/* Don't do it if it reaches to water. */
if (IsClearWaterTile(tmptile)) return;
/* Build a house at the edge. 60% chance or
* always ok if no road allowed. */
if (!IsRoadAllowedHere(tmptile, i) || CHANCE16(6, 10)) {
/* But not if there already is a house there. */
switch (_patches.town_layout) {
default: NOT_REACHED();
case TL_NO_ROADS:
allow_house = true;
break;
case TL_3X3_GRID: /* Use 2x2 grid afterwards! */
/* Fill gap if house has enougth neighbors */
tmptile2 = TILE_ADD(tmptile, ToTileIndexDiff(_roadblock_tileadd[i]));
if (NeighborsAreHouseTiles(tmptile2) && BuildTownHouse(t1, tmptile2)) {
_grow_town_result = -1;
}
case TL_2X2_GRID:
rcmd = GetTownRoadGridElement(t1, tmptile);
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]));
if (NeighborsAreHouseTiles(tmptile2) && BuildTownHouse(t1, tmptile2)) {
_grow_town_result = -1;
}
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));
break;
}
if (allow_house) {
/* Build a house, but not if there already is a house there. */
if (!IsTileType(tmptile, MP_HOUSE)) {
/* Level the land if possible */
LevelTownLand(tmptile);
/* And build a house.
* Set result to -1 if we managed to build it. */
if (BuildTownHouse(t1, tmptile)) _grow_town_result = -1;
if (BuildTownHouse(t1, tmptile)) {
_grow_town_result = -1;
}
}
return;
}
@@ -813,6 +1036,12 @@ build_road_and_exit:
return;
}
/* 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;
}
tmptile = tile;
/* Now it contains the direction of the slope */
@@ -855,8 +1084,23 @@ static int GrowTownAtRoad(Town *t, TileIndex tile)
TILE_ASSERT(tile);
/* Number of times to search. */
_grow_town_result = 10 + t->num_houses * 4 / 9;
/* Number of times to search.
* Better roads, 2X2 and 3X3 grid grow quite fast so we give
* them a little handicap. */
switch (_patches.town_layout) {
case TL_BETTER_ROADS:
_grow_town_result = 10 + t->num_houses * 2 / 9;
break;
case TL_3X3_GRID:
case TL_2X2_GRID:
_grow_town_result = 10 + t->num_houses * 1 / 9;
break;
default:
_grow_town_result = 10 + t->num_houses * 4 / 9;
break;
}
do {
/* Get a bitmask of the road blocks on a tile */
@@ -930,6 +1174,13 @@ static bool GrowTown(Town *t)
{ 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) {
return false;
}
/* Current player is a town */
old_player = _current_player;
_current_player = OWNER_TOWN;