src/town_cmd.cpp
branchgamebalance
changeset 9911 0b8b245a2391
parent 9910 0b2aebc8283e
child 9912 1ac8aac92385
--- a/src/town_cmd.cpp	Wed Jun 13 11:17:30 2007 +0000
+++ b/src/town_cmd.cpp	Wed Jun 13 11:45:14 2007 +0000
@@ -39,6 +39,7 @@
 #include "newgrf.h"
 #include "newgrf_callbacks.h"
 #include "newgrf_house.h"
+#include "newgrf_commons.h"
 
 /**
  * Called if a new block is added to the town-pool
@@ -55,6 +56,11 @@
 /* Initialize the town-pool */
 DEFINE_OLD_POOL(Town, Town, TownPoolNewBlock, NULL)
 
+/**
+ * Removes a specific town as well as all industries
+ * under its "juridiction"
+ * @param t Town to remove
+ */
 void DestroyTown(Town *t)
 {
 	Industry *i;
@@ -121,6 +127,11 @@
 	return variant;
 }
 
+/**
+ * House Tile drawing handler.
+ * Part of the tile loop process
+ * @param ti TileInfo of the tile to draw
+ */
 static void DrawTile_Town(TileInfo *ti)
 {
 	const DrawBuildingsTileStruct *dcts;
@@ -188,6 +199,12 @@
 	return SLOPE_FLAT;
 }
 
