Merge branch 'master' into town_cargo_adj

Conflicts:
	src/settings_gui.cpp
This commit is contained in:
Jonathan G Rennison
2015-08-02 00:04:04 +01:00
940 changed files with 57198 additions and 38591 deletions

View File

@@ -50,6 +50,8 @@
#include "table/strings.h"
#include "table/town_land.h"
#include "safeguards.h"
TownID _new_town_id;
uint32 _town_cargoes_accepted; ///< Bitmap of all cargoes accepted by houses.
@@ -169,7 +171,7 @@ Money HouseSpec::GetRemovalCost() const
return (_price[PR_CLEAR_HOUSE] * this->removal_cost) >> 8;
}
// Local
/* Local */
static int _grow_town_result;
/* Describe the possible states */
@@ -339,6 +341,24 @@ static void AnimateTile_Town(TileIndex tile)
*/
static bool IsCloseToTown(TileIndex tile, uint dist)
{
/* On a large map with many towns, it may be faster to check the surroundings of the tile.
* An iteration in TILE_AREA_LOOP() is generally 2 times faster than one in FOR_ALL_TOWNS(). */
if (Town::GetNumItems() > (size_t) (dist * dist * 2)) {
const int tx = TileX(tile);
const int ty = TileY(tile);
TileArea tile_area = TileArea(
TileXY(max(0, tx - (int) dist), max(0, ty - (int) dist)),
TileXY(min(MapMaxX(), tx + (int) dist), min(MapMaxY(), ty + (int) dist))
);
TILE_AREA_LOOP(atile, tile_area) {
if (GetTileType(atile) == MP_HOUSE) {
Town *t = Town::GetByTile(atile);
if (DistanceManhattan(tile, t->xy) < dist) return true;
}
}
return false;
}
const Town *t;
FOR_ALL_TOWNS(t) {
@@ -357,7 +377,8 @@ void Town::UpdateVirtCoord()
SetDParam(0, this->index);
SetDParam(1, this->cache.population);
this->cache.sign.UpdatePosition(pt.x, pt.y - 24 * ZOOM_LVL_BASE,
_settings_client.gui.population_in_label ? STR_VIEWPORT_TOWN_POP : STR_VIEWPORT_TOWN);
_settings_client.gui.population_in_label ? STR_VIEWPORT_TOWN_POP : STR_VIEWPORT_TOWN,
STR_VIEWPORT_TOWN);
SetWindowDirty(WC_TOWN_VIEW, this->index);
}
@@ -558,7 +579,7 @@ static void TileLoop_Town(TileIndex tile)
Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
if ((hs->building_flags & BUILDING_HAS_1_TILE) &&
HasBit(t->flags, TOWN_IS_FUNDED) &&
HasBit(t->flags, TOWN_IS_GROWING) &&
CanDeleteHouse(tile) &&
GetHouseAge(tile) >= hs->minimum_life &&
--t->time_until_rebuild == 0) {
@@ -806,7 +827,7 @@ static bool GrowTown(Town *t);
static void TownTickHandler(Town *t)
{
if (HasBit(t->flags, TOWN_IS_FUNDED)) {
if (HasBit(t->flags, TOWN_IS_GROWING)) {
int i = t->grow_counter - 1;
if (i < 0) {
if (GrowTown(t)) {
@@ -896,7 +917,7 @@ static bool IsRoadAllowedHere(Town *t, TileIndex tile, DiagDirection dir)
if (DistanceFromEdge(tile) == 0) return false;
/* Prevent towns from building roads under bridges along the bridge. Looks silly. */
if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile) && GetBridgeAxis(tile) == DiagDirToAxis(dir)) return false;
if (IsBridgeAbove(tile) && GetBridgeAxis(tile) == DiagDirToAxis(dir)) return false;
/* Check if there already is a road at this point? */
if (GetTownRoadBits(tile) == ROAD_NONE) {
@@ -1324,13 +1345,56 @@ static void GrowTownInTile(TileIndex *tile_ptr, RoadBits cur_rb, DiagDirection t
GrowTownWithRoad(t1, tile, rcmd);
}
/**
* Checks whether a road can be followed or is a dead end, that can not be extended to the next tile.
* This only checks trivial but often cases.
* @param tile Start tile for road.
* @param dir Direction for road to follow or build.
* @return true If road is or can be connected in the specified direction.
*/
static bool CanFollowRoad(TileIndex tile, DiagDirection dir)
{
TileIndex target_tile = tile + TileOffsByDiagDir(dir);
if (!IsValidTile(target_tile)) return false;
if (HasTileWaterGround(target_tile)) return false;
RoadBits target_rb = GetTownRoadBits(target_tile);
if (_settings_game.economy.allow_town_roads || _generating_world) {
/* Check whether a road connection exists or can be build. */
switch (GetTileType(target_tile)) {
case MP_ROAD:
return target_rb != ROAD_NONE;
case MP_STATION:
return IsDriveThroughStopTile(target_tile);
case MP_TUNNELBRIDGE:
return GetTunnelBridgeTransportType(target_tile) == TRANSPORT_ROAD;
case MP_HOUSE:
case MP_INDUSTRY:
case MP_OBJECT:
return false;
default:
/* Checked for void and water earlier */
return true;
}
} else {
/* Check whether a road connection already exists,
* and it leads somewhere else. */
RoadBits back_rb = DiagDirToRoadBits(ReverseDiagDir(dir));
return (target_rb & back_rb) != 0 && (target_rb & ~back_rb) != 0;
}
}
/**
* Returns "growth" if a house was built, or no if the build failed.
* @param t town to inquiry
* @param tile to inquiry
* @return something other than zero(0)if town expansion was possible
* @return true if town expansion was possible
*/
static int GrowTownAtRoad(Town *t, TileIndex tile)
static bool GrowTownAtRoad(Town *t, TileIndex tile)
{
/* Special case.
* @see GrowTownInTile Check the else if
@@ -1365,9 +1429,9 @@ static int GrowTownAtRoad(Town *t, TileIndex tile)
/* Exclude the source position from the bitmask
* and return if no more road blocks available */
cur_rb &= ~DiagDirToRoadBits(ReverseDiagDir(target_dir));
if (IsValidDiagDirection(target_dir)) cur_rb &= ~DiagDirToRoadBits(ReverseDiagDir(target_dir));
if (cur_rb == ROAD_NONE) {
return _grow_town_result;
return _grow_town_result == GROWTH_SUCCEED;
}
if (IsTileType(tile, MP_TUNNELBRIDGE)) {
@@ -1376,14 +1440,22 @@ static int GrowTownAtRoad(Town *t, TileIndex tile)
} else {
/* Select a random bit from the blockmask, walk a step
* and continue the search from there. */
do target_dir = RandomDiagDir(); while (!(cur_rb & DiagDirToRoadBits(target_dir)));
do {
if (cur_rb == ROAD_NONE) return false;
RoadBits target_bits;
do {
target_dir = RandomDiagDir();
target_bits = DiagDirToRoadBits(target_dir);
} while (!(cur_rb & target_bits));
cur_rb &= ~target_bits;
} while (!CanFollowRoad(tile, target_dir));
}
tile = TileAddByDiagDir(tile, target_dir);
if (IsTileType(tile, MP_ROAD) && !IsRoadDepot(tile) && HasTileRoadType(tile, ROADTYPE_ROAD)) {
/* Don't allow building over roads of other cities */
if (IsRoadOwner(tile, ROADTYPE_ROAD, OWNER_TOWN) && Town::GetByTile(tile) != t) {
_grow_town_result = GROWTH_SUCCEED;
return false;
} else if (IsRoadOwner(tile, ROADTYPE_ROAD, OWNER_NONE) && _game_mode == GM_EDITOR) {
/* If we are in the SE, and this road-piece has no town owner yet, it just found an
* owner :) (happy happy happy road now) */
@@ -1395,7 +1467,7 @@ static int GrowTownAtRoad(Town *t, TileIndex tile)
/* Max number of times is checked. */
} while (--_grow_town_result >= 0);
return (_grow_town_result == -2);
return _grow_town_result == GROWTH_SUCCEED - 1;
}
/**
@@ -1417,7 +1489,7 @@ static RoadBits GenRandomRoadBits()
/**
* Grow the town
* @param t town to grow
* @return true iff a house was built
* @return true iff something (house, road, bridge, ...) was built
*/
static bool GrowTown(Town *t)
{
@@ -1446,9 +1518,9 @@ static bool GrowTown(Town *t)
const TileIndexDiffC *ptr;
for (ptr = _town_coord_mod; ptr != endof(_town_coord_mod); ++ptr) {
if (GetTownRoadBits(tile) != ROAD_NONE) {
int r = GrowTownAtRoad(t, tile);
bool success = GrowTownAtRoad(t, tile);
cur_company.Restore();
return r != 0;
return success;
}
tile = TILE_ADD(tile, ToTileIndexDiff(*ptr));
}
@@ -1459,7 +1531,7 @@ static bool GrowTown(Town *t)
tile = t->xy;
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) == SLOPE_FLAT) {
if (!IsTileType(tile, MP_HOUSE) && IsTileFlat(tile)) {
if (DoCommand(tile, 0, 0, DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR).Succeeded()) {
DoCommand(tile, GenRandomRoadBits(), t->index, DC_EXEC | DC_AUTO, CMD_BUILD_ROAD);
cur_company.Restore();
@@ -1622,7 +1694,7 @@ static CommandCost TownCanBePlacedHere(TileIndex tile)
}
/* Can only build on clear flat areas, possibly with trees. */
if ((!IsTileType(tile, MP_CLEAR) && !IsTileType(tile, MP_TREES)) || GetTileSlope(tile) != SLOPE_FLAT) {
if ((!IsTileType(tile, MP_CLEAR) && !IsTileType(tile, MP_TREES)) || !IsTileFlat(tile)) {
return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
}
@@ -1669,14 +1741,17 @@ CommandCost CmdFoundTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
if (size >= TSZ_END) return CMD_ERROR;
if (layout >= NUM_TLS) return CMD_ERROR;
/* Some things are allowed only in the scenario editor */
if (_game_mode != GM_EDITOR) {
/* Some things are allowed only in the scenario editor and for game scripts. */
if (_game_mode != GM_EDITOR && _current_company != OWNER_DEITY) {
if (_settings_game.economy.found_town == TF_FORBIDDEN) return CMD_ERROR;
if (size == TSZ_LARGE) return CMD_ERROR;
if (random) return CMD_ERROR;
if (_settings_game.economy.found_town != TF_CUSTOM_LAYOUT && layout != _settings_game.economy.town_layout) {
return CMD_ERROR;
}
} else if (_current_company == OWNER_DEITY && random) {
/* Random parameter is not allowed for Game Scripts. */
return CMD_ERROR;
}
if (StrEmpty(text)) {
@@ -1712,7 +1787,7 @@ CommandCost CmdFoundTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
return CommandCost(EXPENSES_OTHER);
}
_generating_world = true;
Backup<bool> old_generating_world(_generating_world, true, FILE_LINE);
UpdateNearestTownForRoadTiles(true);
Town *t;
if (random) {
@@ -1727,10 +1802,10 @@ CommandCost CmdFoundTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
DoCreateTown(t, tile, townnameparts, size, city, layout, true);
}
UpdateNearestTownForRoadTiles(false);
_generating_world = false;
old_generating_world.Restore();
if (t != NULL && !StrEmpty(text)) {
t->name = strdup(text);
t->name = stredup(text);
t->UpdateVirtCoord();
}
@@ -1741,7 +1816,7 @@ CommandCost CmdFoundTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
SetDParam(0, _current_company);
GetString(company_name, STR_COMPANY_NAME, lastof(company_name));
char *cn = strdup(company_name);
char *cn = stredup(company_name);
SetDParamStr(0, cn);
SetDParam(1, t->index);
@@ -1820,7 +1895,7 @@ static bool FindFurthestFromWater(TileIndex tile, void *user_data)
uint dist = GetClosestWaterDistance(tile, true);
if (IsTileType(tile, MP_CLEAR) &&
GetTileSlope(tile) == SLOPE_FLAT &&
IsTileFlat(tile) &&
IsTileAlignedToGrid(tile, sp->layout) &&
dist > sp->max_dist) {
sp->tile = tile;
@@ -1925,7 +2000,9 @@ bool GenerateTowns(TownLayout layout)
uint current_number = 0;
uint difficulty = (_game_mode != GM_EDITOR) ? _settings_game.difficulty.number_towns : 0;
uint total = (difficulty == (uint)CUSTOM_TOWN_NUMBER_DIFFICULTY) ? _settings_game.game_creation.custom_town_number : ScaleByMapSize(_num_initial_towns[difficulty] + (Random() & 7));
total = min(TownPool::MAX_SIZE, total);
uint32 townnameparts;
TownNames town_names;
SetGeneratingWorldProgress(GWP_TOWN, total);
@@ -1936,11 +2013,13 @@ bool GenerateTowns(TownLayout layout)
bool city = (_settings_game.economy.larger_towns != 0 && Chance16(1, _settings_game.economy.larger_towns));
IncreaseGeneratingWorldProgress(GWP_TOWN);
/* Get a unique name for the town. */
if (!GenerateTownName(&townnameparts)) continue;
if (!GenerateTownName(&townnameparts, &town_names)) continue;
/* try 20 times to create a random-sized town for the first loop. */
if (CreateRandomTown(20, townnameparts, TSZ_RANDOM, city, layout) != NULL) current_number++; // If creation was successful, raise a flag.
} while (--total);
town_names.clear();
if (current_number != 0) return true;
/* If current_number is still zero at this point, it means that not a single town has been created.
@@ -2039,7 +2118,7 @@ static inline bool CanBuildHouseHere(TileIndex tile, TownID town, bool noslope)
if ((noslope && slope != SLOPE_FLAT) || IsSteepSlope(slope)) return false;
/* building under a bridge? */
if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return false;
if (IsBridgeAbove(tile)) return false;
/* do not try to build over house owned by another town */
if (IsTileType(tile, MP_HOUSE) && GetTownIndex(tile) != town) return false;
@@ -2239,13 +2318,13 @@ static bool BuildTownHouse(Town *t, TileIndex tile)
/* bits 0-4 are used
* bits 11-15 are used
* bits 5-10 are not used. */
HouseID houses[HOUSE_MAX];
HouseID houses[NUM_HOUSES];
uint num = 0;
uint probs[HOUSE_MAX];
uint probs[NUM_HOUSES];
uint probability_max = 0;
/* Generate a list of all possible houses that can be built. */
for (uint i = 0; i < HOUSE_MAX; i++) {
for (uint i = 0; i < NUM_HOUSES; i++) {
const HouseSpec *hs = HouseSpec::Get(i);
/* Verify that the candidate house spec matches the current tile status */
@@ -2469,7 +2548,7 @@ CommandCost CmdRenameTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
if (flags & DC_EXEC) {
free(t->name);
t->name = reset ? NULL : strdup(text);
t->name = reset ? NULL : stredup(text);
t->UpdateVirtCoord();
InvalidateWindowData(WC_TOWN_DIRECTORY, 0, 1);
@@ -2510,7 +2589,7 @@ CommandCost CmdTownCargoGoal(TileIndex tile, DoCommandFlag flags, uint32 p1, uin
if (_current_company != OWNER_DEITY) return CMD_ERROR;
TownEffect te = (TownEffect)GB(p1, 16, 8);
if (te < TE_BEGIN || te > TE_END) return CMD_ERROR;
if (te < TE_BEGIN || te >= TE_END) return CMD_ERROR;
uint16 index = GB(p1, 0, 16);
Town *t = Town::GetIfValid(index);
@@ -2546,7 +2625,7 @@ CommandCost CmdTownSetText(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
if (flags & DC_EXEC) {
free(t->text);
t->text = StrEmpty(text) ? NULL : strdup(text);
t->text = StrEmpty(text) ? NULL : stredup(text);
InvalidateWindowData(WC_TOWN_VIEW, p1);
}
@@ -2558,21 +2637,34 @@ CommandCost CmdTownSetText(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
* @param tile Unused.
* @param flags Type of operation.
* @param p1 Town ID to cargo game of.
* @param p2 Amount of days between growth.
* @param p2 Amount of days between growth, or TOWN_GROW_RATE_CUSTOM_NONE, or 0 to reset custom growth rate.
* @param text Unused.
* @return Empty cost or an error.
*/
CommandCost CmdTownGrowthRate(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
{
if (_current_company != OWNER_DEITY) return CMD_ERROR;
if ((p2 & TOWN_GROW_RATE_CUSTOM) != 0) return CMD_ERROR;
if ((p2 & TOWN_GROW_RATE_CUSTOM) != 0 && p2 != TOWN_GROW_RATE_CUSTOM_NONE) return CMD_ERROR;
if (GB(p2, 16, 16) != 0) return CMD_ERROR;
Town *t = Town::GetIfValid(p1);
if (t == NULL) return CMD_ERROR;
if (flags & DC_EXEC) {
t->growth_rate = (p2 == 0) ? 0 : p2 | TOWN_GROW_RATE_CUSTOM;
if (p2 == 0) {
/* Clear TOWN_GROW_RATE_CUSTOM, UpdateTownGrowRate will determine a proper value */
t->growth_rate = 0;
} else {
uint old_rate = t->growth_rate & ~TOWN_GROW_RATE_CUSTOM;
if (t->grow_counter >= old_rate) {
/* This also catches old_rate == 0 */
t->grow_counter = p2;
} else {
/* Scale grow_counter, so half finished houses stay half finished */
t->grow_counter = t->grow_counter * p2 / old_rate;
}
t->growth_rate = p2 | TOWN_GROW_RATE_CUSTOM;
}
UpdateTownGrowRate(t);
InvalidateWindowData(WC_TOWN_VIEW, p1);
}
@@ -2680,7 +2772,7 @@ CommandCost CmdDeleteTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
} else {
Object *o = Object::GetByTile(tile);
if (o->town == t) {
if (GetObjectType(tile) == OBJECT_STATUE) {
if (o->type == OBJECT_STATUE) {
/* Statue... always remove. */
try_clear = true;
} else {
@@ -2750,7 +2842,7 @@ static CommandCost TownActionRoadRebuild(Town *t, DoCommandFlag flags)
SetDParam(0, _current_company);
GetString(company_name, STR_COMPANY_NAME, lastof(company_name));
char *cn = strdup(company_name);
char *cn = stredup(company_name);
SetDParam(0, t->index);
SetDParamStr(1, cn);
@@ -2798,7 +2890,7 @@ static bool SearchTileForStatue(TileIndex tile, void *user_data)
/* Statues can be build on slopes, just like houses. Only the steep slopes is a no go. */
if (IsSteepSlope(GetTileSlope(tile))) return false;
/* Don't build statues under bridges. */
if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return false;
if (IsBridgeAbove(tile)) return false;
/* A clear-able open space is always preferred. */
if ((IsTileType(tile, MP_CLEAR) || IsTileType(tile, MP_TREES)) && TryClearTile(tile)) {
@@ -2858,11 +2950,12 @@ static CommandCost TownActionFundBuildings(Town *t, DoCommandFlag flags)
if (flags & DC_EXEC) {
/* Build next tick */
t->grow_counter = 1;
/* If we were not already growing */
SetBit(t->flags, TOWN_IS_FUNDED);
/* And grow for 3 months */
t->fund_buildings_months = 3;
/* Enable growth (also checking GameScript's opinion) */
UpdateTownGrowRate(t);
SetWindowDirty(WC_TOWN_VIEW, t->index);
}
return CommandCost();
@@ -3057,7 +3150,7 @@ static void UpdateTownRating(Town *t)
static void UpdateTownGrowRate(Town *t)
{
ClrBit(t->flags, TOWN_IS_FUNDED);
ClrBit(t->flags, TOWN_IS_GROWING);
SetWindowDirty(WC_TOWN_VIEW, t->index);
if (_settings_game.economy.town_growth_rate == 0 && t->fund_buildings_months == 0) return;
@@ -3080,7 +3173,7 @@ static void UpdateTownGrowRate(Town *t)
}
if ((t->growth_rate & TOWN_GROW_RATE_CUSTOM) != 0) {
SetBit(t->flags, TOWN_IS_FUNDED);
if (t->growth_rate != TOWN_GROW_RATE_CUSTOM_NONE) SetBit(t->flags, TOWN_IS_GROWING);
SetWindowDirty(WC_TOWN_VIEW, t->index);
return;
}
@@ -3122,11 +3215,9 @@ static void UpdateTownGrowRate(Town *t)
if (t->larger_town) m /= 2;
t->growth_rate = m / (t->cache.num_houses / 50 + 1);
if (m <= t->grow_counter) {
t->grow_counter = m;
}
t->grow_counter = min(t->growth_rate, t->grow_counter);
SetBit(t->flags, TOWN_IS_FUNDED);
SetBit(t->flags, TOWN_IS_GROWING);
SetWindowDirty(WC_TOWN_VIEW, t->index);
}
@@ -3423,7 +3514,7 @@ extern const TileTypeProcs _tile_type_town_procs = {
};
HouseSpec _house_specs[HOUSE_MAX];
HouseSpec _house_specs[NUM_HOUSES];
void ResetHouses()
{