src/town_cmd.cpp
changeset 8485 00c2183c2a7f
parent 8461 126aeb3ebd1d
child 8487 9d7e14b019fa
equal deleted inserted replaced
8484:bc879e91d26a 8485:00c2183c2a7f
   115 	GROWTH_SEARCH_STOPPED  =  0
   115 	GROWTH_SEARCH_STOPPED  =  0
   116 //	GROWTH_SEARCH_RUNNING >=  1
   116 //	GROWTH_SEARCH_RUNNING >=  1
   117 };
   117 };
   118 
   118 
   119 static bool BuildTownHouse(Town *t, TileIndex tile);
   119 static bool BuildTownHouse(Town *t, TileIndex tile);
   120 static void DoBuildTownHouse(Town *t, TileIndex tile);
       
   121 
   120 
   122 static void TownDrawHouseLift(const TileInfo *ti)
   121 static void TownDrawHouseLift(const TileInfo *ti)
   123 {
   122 {
   124 	AddChildSpriteScreen(SPR_LIFT, PAL_NONE, 14, 60 - GetLiftPosition(ti->tile));
   123 	AddChildSpriteScreen(SPR_LIFT, PAL_NONE, 14, 60 - GetLiftPosition(ti->tile));
   125 }
   124 }
   491 		t->time_until_rebuild = GB(r, 16, 8) + 192;
   490 		t->time_until_rebuild = GB(r, 16, 8) + 192;
   492 
   491 
   493 		ClearTownHouse(t, tile);
   492 		ClearTownHouse(t, tile);
   494 
   493 
   495 		/* Rebuild with another house? */
   494 		/* Rebuild with another house? */
   496 		if (GB(r, 24, 8) >= 12) DoBuildTownHouse(t, tile);
   495 		if (GB(r, 24, 8) >= 12) BuildTownHouse(t, tile);
   497 	}
   496 	}
   498 
   497 
   499 	_current_player = OWNER_NONE;
   498 	_current_player = OWNER_NONE;
   500 }
   499 }
   501 
   500 
  1584 	}
  1583 	}
  1585 
  1584 
  1586 	return true;
  1585 	return true;
  1587 }
  1586 }
  1588 
  1587 
  1589 static bool CheckBuildHouseMode(TileIndex tile, Slope tileh, int mode)
       
  1590 {
       
  1591 	int b;
       
  1592 	Slope slope;
       
  1593 
       
  1594 	static const Slope _masks[8] = {
       
  1595 		SLOPE_NE,  SLOPE_SW,  SLOPE_NW,  SLOPE_SE,
       
  1596 		SLOPE_SW,  SLOPE_NE,  SLOPE_SE,  SLOPE_NW,
       
  1597 	};
       
  1598 
       
  1599 	slope = GetTileSlope(tile, NULL);
       
  1600 	if (IsSteepSlope(slope)) return false;
       
  1601 
       
  1602 	if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return false;
       
  1603 
       
  1604 	b = 0;
       
  1605 	if ((slope != SLOPE_FLAT && ~slope & _masks[mode])) b = ~b;
       
  1606 	if ((tileh != SLOPE_FLAT && ~tileh & _masks[mode + 4])) b = ~b;
       
  1607 	if (b)
       
  1608 		return false;
       
  1609 
       
  1610 	return CmdSucceeded(DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR));
       
  1611 }
       
  1612 
  1588 
  1613 /** Returns the bit corresponding to the town zone of the specified tile
  1589 /** Returns the bit corresponding to the town zone of the specified tile
  1614  * @param t Town on which radius is to be found
  1590  * @param t Town on which radius is to be found
  1615  * @param tile TileIndex where radius needs to be found
  1591  * @param tile TileIndex where radius needs to be found
  1616  * @return the bit position of the given zone, as defined in HouseZones
  1592  * @return the bit position of the given zone, as defined in HouseZones
  1629 	}
  1605 	}
  1630 
  1606 
  1631 	return smallest;
  1607 	return smallest;
  1632 }
  1608 }
  1633 
  1609 
  1634 static bool CheckFree2x2Area(TileIndex tile)
  1610 /**
  1635 {
  1611  * Clears tile and builds a house or house part.
  1636 	int i;
  1612  * @param t tile index
  1637 
  1613  * @param tid Town index
  1638 	static const TileIndexDiffC _tile_add[] = {
  1614  * @param counter of construction step
  1639 		{0    , 0    },
  1615  * @param stage of construction (used for drawing)
  1640 		{0 - 0, 1 - 0},
  1616  * @param type of house. Index into house specs array
  1641 		{1 - 0, 0 - 1},
  1617  * @param random_bits required for newgrf houses
  1642 		{1 - 1, 1 - 0}
  1618  * @pre house can be built here
  1643 	};
  1619  */
  1644 
  1620 
  1645 	for (i = 0; i != 4; i++) {
  1621 static inline void ClearMakeHouseTile(TileIndex tile, TownID tid, byte counter, byte stage, HouseID type, byte random_bits)
  1646 		tile += ToTileIndexDiff(_tile_add[i]);
  1622 {
  1647 
  1623 	CommandCost cc = DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR);
  1648 		if (GetTileSlope(tile, NULL) != SLOPE_FLAT) return false;
  1624 	assert(CmdSucceeded(cc));
  1649 
  1625 
  1650 		if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return false;
  1626 	MakeHouseTile(tile, tid, counter, stage, type, random_bits);
  1651 
  1627 }
  1652 		if (CmdFailed(DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER | DC_FORCETEST, CMD_LANDSCAPE_CLEAR)))
  1628 
  1653 			return false;
  1629 /**
  1654 	}
  1630  * Write house information into the map. For houses > 1 tile, all tiles are marked.
       
  1631  * @param t tile index
       
  1632  * @param tid Town index
       
  1633  * @param counter of construction step
       
  1634  * @param stage of construction (used for drawing)
       
  1635  * @param type of house. Index into house specs array
       
  1636  * @param random_bits required for newgrf houses
       
  1637  * @pre house can be built here
       
  1638  */
       
  1639 static void MakeTownHouse(TileIndex t, TownID tid, byte counter, byte stage, HouseID type, byte random_bits)
       
  1640 {
       
  1641 	BuildingFlags size = GetHouseSpecs(type)->building_flags;
       
  1642 
       
  1643 	ClearMakeHouseTile(t, tid, counter, stage, type, random_bits);
       
  1644 	if (size & BUILDING_2_TILES_Y)   ClearMakeHouseTile(t + TileDiffXY(0, 1), tid, counter, stage, ++type, random_bits);
       
  1645 	if (size & BUILDING_2_TILES_X)   ClearMakeHouseTile(t + TileDiffXY(1, 0), tid, counter, stage, ++type, random_bits);
       
  1646 	if (size & BUILDING_HAS_4_TILES) ClearMakeHouseTile(t + TileDiffXY(1, 1), tid, counter, stage, ++type, random_bits);
       
  1647 }
       
  1648 
       
  1649 
       
  1650 /**
       
  1651  * Checks if a house can be built here. Important is slope, bridge above
       
  1652  * and ability to clear the land.
       
  1653  * @param tile tile to check
       
  1654  * @param noslope are slopes (foundations) allowed?
       
  1655  * @return true iff house can be built here
       
  1656  */
       
  1657 static inline bool CanBuildHouseHere(TileIndex tile, bool noslope)
       
  1658 {
       
  1659 	/* cannot build on these slopes... */
       
  1660 	Slope slope = GetTileSlope(tile, NULL);
       
  1661 	if ((noslope && slope != SLOPE_FLAT) || IsSteepSlope(slope)) return false;
       
  1662 
       
  1663 	/* building under a bridge? */
       
  1664 	if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return false;
       
  1665 
       
  1666 	/* can we clear the land? */
       
  1667 	return CmdSucceeded(DoCommand(tile, 0, 0, DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR));
       
  1668 }
       
  1669 
       
  1670 
       
  1671 /**
       
  1672  * Checks if a house can be built at this tile, must have the same max z as parameter.
       
  1673  * @param tile tile to check
       
  1674  * @param z max z of this tile so more parts of a house are at the same height (with foundation)
       
  1675  * @param noslope are slopes (foundations) allowed?
       
  1676  * @return true iff house can be built here
       
  1677  * @see CanBuildHouseHere()
       
  1678  */
       
  1679 static inline bool CheckBuildHouseSameZ(TileIndex tile, uint z, bool noslope)
       
  1680 {
       
  1681 	if (!CanBuildHouseHere(tile, noslope)) return false;
       
  1682 
       
  1683 	/* if building on slopes is allowed, there will be flattening foundation (to tile max z) */
       
  1684 	if (GetTileMaxZ(tile) != z) return false;
  1655 
  1685 
  1656 	return true;
  1686 	return true;
  1657 }
  1687 }
  1658 
  1688 
  1659 static void DoBuildTownHouse(Town *t, TileIndex tile)
  1689 
       
  1690 /**
       
  1691  * Checks if a house of size 2x2 can be built at this tile
       
  1692  * @param tile tile, N corner
       
  1693  * @param z maximum tile z so all tile have the same max z
       
  1694  * @param noslope are slopes (foundations) allowed?
       
  1695  * @return true iff house can be built
       
  1696  * @see CheckBuildHouseSameZ()
       
  1697  */
       
  1698 static bool CheckFree2x2Area(TileIndex tile, uint z, bool noslope)
       
  1699 {
       
  1700 	/* we need to check this tile too because we can be at different tile now */
       
  1701 	if (!CheckBuildHouseSameZ(tile, z, noslope)) return false;
       
  1702 
       
  1703 	for (DiagDirection d = DIAGDIR_SE; d < DIAGDIR_END; d++) {
       
  1704 		tile += TileOffsByDiagDir(d);
       
  1705 		if (!CheckBuildHouseSameZ(tile, z, noslope)) return false;
       
  1706 	}
       
  1707 
       
  1708 	return true;
       
  1709 }
       
  1710 
       
  1711 
       
  1712 /**
       
  1713  * Tries to build a house at this tile
       
  1714  * @param t town the house will belong to
       
  1715  * @param tile where the house will be built
       
  1716  * @return false iff no house can be built at this tile
       
  1717  */
       
  1718 static bool BuildTownHouse(Town *t, TileIndex tile)
  1660 {
  1719 {
  1661 	int i;
  1720 	int i;
  1662 	uint bitmask;
  1721 	uint bitmask;
  1663 	HouseID house;
  1722 	HouseID house;
  1664 	Slope slope;
  1723 	Slope slope;
  1665 	uint z;
  1724 	uint z;
  1666 	uint oneof = 0;
  1725 	uint oneof = 0;
  1667 	HouseSpec *hs;
  1726 	HouseSpec *hs;
       
  1727 
       
  1728 	/* no house allowed at all, bail out */
       
  1729 	if (!CanBuildHouseHere(tile, false)) return false;
  1668 
  1730 
  1669 	/* Above snow? */
  1731 	/* Above snow? */
  1670 	slope = GetTileSlope(tile, &z);
  1732 	slope = GetTileSlope(tile, &z);
  1671 
  1733 
  1672 	/* Get the town zone type of the current tile, as well as the climate.
  1734 	/* Get the town zone type of the current tile, as well as the climate.
  1700 				}
  1762 				}
  1701 				houses[num++] = (HouseID)i;
  1763 				houses[num++] = (HouseID)i;
  1702 			}
  1764 			}
  1703 		}
  1765 		}
  1704 
  1766 
       
  1767 		uint maxz = GetTileMaxZ(tile);
       
  1768 
  1705 		for (;;) {
  1769 		for (;;) {
  1706 			if (_loaded_newgrf_features.has_newhouses) {
  1770 			if (_loaded_newgrf_features.has_newhouses) {
  1707 				uint r = RandomRange(probability_max);
  1771 				uint r = RandomRange(probability_max);
  1708 				for (i = 0; i < num; i++) if (cumulative_probs[i] >= r) break;
  1772 				for (i = 0; i < num; i++) if (cumulative_probs[i] >= r) break;
  1709 
  1773 
  1740 			}
  1804 			}
  1741 
  1805 
  1742 			if (HASBITS(t->flags12 , oneof)) continue;
  1806 			if (HASBITS(t->flags12 , oneof)) continue;
  1743 
  1807 
  1744 			/* Make sure there is no slope? */
  1808 			/* Make sure there is no slope? */
  1745 			if (hs->building_flags & TILE_NOT_SLOPED && slope != SLOPE_FLAT) continue;
  1809 			bool noslope = (hs->building_flags & TILE_NOT_SLOPED) != 0;
       
  1810 			if (noslope && slope != SLOPE_FLAT) continue;
  1746 
  1811 
  1747 			if (hs->building_flags & TILE_SIZE_2x2) {
  1812 			if (hs->building_flags & TILE_SIZE_2x2) {
  1748 				if (CheckFree2x2Area(tile) ||
  1813 				if (CheckFree2x2Area(tile, maxz, noslope) ||
  1749 						CheckFree2x2Area(tile += TileDiffXY(-1,  0)) ||
  1814 						CheckFree2x2Area(tile += TileDiffXY(-1,  0), maxz, noslope) ||
  1750 						CheckFree2x2Area(tile += TileDiffXY( 0, -1)) ||
  1815 						CheckFree2x2Area(tile += TileDiffXY( 0, -1), maxz, noslope) ||
  1751 						CheckFree2x2Area(tile += TileDiffXY( 1,  0))) {
  1816 						CheckFree2x2Area(tile += TileDiffXY( 1,  0), maxz, noslope)) {
  1752 					break;
  1817 					break;
  1753 				}
  1818 				}
       
  1819 				/* return to original tile */
  1754 				tile += TileDiffXY(0, 1);
  1820 				tile += TileDiffXY(0, 1);
  1755 			} else if (hs->building_flags & TILE_SIZE_2x1) {
  1821 			} else if (hs->building_flags & TILE_SIZE_2x1) {
  1756 				if (CheckBuildHouseMode(tile + TileDiffXY(1, 0), slope, 0)) break;
  1822 				/* 'tile' is already checked above - CanBuildHouseHere() and slope test */
  1757 
  1823 				if (CheckBuildHouseSameZ(tile + TileDiffXY(1, 0), maxz, noslope)) break;
  1758 				if (CheckBuildHouseMode(tile + TileDiffXY(-1, 0), slope, 1)) {
  1824 
       
  1825 				if (CheckBuildHouseSameZ(tile + TileDiffXY(-1, 0), maxz, noslope)) {
  1759 					tile += TileDiffXY(-1, 0);
  1826 					tile += TileDiffXY(-1, 0);
  1760 					break;
  1827 					break;
  1761 				}
  1828 				}
  1762 			} else if (hs->building_flags & TILE_SIZE_1x2) {
  1829 			} else if (hs->building_flags & TILE_SIZE_1x2) {
  1763 				if (CheckBuildHouseMode(tile + TileDiffXY(0, 1), slope, 2)) break;
  1830 				if (CheckBuildHouseSameZ(tile + TileDiffXY(0, 1), maxz, noslope)) break;
  1764 
  1831 
  1765 				if (CheckBuildHouseMode(tile + TileDiffXY(0, -1), slope, 3)) {
  1832 				if (CheckBuildHouseSameZ(tile + TileDiffXY(0, -1), maxz, noslope)) {
  1766 					tile += TileDiffXY(0, -1);
  1833 					tile += TileDiffXY(0, -1);
  1767 					break;
  1834 					break;
  1768 				}
  1835 				}
  1769 			} else {
  1836 			} else {
  1770 				break;
  1837 				break;
  1793 				construction_counter = GB(r, 2, 2);
  1860 				construction_counter = GB(r, 2, 2);
  1794 			}
  1861 			}
  1795 		}
  1862 		}
  1796 		MakeTownHouse(tile, t->index, construction_counter, construction_stage, house, Random());
  1863 		MakeTownHouse(tile, t->index, construction_counter, construction_stage, house, Random());
  1797 	}
  1864 	}
  1798 }
  1865 
  1799 
       
  1800 static bool BuildTownHouse(Town *t, TileIndex tile)
       
  1801 {
       
  1802 	CommandCost r;
       
  1803 
       
  1804 	if (IsSteepSlope(GetTileSlope(tile, NULL))) return false;
       
  1805 	if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return false;
       
  1806 
       
  1807 	r = DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR);
       
  1808 	if (CmdFailed(r)) return false;
       
  1809 
       
  1810 	DoBuildTownHouse(t, tile);
       
  1811 	return true;
  1866 	return true;
  1812 }
  1867 }
  1813 
  1868 
  1814 
  1869 
  1815 static void DoClearTownHouseHelper(TileIndex tile)
  1870 static void DoClearTownHouseHelper(TileIndex tile)