+/**
+ * Animate a tile for a town
+ * Only certain houses can be animated
+ * The newhouses animation superseeds regular ones
+ * @param tile TileIndex of the house to animate
+ */
 static void AnimateTile_Town(TileIndex tile)
 {
 	int pos, dest;
@@ -234,6 +251,12 @@
 
 static void UpdateTownRadius(Town *t);
 
+/**
+ * Determines if a town is close to a tile
+ * @param tile TileIndex of the tile to query
+ * @param dist maximum distance to be accepted
+ * @returns true if the tile correspond to the distance criteria
+ */
 static bool IsCloseToTown(TileIndex tile, uint dist)
 {
 	const Town* t;
@@ -244,6 +267,10 @@
 	return false;
 }
 
+/**
+ * Marks the town sign as needing a repaint
+ * @param t Town requesting repaint
+ */
 static void MarkTownSignDirty(Town *t)
 {
 	MarkAllViewportsDirty(
@@ -254,6 +281,11 @@
 	);
 }
 
+/**
+ * Resize the sign(label) of the town after changes in
+ * population (creation or growth or else)
+ * @param t Town to update
+ */
 void UpdateTownVirtCoord(Town *t)
 {
 	Point pt;
@@ -267,6 +299,11 @@
 	MarkTownSignDirty(t);
 }
 
+/**
+ * Change the towns population
+ * @param t Town which polulation has changed
+ * @param mod polulation change (can be positive or negative)
+ */
 static void ChangePopulation(Town *t, int mod)
 {
 	t->population += mod;
@@ -276,6 +313,11 @@
 	if (_town_sort_order & 2) _town_sort_dirty = true;
 }
 
+/**
+ * Determines the world population
+ * Basically, count population of all towns, one by one
+ * @return uint32 the calculated population of the world
+ */
 uint32 GetWorldPopulation()
 {
 	uint32 pop;
@@ -286,17 +328,24 @@
 	return pop;
 }
 
+/**
+ * Helper function for house completion stages progression
+ * @param tile TileIndex of the house (or parts of it) to "grow"
+ */
 static void MakeSingleHouseBigger(TileIndex tile)
 {
 	assert(IsTileType(tile, MP_HOUSE));
 
+	/* means it is completed, get out. */
 	if (LiftHasDestination(tile)) return;
 
+	/* progress in construction stages */
 	IncHouseConstructionTick(tile);
 	if (GetHouseConstructionTick(tile) != 0) return;
 
+	/* Check and/or  */
 	if (HASBIT(GetHouseSpecs(GetHouseType(tile))->callback_mask, CBM_CONSTRUCTION_STATE_CHANGE)) {
-		uint16 callback_res = GetHouseCallback(CBID_CONSTRUCTION_STATE_CHANGE, 0, GetHouseType(tile), GetTownByTile(tile), tile);
+		uint16 callback_res = GetHouseCallback(CBID_CONSTRUCTION_STATE_CHANGE, 0, 0, GetHouseType(tile), GetTownByTile(tile), tile);
 		if (callback_res != CALLBACK_FAILED) ChangeHouseAnimationFrame(tile, callback_res);
 	}
 
@@ -308,6 +357,9 @@
 	MarkTileDirtyByTile(tile);
 }
 
+/** Make the house advances in its construction stages until completion
+ * @param tile TileIndex of house
+ */
 static void MakeTownHouseBigger(TileIndex tile)
 {
 	uint flags = GetHouseSpecs(GetHouseType(tile))->building_flags;
@@ -317,6 +369,10 @@
 	if (flags & BUILDING_HAS_4_TILES) MakeSingleHouseBigger(TILE_ADDXY(tile, 1, 1));
 }
 
+/**
+ * Periodic tic handler for houses and town
+ * @param tile been asked to do its stuff
+ */
 static void TileLoop_Town(TileIndex tile)
 {
 	Town *t;
@@ -335,29 +391,69 @@
 	}
 
 	/* If the lift has a destination, it is already an animated tile. */
-	if ((hs->building_flags & BUILDING_IS_ANIMATED) && house_id < NEW_HOUSE_OFFSET && !LiftHasDestination(tile) && CHANCE16(1, 2)) AddAnimatedTile(tile);
+	if ((hs->building_flags & BUILDING_IS_ANIMATED) &&
+			house_id < NEW_HOUSE_OFFSET &&
+			!LiftHasDestination(tile) &&
+			CHANCE16(1, 2))
+		AddAnimatedTile(tile);
 
 	t = GetTownByTile(tile);
 
 	r = Random();
 
-	if (GB(r, 0, 8) < (t->GetActivity() * _eco->GetActivity() * 8)) {
-		int amt = hs->population / 8 + 1;
-		t->new_max_pass += amt;
-		int moved = MoveGoodsToStation(tile, 1, 1, CT_PASSENGERS, amt);
-		t->new_act_pass += moved;
-	}
-
-	if (GB(r, 8, 8) < (t->GetActivity() * _eco->GetActivity() * 8)) {
-		int amt = hs->mail_generation / 8 + 1;
-		t->new_max_pass += amt;
-		int moved = MoveGoodsToStation(tile, 1, 1, CT_PASSENGERS, amt);
-		t->new_act_pass += moved;
+	if (HASBIT(hs->callback_mask, CBM_HOUSE_PRODUCE_CARGO)) {
+		/** @todo Implement economic activity here as well */
+		for (uint i = 0; i < 256; i++) {
+			uint16 callback = GetHouseCallback(CBID_HOUSE_PRODUCE_CARGO, i, r, house_id, t, tile);
+
+			if (callback == CALLBACK_FAILED) break;
+			if (callback == 0x20FF) break;
+
+			CargoID cargo = GetCargoTranslation(GB(callback, 8, 7), hs->grffile);
+			if (cargo == CT_INVALID) continue;
+
+			uint amt = GB(callback, 0, 8);
+			uint moved = MoveGoodsToStation(tile, 1, 1, cargo, amt);
+
+			const CargoSpec *cs = GetCargo(cargo);
+			switch (cs->town_effect) {
+				case TE_PASSENGERS:
+					t->new_max_pass += amt;
+					t->new_act_pass += moved;
+					break;
+
+				case TE_MAIL:
+					t->new_max_mail += amt;
+					t->new_act_mail += moved;
+					break;
+
+				default:
+					break;
+			}
+		}
+	} else {
+		if (GB(r, 0, 8) < (t->GetActivity() * _eco->GetActivity() * 8)) {
+			int amt = hs->population / 8 + 1;
+			t->new_max_pass += amt;
+			int moved = MoveGoodsToStation(tile, 1, 1, CT_PASSENGERS, amt);
+			t->new_act_pass += moved;
+		}
+
+		if (GB(r, 8, 8) < (t->GetActivity() * _eco->GetActivity() * 8)) {
+			int amt = hs->mail_generation / 8 + 1;
+			t->new_max_pass += amt;
+			int moved = MoveGoodsToStation(tile, 1, 1, CT_PASSENGERS, amt);
+			t->new_act_pass += moved;
+		}
 	}
 
 	_current_player = OWNER_TOWN;
 
-	if (hs->building_flags & BUILDING_HAS_1_TILE && HASBIT(t->flags12, TOWN_IS_FUNDED) && CanDeleteHouse(tile) && --t->time_until_rebuild == 0) {
+	if (hs->building_flags & BUILDING_HAS_1_TILE &&
+			HASBIT(t->flags12, TOWN_IS_FUNDED) &&
+			CanDeleteHouse(tile) &&
+			max(_cur_year - GetHouseConstructionYear(tile), 0) >= hs->minimum_life &&
+			--t->time_until_rebuild == 0) {
 		t->time_until_rebuild = GB(r, 16, 8) + 192;
 
 		ClearTownHouse(t, tile);
@@ -369,6 +465,10 @@
 	_current_player = OWNER_NONE;
 }
 
+/**
+ * Unused handler
+ * @param tile unused
+ */
 static void ClickTile_Town(TileIndex tile)
 {
 	/* not used */
@@ -408,8 +508,44 @@
 static void GetAcceptedCargo_Town(TileIndex tile, AcceptedCargo ac)
 {
 	HouseSpec *hs = GetHouseSpecs(GetHouseType(tile));
-
-	for (uint8 i = 0; i < 3; i++) ac[hs->accepts_cargo[i]] = hs->cargo_acceptance[i];
+	CargoID accepts[3];
+
+	/* Set the initial accepted cargo types */
+	for (uint8 i = 0; i < lengthof(accepts); i++) {
+		accepts[i] = hs->accepts_cargo[i];
+	}
+
+	/* Check for custom accepted cargo types */
+	if (HASBIT(hs->callback_mask, CBM_HOUSE_ACCEPT_CARGO)) {
+		uint16 callback = GetHouseCallback(CBID_HOUSE_ACCEPT_CARGO, 0, 0, GetHouseType(tile), GetTownByTile(tile), tile);
+		if (callback != CALLBACK_FAILED) {
+			/* Replace accepted cargo types with translated values from callback */
+			accepts[0] = GetCargoTranslation(GB(callback,  0, 5), hs->grffile);
+			accepts[1] = GetCargoTranslation(GB(callback,  5, 5), hs->grffile);
+			accepts[2] = GetCargoTranslation(GB(callback, 10, 5), hs->grffile);
+		}
+	}
+
+	/* Check for custom cargo acceptance */
+	if (HASBIT(hs->callback_mask, CBM_CARGO_ACCEPTANCE)) {
+		uint16 callback = GetHouseCallback(CBID_HOUSE_CARGO_ACCEPTANCE, 0, 0, GetHouseType(tile), GetTownByTile(tile), tile);
+		if (callback != CALLBACK_FAILED) {
+			if (accepts[0] != CT_INVALID) ac[accepts[0]] = GB(callback, 0, 4);
+			if (accepts[1] != CT_INVALID) ac[accepts[1]] = GB(callback, 4, 4);
+			if (_opt.landscape != LT_TEMPERATE && HASBIT(callback, 12)) {
+				/* The 'S' bit indicates food instead of goods */
+				ac[CT_FOOD] = GB(callback, 8, 4);
+			} else {
+				if (accepts[2] != CT_INVALID) ac[accepts[2]] = GB(callback, 8, 4);
+			}
+			return;
+		}
+	}
+
+	/* No custom acceptance, so fill in with the default values */
+	for (uint8 i = 0; i < lengthof(accepts); i++) {
+		if (accepts[i] != CT_INVALID) ac[accepts[i]] = hs->cargo_acceptance[i];
+	}
 }
 
 static void GetTileDesc_Town(TileIndex tile, TileDesc *td)
@@ -448,6 +584,14 @@
 	{ 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);
 
@@ -488,7 +632,7 @@
 
 static RoadBits GetTownRoadMask(TileIndex tile)
 {
-	TrackBits b = GetAnyRoadTrackBits(tile);
+	TrackBits b = GetAnyRoadTrackBits(tile, ROADTYPE_ROAD);
 	RoadBits r = ROAD_NONE;
 
 	if (b & TRACK_BIT_X)     r |= ROAD_X;
@@ -500,6 +644,23 @@
 	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;
@@ -511,7 +672,7 @@
 
 	for (;;) {
 		/* Check if there already is a road at this point? */
-		if (GetAnyRoadTrackBits(tile) == 0) {
+		if (GetAnyRoadTrackBits(tile, ROADTYPE_ROAD) == 0) {
 			/* 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. */
@@ -523,16 +684,17 @@
 		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;
-
-			/* Otherwise allow */
-			return true;
+			/* 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 !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
@@ -591,6 +753,127 @@
 	}
 }
 
+/**
+ * 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;
@@ -613,39 +896,81 @@
 		LevelTownLand(tile);
 
 		/* Is a road allowed here? */
-		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);
+		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);
+				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;
 		}
 
-		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));
-
 	} 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)) {
@@ -668,17 +993,51 @@
 		/* 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;
 		}
@@ -706,6 +1065,12 @@
 			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 */
@@ -748,8 +1113,23 @@
 
 	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 */
@@ -823,6 +1203,13 @@
 		{ 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;
+	}
+
 	/* Current player is a town */
 	old_player = _current_player;
 	_current_player = OWNER_TOWN;
@@ -830,7 +1217,7 @@
 	/* 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) != 0) {
+		if (GetAnyRoadTrackBits(tile, ROADTYPE_ROAD) != 0) {
 			int r = GrowTownAtRoad(t, tile);
 			_current_player = old_player;
 			return r != 0;
@@ -844,7 +1231,7 @@
 	for (ptr = _town_coord_mod; ptr != endof(_town_coord_mod); ++ptr) {
 		/* Only work with plain land that not already has a house */
 		if (!IsTileType(tile, MP_HOUSE) && GetTileSlope(tile, NULL) == SLOPE_FLAT) {
-			if (!CmdFailed(DoCommand(tile, 0, 0, DC_AUTO, CMD_LANDSCAPE_CLEAR))) {
+			if (!CmdFailed(DoCommand(tile, 0, 0, DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR))) {
 				DoCommand(tile, GenRandomRoadBits(), t->index, DC_EXEC | DC_AUTO, CMD_BUILD_ROAD);
 				_current_player = old_player;
 				return true;
@@ -1160,7 +1547,7 @@
 	return NULL;
 }
 
-static const byte _num_initial_towns[3] = {11, 23, 46};
+static const byte _num_initial_towns[4] = {5, 11, 23, 46};
 
 bool GenerateTowns()
 {
@@ -1304,7 +1691,7 @@
 				if ((hs->extra_flags & BUILDING_IS_HISTORICAL) && !_generating_world) continue;
 
 				if (HASBIT(hs->callback_mask, CBM_HOUSE_ALLOW_CONSTRUCTION)) {
-					uint16 callback_res = GetHouseCallback(CBID_HOUSE_ALLOW_CONSTRUCTION, 0, house, t, tile);
+					uint16 callback_res = GetHouseCallback(CBID_HOUSE_ALLOW_CONSTRUCTION, 0, 0, house, t, tile);
 					if (callback_res != CALLBACK_FAILED && callback_res == 0) continue;
 				}
 			}
@@ -1818,7 +2205,7 @@
 {
 	if (IsTileType(tile, MP_HOUSE) || (
 				IsTileType(tile, MP_STREET) &&
-				(IsLevelCrossing(tile) ? GetCrossingRoadOwner(tile) : GetTileOwner(tile)) == OWNER_TOWN
+				GetRoadOwner(tile, ROADTYPE_ROAD) == OWNER_TOWN
 			)) {
 		return GetTownByTile(tile);
 	} else {
@@ -2014,19 +2401,19 @@
 /* Save and load the mapping between the house id on the map, and the grf file
  * it came from. */
 static const SaveLoad _house_id_mapping_desc[] = {
-	SLE_VAR(HouseIDMapping, grfid,         SLE_UINT32),
-	SLE_VAR(HouseIDMapping, house_id,      SLE_UINT8),
-	SLE_VAR(HouseIDMapping, substitute_id, SLE_UINT8),
+	SLE_VAR(EntityIDMapping, grfid,         SLE_UINT32),
+	SLE_VAR(EntityIDMapping, entity_id,     SLE_UINT8),
+	SLE_VAR(EntityIDMapping, substitute_id, SLE_UINT8),
 	SLE_END()
 };
 
 static void Save_HOUSEIDS()
 {
-	uint i;
-
-	for (i = 0; i != lengthof(_house_id_mapping); i++) {
+	uint j = _house_mngr.GetMaxMapping();
+
+	for (uint i = 0; i < j; i++) {
 		SlSetArrayIndex(i);
-		SlObject(&_house_id_mapping[i], _house_id_mapping_desc);
+		SlObject(&_house_mngr.mapping_ID[i], _house_id_mapping_desc);
 	}
 }
 
@@ -2034,11 +2421,12 @@
 {
 	int index;
 
-	ResetHouseIDMapping();
+	_house_mngr.ResetMapping();
+	uint max_id = _house_mngr.GetMaxMapping();
 
 	while ((index = SlIterateArray()) != -1) {
-		if ((uint)index >= lengthof(_house_id_mapping)) break;
-		SlObject(&_house_id_mapping[index], _house_id_mapping_desc);
+		if ((uint)index >= max_id) break;
+		SlObject(&_house_mngr.mapping_ID[index], _house_id_mapping_desc);
 	}
 }