Merge remote-tracking branch 'upstream/master' into 13.0
This commit is contained in:
@@ -40,8 +40,10 @@
|
||||
#include "object_base.h"
|
||||
#include "game/game.hpp"
|
||||
#include "error.h"
|
||||
#include "cmd_helper.h"
|
||||
#include "string_func.h"
|
||||
#include "industry_cmd.h"
|
||||
#include "landscape_cmd.h"
|
||||
#include "terraform_cmd.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
#include "table/industry_land.h"
|
||||
@@ -199,7 +201,7 @@ Industry::~Industry()
|
||||
CargoPacket::InvalidateAllFrom(ST_INDUSTRY, this->index);
|
||||
|
||||
for (Station *st : this->stations_near) {
|
||||
st->industries_near.erase(this);
|
||||
st->RemoveIndustryToDeliver(this);
|
||||
}
|
||||
citymania::UpdateIndustryHighlight();
|
||||
}
|
||||
@@ -1103,7 +1105,7 @@ static bool SearchLumberMillTrees(TileIndex tile, void *user_data)
|
||||
_industry_sound_tile = tile;
|
||||
if (_settings_client.sound.ambient) SndPlayTileFx(SND_38_LUMBER_MILL_1, tile);
|
||||
|
||||
DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
|
||||
Command<CMD_LANDSCAPE_CLEAR>::Do(DC_EXEC, tile);
|
||||
|
||||
cur_company.Restore();
|
||||
return true;
|
||||
@@ -1430,18 +1432,12 @@ bool IsSlopeRefused(Slope current, Slope refused)
|
||||
* Are the tiles of the industry free?
|
||||
* @param tile Position to check.
|
||||
* @param layout Industry tiles table.
|
||||
* @param layout_index The index of the layout to build/fund
|
||||
* @param type Type of the industry.
|
||||
* @param initial_random_bits The random bits the industry is going to have after construction.
|
||||
* @param founder Industry founder
|
||||
* @param creation_type The circumstances the industry is created under.
|
||||
* @param[out] custom_shape_check Perform custom check for the site.
|
||||
* @return Failed or succeeded command.
|
||||
*/
|
||||
static CommandCost CheckIfIndustryTilesAreFree(TileIndex tile, const IndustryTileLayout &layout, size_t layout_index, int type, uint16 initial_random_bits, Owner founder, IndustryAvailabilityCallType creation_type, bool *custom_shape_check = nullptr)
|
||||
static CommandCost CheckIfIndustryTilesAreFree(TileIndex tile, const IndustryTileLayout &layout, IndustryType type)
|
||||
{
|
||||
bool refused_slope = false;
|
||||
bool custom_shape = false;
|
||||
IndustryBehaviour ind_behav = GetIndustrySpec(type)->behaviour;
|
||||
|
||||
for (const IndustryTileLayoutTile &it : layout) {
|
||||
IndustryGfx gfx = GetTranslatedIndustryTileID(it.gfx);
|
||||
@@ -1463,20 +1459,9 @@ static CommandCost CheckIfIndustryTilesAreFree(TileIndex tile, const IndustryTil
|
||||
|
||||
const IndustryTileSpec *its = GetIndustryTileSpec(gfx);
|
||||
|
||||
IndustryBehaviour ind_behav = GetIndustrySpec(type)->behaviour;
|
||||
|
||||
/* Perform land/water check if not disabled */
|
||||
if (!HasBit(its->slopes_refused, 5) && ((HasTileWaterClass(cur_tile) && IsTileOnWater(cur_tile)) == !(ind_behav & INDUSTRYBEH_BUILT_ONWATER))) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
|
||||
|
||||
if (HasBit(its->callback_mask, CBM_INDT_SHAPE_CHECK)) {
|
||||
custom_shape = true;
|
||||
CommandCost ret = PerformIndustryTileSlopeCheck(tile, cur_tile, its, type, gfx, layout_index, initial_random_bits, founder, creation_type);
|
||||
if (ret.Failed()) return ret;
|
||||
} else {
|
||||
Slope tileh = GetTileSlope(cur_tile);
|
||||
refused_slope |= IsSlopeRefused(tileh, its->slopes_refused);
|
||||
}
|
||||
|
||||
if ((ind_behav & (INDUSTRYBEH_ONLY_INTOWN | INDUSTRYBEH_TOWN1200_MORE)) || // Tile must be a house
|
||||
((ind_behav & INDUSTRYBEH_ONLY_NEARTOWN) && IsTileType(cur_tile, MP_HOUSE))) { // Tile is allowed to be a house (and it is a house)
|
||||
if (!IsTileType(cur_tile, MP_HOUSE)) {
|
||||
@@ -1485,19 +1470,57 @@ static CommandCost CheckIfIndustryTilesAreFree(TileIndex tile, const IndustryTil
|
||||
|
||||
/* Clear the tiles as OWNER_TOWN to not affect town rating, and to not clear protected buildings */
|
||||
Backup<CompanyID> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
|
||||
CommandCost ret = DoCommand(cur_tile, 0, 0, DC_NONE, CMD_LANDSCAPE_CLEAR);
|
||||
CommandCost ret = Command<CMD_LANDSCAPE_CLEAR>::Do(DC_NONE, cur_tile);
|
||||
cur_company.Restore();
|
||||
|
||||
if (ret.Failed()) return ret;
|
||||
} else {
|
||||
/* Clear the tiles, but do not affect town ratings */
|
||||
CommandCost ret = DoCommand(cur_tile, 0, 0, DC_AUTO | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING, CMD_LANDSCAPE_CLEAR);
|
||||
|
||||
CommandCost ret = Command<CMD_LANDSCAPE_CLEAR>::Do(DC_AUTO | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING, cur_tile);
|
||||
if (ret.Failed()) return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CommandCost();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check slope requirements for industry tiles.
|
||||
* @param tile Position to check.
|
||||
* @param layout Industry tiles table.
|
||||
* @param layout_index The index of the layout to build/fund
|
||||
* @param type Type of the industry.
|
||||
* @param initial_random_bits The random bits the industry is going to have after construction.
|
||||
* @param founder Industry founder
|
||||
* @param creation_type The circumstances the industry is created under.
|
||||
* @param[out] custom_shape_check Perform custom check for the site.
|
||||
* @return Failed or succeeded command.
|
||||
*/
|
||||
static CommandCost CheckIfIndustryTileSlopes(TileIndex tile, const IndustryTileLayout &layout, size_t layout_index, int type, uint16 initial_random_bits, Owner founder, IndustryAvailabilityCallType creation_type, bool *custom_shape_check = nullptr)
|
||||
{
|
||||
bool refused_slope = false;
|
||||
bool custom_shape = false;
|
||||
|
||||
for (const IndustryTileLayoutTile &it : layout) {
|
||||
IndustryGfx gfx = GetTranslatedIndustryTileID(it.gfx);
|
||||
TileIndex cur_tile = TileAddWrap(tile, it.ti.x, it.ti.y);
|
||||
assert(IsValidTile(cur_tile)); // checked before in CheckIfIndustryTilesAreFree
|
||||
|
||||
if (gfx != GFX_WATERTILE_SPECIALCHECK) {
|
||||
const IndustryTileSpec *its = GetIndustryTileSpec(gfx);
|
||||
|
||||
if (HasBit(its->callback_mask, CBM_INDT_SHAPE_CHECK)) {
|
||||
custom_shape = true;
|
||||
CommandCost ret = PerformIndustryTileSlopeCheck(tile, cur_tile, its, type, gfx, layout_index, initial_random_bits, founder, creation_type);
|
||||
if (ret.Failed()) return ret;
|
||||
} else {
|
||||
Slope tileh = GetTileSlope(cur_tile);
|
||||
refused_slope |= IsSlopeRefused(tileh, its->slopes_refused);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (custom_shape_check != nullptr) *custom_shape_check = custom_shape;
|
||||
|
||||
/* It is almost impossible to have a fully flat land in TG, so what we
|
||||
@@ -1601,7 +1624,7 @@ static bool CheckIfCanLevelIndustryPlatform(TileIndex tile, DoCommandFlag flags,
|
||||
}
|
||||
/* This is not 100% correct check, but the best we can do without modifying the map.
|
||||
* What is missing, is if the difference in height is more than 1.. */
|
||||
if (DoCommand(tile_walk, SLOPE_N, (curh > h) ? 0 : 1, flags & ~DC_EXEC, CMD_TERRAFORM_LAND).Failed()) {
|
||||
if (std::get<0>(Command<CMD_TERRAFORM_LAND>::Do(flags & ~DC_EXEC, tile_walk, SLOPE_N, curh <= h)).Failed()) {
|
||||
cur_company.Restore();
|
||||
return false;
|
||||
}
|
||||
@@ -1616,7 +1639,7 @@ static bool CheckIfCanLevelIndustryPlatform(TileIndex tile, DoCommandFlag flags,
|
||||
/* We give the terraforming for free here, because we can't calculate
|
||||
* exact cost in the test-round, and as we all know, that will cause
|
||||
* a nice assert if they don't match ;) */
|
||||
DoCommand(tile_walk, SLOPE_N, (curh > h) ? 0 : 1, flags, CMD_TERRAFORM_LAND);
|
||||
Command<CMD_TERRAFORM_LAND>::Do(flags, tile_walk, SLOPE_N, curh <= h);
|
||||
curh += (curh > h) ? -1 : 1;
|
||||
}
|
||||
}
|
||||
@@ -1702,15 +1725,15 @@ static void PopulateStationsNearby(Industry *ind)
|
||||
/* Industry has a neutral station. Use it and ignore any other nearby stations. */
|
||||
ind->stations_near.insert(ind->neutral_station);
|
||||
ind->neutral_station->industries_near.clear();
|
||||
ind->neutral_station->industries_near.insert(ind);
|
||||
ind->neutral_station->industries_near.insert(IndustryListEntry{0, ind});
|
||||
return;
|
||||
}
|
||||
|
||||
ForAllStationsAroundTiles(ind->location, [ind](Station *st, TileIndex tile) {
|
||||
if (!IsTileType(tile, MP_INDUSTRY) || GetIndustryIndex(tile) != ind->index) return false;
|
||||
ind->stations_near.insert(st);
|
||||
st->AddIndustryToDeliver(ind);
|
||||
return true;
|
||||
st->AddIndustryToDeliver(ind, tile);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1886,7 +1909,7 @@ static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type,
|
||||
|
||||
WaterClass wc = (IsWaterTile(cur_tile) ? GetWaterClass(cur_tile) : WATER_CLASS_INVALID);
|
||||
|
||||
DoCommand(cur_tile, 0, 0, DC_EXEC | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING, CMD_LANDSCAPE_CLEAR);
|
||||
Command<CMD_LANDSCAPE_CLEAR>::Do(DC_EXEC | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING, cur_tile);
|
||||
|
||||
MakeIndustry(cur_tile, i->index, it.gfx, Random(), wc);
|
||||
|
||||
@@ -1931,28 +1954,11 @@ static CommandCost CreateNewIndustryHelper(TileIndex tile, IndustryType type, Do
|
||||
{
|
||||
assert(layout_index < indspec->layouts.size());
|
||||
const IndustryTileLayout &layout = indspec->layouts[layout_index];
|
||||
bool custom_shape_check = false;
|
||||
|
||||
*ip = nullptr;
|
||||
|
||||
std::vector<ClearedObjectArea> object_areas(_cleared_object_areas);
|
||||
CommandCost ret = CheckIfIndustryTilesAreFree(tile, layout, layout_index, type, random_initial_bits, founder, creation_type, &custom_shape_check);
|
||||
_cleared_object_areas = object_areas;
|
||||
if (ret.Failed()) return ret;
|
||||
|
||||
if (HasBit(GetIndustrySpec(type)->callback_mask, CBM_IND_LOCATION)) {
|
||||
ret = CheckIfCallBackAllowsCreation(tile, type, layout_index, random_var8f, random_initial_bits, founder, creation_type);
|
||||
} else {
|
||||
ret = _check_new_industry_procs[indspec->check_proc](tile);
|
||||
}
|
||||
if (ret.Failed()) return ret;
|
||||
|
||||
if (!custom_shape_check && _settings_game.game_creation.land_generator == LG_TERRAGENESIS && _generating_world &&
|
||||
!_ignore_restrictions && !CheckIfCanLevelIndustryPlatform(tile, DC_NO_WATER, layout, type)) {
|
||||
return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
|
||||
}
|
||||
|
||||
ret = CheckIfFarEnoughFromConflictingIndustry(tile, type);
|
||||
/* 1. Cheap: Built-in checks on industry level. */
|
||||
CommandCost ret = CheckIfFarEnoughFromConflictingIndustry(tile, type);
|
||||
if (ret.Failed()) return ret;
|
||||
|
||||
Town *t = nullptr;
|
||||
@@ -1963,6 +1969,30 @@ static CommandCost CreateNewIndustryHelper(TileIndex tile, IndustryType type, Do
|
||||
ret = CheckIfIndustryIsAllowed(tile, type, t);
|
||||
if (ret.Failed()) return ret;
|
||||
|
||||
/* 2. Built-in checks on industry tiles. */
|
||||
std::vector<ClearedObjectArea> object_areas(_cleared_object_areas);
|
||||
ret = CheckIfIndustryTilesAreFree(tile, layout, type);
|
||||
_cleared_object_areas = object_areas;
|
||||
if (ret.Failed()) return ret;
|
||||
|
||||
/* 3. NewGRF-defined checks on industry level. */
|
||||
if (HasBit(GetIndustrySpec(type)->callback_mask, CBM_IND_LOCATION)) {
|
||||
ret = CheckIfCallBackAllowsCreation(tile, type, layout_index, random_var8f, random_initial_bits, founder, creation_type);
|
||||
} else {
|
||||
ret = _check_new_industry_procs[indspec->check_proc](tile);
|
||||
}
|
||||
if (ret.Failed()) return ret;
|
||||
|
||||
/* 4. Expensive: NewGRF-defined checks on industry tiles. */
|
||||
bool custom_shape_check = false;
|
||||
ret = CheckIfIndustryTileSlopes(tile, layout, layout_index, type, random_initial_bits, founder, creation_type, &custom_shape_check);
|
||||
if (ret.Failed()) return ret;
|
||||
|
||||
if (!custom_shape_check && _settings_game.game_creation.land_generator == LG_TERRAGENESIS && _generating_world &&
|
||||
!_ignore_restrictions && !CheckIfCanLevelIndustryPlatform(tile, DC_NO_WATER, layout, type)) {
|
||||
return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
|
||||
}
|
||||
|
||||
if (!Industry::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_INDUSTRIES);
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
@@ -2010,19 +2040,16 @@ bool CanBuildIndustryOnTile(IndustryType type, TileIndex tile) {
|
||||
|
||||
/**
|
||||
* Build/Fund an industry
|
||||
* @param tile tile where industry is built
|
||||
* @param flags of operations to conduct
|
||||
* @param p1 various bitstuffed elements
|
||||
* - p1 = (bit 0 - 7) - industry type see build_industry.h and see industry.h
|
||||
* - p1 = (bit 8 - 15) - first layout to try
|
||||
* - p1 = (bit 16 ) - 0 = prospect, 1 = fund (only valid if current company is DEITY)
|
||||
* @param p2 seed to use for desyncfree randomisations
|
||||
* @param text unused
|
||||
* @param tile tile where industry is built
|
||||
* @param it industry type see build_industry.h and see industry.h
|
||||
* @param first_layout first layout to try
|
||||
* @param fund false = prospect, true = fund (only valid if current company is DEITY)
|
||||
* @param seed seed to use for desyncfree randomisations
|
||||
* @return the cost of this operation or an error
|
||||
*/
|
||||
CommandCost CmdBuildIndustry(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const std::string &text)
|
||||
CommandCost CmdBuildIndustry(DoCommandFlag flags, TileIndex tile, IndustryType it, uint32 first_layout, bool fund, uint32 seed)
|
||||
{
|
||||
IndustryType it = GB(p1, 0, 8);
|
||||
if (it >= NUM_INDUSTRYTYPES) return CMD_ERROR;
|
||||
|
||||
const IndustrySpec *indspec = GetIndustrySpec(it);
|
||||
@@ -2041,12 +2068,12 @@ CommandCost CmdBuildIndustry(TileIndex tile, DoCommandFlag flags, uint32 p1, uin
|
||||
}
|
||||
|
||||
Randomizer randomizer;
|
||||
randomizer.SetSeed(p2);
|
||||
uint16 random_initial_bits = GB(p2, 0, 16);
|
||||
randomizer.SetSeed(seed);
|
||||
uint16 random_initial_bits = GB(seed, 0, 16);
|
||||
uint32 random_var8f = randomizer.Next();
|
||||
size_t num_layouts = indspec->layouts.size();
|
||||
CommandCost ret = CommandCost(STR_ERROR_SITE_UNSUITABLE);
|
||||
const bool deity_prospect = _current_company == OWNER_DEITY && !HasBit(p1, 16);
|
||||
const bool deity_prospect = _current_company == OWNER_DEITY && !fund;
|
||||
|
||||
Industry *ind = nullptr;
|
||||
if (deity_prospect || (_game_mode != GM_EDITOR && _current_company != OWNER_DEITY && _settings_game.construction.raw_industry_construction == 2 && indspec->IsRawIndustry())) {
|
||||
@@ -2076,7 +2103,7 @@ CommandCost CmdBuildIndustry(TileIndex tile, DoCommandFlag flags, uint32 p1, uin
|
||||
cur_company.Restore();
|
||||
}
|
||||
} else {
|
||||
size_t layout = GB(p1, 8, 8);
|
||||
size_t layout = first_layout;
|
||||
if (layout >= num_layouts) return CMD_ERROR;
|
||||
|
||||
/* Check subsequently each layout, starting with the given layout in p1 */
|
||||
@@ -2099,41 +2126,32 @@ CommandCost CmdBuildIndustry(TileIndex tile, DoCommandFlag flags, uint32 p1, uin
|
||||
|
||||
/**
|
||||
* Change industry properties
|
||||
* @param tile Unused.
|
||||
* @param flags Type of operation.
|
||||
* @param p1 IndustryID
|
||||
* @param p2 various bitstuffed elements
|
||||
* - p2 = (bit 0 - 7) - IndustryAction to perform
|
||||
* - p2 = (bit 8 - 15) - IndustryControlFlags
|
||||
* (only used with set control flags)
|
||||
* - p2 = (bit 16 - 23) - CompanyID to set or INVALID_OWNER (available to everyone) or
|
||||
* OWNER_NONE (neutral stations only) or OWNER_DEITY (no one)
|
||||
* (only used with set exclusive supplier / consumer)
|
||||
* @param ind_id IndustryID
|
||||
* @param action IndustryAction to perform
|
||||
* @param ctlflags IndustryControlFlags (only used with set control flags)
|
||||
* @param company_id CompanyID to set or INVALID_OWNER (available to everyone) or
|
||||
* OWNER_NONE (neutral stations only) or OWNER_DEITY (no one)
|
||||
* (only used with set exclusive supplier / consumer)
|
||||
* @param text - Additional industry text (only used with set text action)
|
||||
* @return Empty cost or an error.
|
||||
*/
|
||||
CommandCost CmdIndustryCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const std::string &text)
|
||||
CommandCost CmdIndustryCtrl(DoCommandFlag flags, IndustryID ind_id, IndustryAction action, IndustryControlFlags ctlflags, Owner company_id, const std::string &text)
|
||||
{
|
||||
if (_current_company != OWNER_DEITY) return CMD_ERROR;
|
||||
|
||||
Industry *ind = Industry::GetIfValid(p1);
|
||||
Industry *ind = Industry::GetIfValid(ind_id);
|
||||
if (ind == nullptr) return CMD_ERROR;
|
||||
|
||||
auto action = static_cast<IndustryAction>(GB(p2, 0, 8));
|
||||
|
||||
switch (action) {
|
||||
case IndustryAction::SetControlFlags: {
|
||||
IndustryControlFlags ctlflags = (IndustryControlFlags)GB(p2, 8, 8) & INDCTL_MASK;
|
||||
|
||||
if (flags & DC_EXEC) ind->ctlflags = ctlflags;
|
||||
if (flags & DC_EXEC) ind->ctlflags = ctlflags & INDCTL_MASK;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case IndustryAction::SetExclusiveSupplier:
|
||||
case IndustryAction::SetExclusiveConsumer: {
|
||||
Owner company_id = (Owner)GB(p2, 16, 8);
|
||||
|
||||
if (company_id != OWNER_NONE && company_id != INVALID_OWNER && company_id != OWNER_DEITY
|
||||
&& !Company::IsValidID(company_id)) return CMD_ERROR;
|
||||
|
||||
@@ -3097,7 +3115,7 @@ static CommandCost TerraformTile_Industry(TileIndex tile, DoCommandFlag flags, i
|
||||
}
|
||||
}
|
||||
}
|
||||
return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
|
||||
return Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile);
|
||||
}
|
||||
|
||||
extern const TileTypeProcs _tile_type_industry_procs = {
|
||||
@@ -3117,7 +3135,8 @@ extern const TileTypeProcs _tile_type_industry_procs = {
|
||||
TerraformTile_Industry, // terraform_tile_proc
|
||||
};
|
||||
|
||||
bool IndustryCompare::operator() (const Industry *lhs, const Industry *rhs) const
|
||||
bool IndustryCompare::operator() (const IndustryListEntry &lhs, const IndustryListEntry &rhs) const
|
||||
{
|
||||
return lhs->index < rhs->index;
|
||||
/* Compare by distance first and use index as a tiebreaker. */
|
||||
return std::tie(lhs.distance, lhs.industry->index) < std::tie(rhs.distance, rhs.industry->index);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user