Merge remote-tracking branch 'upstream/master'
This commit is contained in:
@@ -8,6 +8,8 @@
|
||||
/** @file industry_cmd.cpp Handling of industry tiles. */
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "misc/history_type.hpp"
|
||||
#include "misc/history_func.hpp"
|
||||
#include "clear_map.h"
|
||||
#include "industry.h"
|
||||
#include "station_base.h"
|
||||
@@ -66,7 +68,7 @@ void BuildOilRig(TileIndex tile);
|
||||
static uint8_t _industry_sound_ctr;
|
||||
static TileIndex _industry_sound_tile;
|
||||
|
||||
std::array<std::vector<IndustryID>, NUM_INDUSTRYTYPES> Industry::industries;
|
||||
std::array<FlatSet<IndustryID>, NUM_INDUSTRYTYPES> Industry::industries;
|
||||
|
||||
IndustrySpec _industry_specs[NUM_INDUSTRYTYPES];
|
||||
IndustryTileSpec _industry_tile_specs[NUM_INDUSTRYTILES];
|
||||
@@ -195,8 +197,7 @@ Industry::~Industry()
|
||||
delete this->psa;
|
||||
|
||||
auto &industries = Industry::industries[type];
|
||||
auto it = std::ranges::lower_bound(industries, this->index);
|
||||
industries.erase(it);
|
||||
industries.erase(this->index);
|
||||
|
||||
DeleteIndustryNews(this->index);
|
||||
CloseWindowById(WC_INDUSTRY_VIEW, this->index);
|
||||
@@ -342,7 +343,7 @@ static void DrawTile_Industry(TileInfo *ti)
|
||||
* DrawNewIndustry will return false if ever the resolver could not
|
||||
* find any sprite to display. So in this case, we will jump on the
|
||||
* substitute gfx instead. */
|
||||
if (indts->grf_prop.GetSpriteGroup() != nullptr && DrawNewIndustryTile(ti, ind, gfx, indts)) {
|
||||
if (indts->grf_prop.HasSpriteGroups() && DrawNewIndustryTile(ti, ind, gfx, indts)) {
|
||||
return;
|
||||
} else {
|
||||
/* No sprite group (or no valid one) found, meaning no graphics associated.
|
||||
@@ -369,7 +370,7 @@ static void DrawTile_Industry(TileInfo *ti)
|
||||
if (image == SPR_FLAT_WATER_TILE && IsTileOnWater(ti->tile)) {
|
||||
DrawWaterClassGround(ti);
|
||||
} else {
|
||||
DrawGroundSprite(image, GroundSpritePaletteTransform(image, dits->ground.pal, GENERAL_SPRITE_COLOUR(ind->random_colour)));
|
||||
DrawGroundSprite(image, GroundSpritePaletteTransform(image, dits->ground.pal, GetColourPalette(ind->random_colour)));
|
||||
}
|
||||
|
||||
/* If industries are transparent and invisible, do not draw the upper part */
|
||||
@@ -378,14 +379,8 @@ static void DrawTile_Industry(TileInfo *ti)
|
||||
/* Add industry on top of the ground? */
|
||||
image = dits->building.sprite;
|
||||
if (image != 0) {
|
||||
AddSortableSpriteToDraw(image, SpriteLayoutPaletteTransform(image, dits->building.pal, GENERAL_SPRITE_COLOUR(ind->random_colour)),
|
||||
ti->x + dits->subtile_x,
|
||||
ti->y + dits->subtile_y,
|
||||
dits->width,
|
||||
dits->height,
|
||||
dits->dz,
|
||||
ti->z,
|
||||
IsTransparencySet(TO_INDUSTRIES));
|
||||
AddSortableSpriteToDraw(image, SpriteLayoutPaletteTransform(image, dits->building.pal, GetColourPalette(ind->random_colour)),
|
||||
*ti, *dits, IsTransparencySet(TO_INDUSTRIES));
|
||||
|
||||
if (IsTransparencySet(TO_INDUSTRIES)) return;
|
||||
}
|
||||
@@ -411,7 +406,7 @@ static Foundation GetFoundation_Industry(TileIndex tile, Slope tileh)
|
||||
*/
|
||||
if (gfx >= NEW_INDUSTRYTILEOFFSET) {
|
||||
const IndustryTileSpec *indts = GetIndustryTileSpec(gfx);
|
||||
if (indts->grf_prop.GetSpriteGroup() != nullptr && indts->callback_mask.Test(IndustryTileCallbackMask::DrawFoundations)) {
|
||||
if (indts->callback_mask.Test(IndustryTileCallbackMask::DrawFoundations)) {
|
||||
uint32_t callback_res = GetIndustryTileCallback(CBID_INDTILE_DRAW_FOUNDATIONS, 0, 0, gfx, Industry::GetByTile(tile), tile);
|
||||
if (callback_res != CALLBACK_FAILED && !ConvertBooleanCallback(indts->grf_prop.grffile, CBID_INDTILE_DRAW_FOUNDATIONS, callback_res)) return FOUNDATION_NONE;
|
||||
}
|
||||
@@ -702,7 +697,7 @@ static void AnimateTile_Industry(TileIndex tile)
|
||||
{
|
||||
IndustryGfx gfx = GetIndustryGfx(tile);
|
||||
|
||||
if (GetIndustryTileSpec(gfx)->animation.status != ANIM_STATUS_NO_ANIMATION) {
|
||||
if (GetIndustryTileSpec(gfx)->animation.status != AnimationStatus::NoAnimation) {
|
||||
AnimateNewIndustryTile(tile);
|
||||
return;
|
||||
}
|
||||
@@ -712,7 +707,7 @@ static void AnimateTile_Industry(TileIndex tile)
|
||||
if ((TimerGameTick::counter & 1) == 0) AnimateSugarSieve(tile);
|
||||
break;
|
||||
|
||||
case GFX_TOFFEE_QUARY:
|
||||
case GFX_TOFFEE_QUARRY:
|
||||
if ((TimerGameTick::counter & 3) == 0) AnimateToffeeQuarry(tile);
|
||||
break;
|
||||
|
||||
@@ -769,7 +764,7 @@ static void MakeIndustryTileBigger(TileIndex tile)
|
||||
uint8_t stage = GetIndustryConstructionStage(tile) + 1;
|
||||
SetIndustryConstructionCounter(tile, 0);
|
||||
SetIndustryConstructionStage(tile, stage);
|
||||
StartStopIndustryTileAnimation(tile, IAT_CONSTRUCTION_STATE_CHANGE);
|
||||
TriggerIndustryTileAnimation_ConstructionStageChanged(tile, false);
|
||||
if (stage == INDUSTRY_COMPLETED) SetIndustryCompleted(tile);
|
||||
|
||||
MarkTileDirtyByTile(tile);
|
||||
@@ -804,7 +799,7 @@ static void MakeIndustryTileBigger(TileIndex tile)
|
||||
|
||||
case GFX_TOY_FACTORY:
|
||||
case GFX_BUBBLE_CATCHER:
|
||||
case GFX_TOFFEE_QUARY:
|
||||
case GFX_TOFFEE_QUARRY:
|
||||
SetAnimationFrame(tile, 0);
|
||||
SetIndustryAnimationLoop(tile, 0);
|
||||
break;
|
||||
@@ -850,7 +845,7 @@ static void TileLoop_Industry(TileIndex tile)
|
||||
* returning from TileLoop_Water. */
|
||||
if (!IsTileType(tile, MP_INDUSTRY)) return;
|
||||
|
||||
TriggerIndustryTile(tile, INDTILE_TRIGGER_TILE_LOOP);
|
||||
TriggerIndustryTileRandomisation(tile, IndustryRandomTrigger::TileLoop);
|
||||
|
||||
if (!IsIndustryCompleted(tile)) {
|
||||
MakeIndustryTileBigger(tile);
|
||||
@@ -859,7 +854,7 @@ static void TileLoop_Industry(TileIndex tile)
|
||||
|
||||
if (_game_mode == GM_EDITOR) return;
|
||||
|
||||
if (TransportIndustryGoods(tile) && !StartStopIndustryTileAnimation(Industry::GetByTile(tile), IAT_INDUSTRY_DISTRIBUTES_CARGO)) {
|
||||
if (TransportIndustryGoods(tile) && !TriggerIndustryAnimation(Industry::GetByTile(tile), IndustryAnimationTrigger::CargoDistributed)) {
|
||||
uint newgfx = GetIndustryTileSpec(GetIndustryGfx(tile))->anim_production;
|
||||
|
||||
if (newgfx != INDUSTRYTILE_NOANIM) {
|
||||
@@ -871,7 +866,7 @@ static void TileLoop_Industry(TileIndex tile)
|
||||
}
|
||||
}
|
||||
|
||||
if (StartStopIndustryTileAnimation(tile, IAT_TILELOOP)) return;
|
||||
if (TriggerIndustryTileAnimation(tile, IndustryAnimationTrigger::TileLoop)) return;
|
||||
|
||||
IndustryGfx newgfx = GetIndustryTileSpec(GetIndustryGfx(tile))->anim_next;
|
||||
if (newgfx != INDUSTRYTILE_NOANIM) {
|
||||
@@ -949,7 +944,7 @@ static void TileLoop_Industry(TileIndex tile)
|
||||
TileLoopIndustry_BubbleGenerator(tile);
|
||||
break;
|
||||
|
||||
case GFX_TOFFEE_QUARY:
|
||||
case GFX_TOFFEE_QUARRY:
|
||||
AddAnimatedTile(tile);
|
||||
break;
|
||||
|
||||
@@ -1109,30 +1104,6 @@ void PlantRandomFarmField(const Industry *i)
|
||||
if (tile != INVALID_TILE) PlantFarmField(tile, i->index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search callback function for ChopLumberMillTrees
|
||||
* @param tile to test
|
||||
* @return the result of the test
|
||||
*/
|
||||
static bool SearchLumberMillTrees(TileIndex tile, void *)
|
||||
{
|
||||
if (IsTileType(tile, MP_TREES) && GetTreeGrowth(tile) >= TreeGrowthStage::Grown) {
|
||||
/* found a tree */
|
||||
|
||||
Backup<CompanyID> cur_company(_current_company, OWNER_NONE);
|
||||
|
||||
_industry_sound_ctr = 1;
|
||||
_industry_sound_tile = tile;
|
||||
if (_settings_client.sound.ambient) SndPlayTileFx(SND_38_LUMBER_MILL_1, tile);
|
||||
|
||||
Command<CMD_LANDSCAPE_CLEAR>::Do(DoCommandFlag::Execute, tile);
|
||||
|
||||
cur_company.Restore();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a circular search around the Lumber Mill in order to find trees to cut
|
||||
* @param i industry
|
||||
@@ -1150,9 +1121,20 @@ static void ChopLumberMillTrees(Industry *i)
|
||||
}
|
||||
}
|
||||
|
||||
TileIndex tile = i->location.tile;
|
||||
if (CircularTileSearch(&tile, 40, SearchLumberMillTrees, nullptr)) { // 40x40 tiles to search.
|
||||
itp->waiting = ClampTo<uint16_t>(itp->waiting + ScaleByCargoScale(45, false)); // Found a tree, add according value to waiting cargo.
|
||||
for (auto tile : SpiralTileSequence(i->location.tile, 40)) { // 40x40 tiles to search.
|
||||
if (!IsTileType(tile, MP_TREES) || GetTreeGrowth(tile) < TreeGrowthStage::Grown) continue;
|
||||
|
||||
/* found a tree */
|
||||
_industry_sound_ctr = 1;
|
||||
_industry_sound_tile = tile;
|
||||
if (_settings_client.sound.ambient) SndPlayTileFx(SND_38_LUMBER_MILL_1, tile);
|
||||
|
||||
AutoRestoreBackup<CompanyID> cur_company(_current_company, OWNER_NONE);
|
||||
Command<CMD_LANDSCAPE_CLEAR>::Do(DoCommandFlag::Execute, tile);
|
||||
|
||||
/* Add according value to waiting cargo. */
|
||||
itp->waiting = ClampTo<uint16_t>(itp->waiting + ScaleByCargoScale(45, false));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1241,8 +1223,8 @@ static void ProduceIndustryGoods(Industry *i)
|
||||
if (cut) ChopLumberMillTrees(i);
|
||||
}
|
||||
|
||||
TriggerIndustry(i, INDUSTRY_TRIGGER_INDUSTRY_TICK);
|
||||
StartStopIndustryTileAnimation(i, IAT_INDUSTRY_TICK);
|
||||
TriggerIndustryRandomisation(i, IndustryRandomTrigger::IndustryTick);
|
||||
TriggerIndustryAnimation(i, IndustryAnimationTrigger::IndustryTick);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1263,6 +1245,10 @@ void OnTick_Industry()
|
||||
|
||||
for (Industry *i : Industry::Iterate()) {
|
||||
ProduceIndustryGoods(i);
|
||||
|
||||
if ((TimerGameTick::counter + i->index) % Ticks::DAY_TICKS == 0) {
|
||||
for (auto &a : i->accepted) a.accumulated_waiting += a.waiting;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1779,7 +1765,7 @@ static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type,
|
||||
i->type = type;
|
||||
|
||||
auto &industries = Industry::industries[type];
|
||||
industries.emplace(std::ranges::lower_bound(industries, i->index), i->index);
|
||||
industries.insert(i->index);
|
||||
|
||||
for (size_t index = 0; index < std::size(indspec->produced_cargo); ++index) {
|
||||
if (!IsValidCargoType(indspec->produced_cargo[index])) break;
|
||||
@@ -1855,6 +1841,8 @@ static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type,
|
||||
for (auto &p : i->produced) {
|
||||
p.history[LAST_MONTH].production += ScaleByCargoScale(p.rate * 8, false);
|
||||
}
|
||||
|
||||
UpdateValidHistory(i->valid_history, HISTORY_YEAR, TimerGameEconomy::month);
|
||||
}
|
||||
|
||||
if (indspec->callback_mask.Test(IndustryCallbackMask::DecideColour)) {
|
||||
@@ -1961,7 +1949,16 @@ static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type,
|
||||
/* it->gfx is stored in the map. But the translated ID cur_gfx is the interesting one */
|
||||
IndustryGfx cur_gfx = GetTranslatedIndustryTileID(it.gfx);
|
||||
const IndustryTileSpec *its = GetIndustryTileSpec(cur_gfx);
|
||||
if (its->animation.status != ANIM_STATUS_NO_ANIMATION) AddAnimatedTile(cur_tile);
|
||||
if (its->animation.status != AnimationStatus::NoAnimation) AddAnimatedTile(cur_tile);
|
||||
}
|
||||
}
|
||||
|
||||
/* Call callbacks after all tiles have been created. */
|
||||
for (TileIndex cur_tile : i->location) {
|
||||
if (i->TileBelongsToIndustry(cur_tile)) {
|
||||
/* There are no shared random bits, consistent with "MakeIndustryTileBigger" in tile loop.
|
||||
* So, trigger tiles individually */
|
||||
TriggerIndustryTileAnimation_ConstructionStageChanged(cur_tile, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2538,22 +2535,48 @@ void GenerateIndustries()
|
||||
_industry_builder.Reset();
|
||||
}
|
||||
|
||||
template <>
|
||||
Industry::ProducedHistory SumHistory(std::span<const Industry::ProducedHistory> history)
|
||||
{
|
||||
uint32_t production = std::accumulate(std::begin(history), std::end(history), 0, [](uint32_t r, const auto &p) { return r + p.production; });
|
||||
uint32_t transported = std::accumulate(std::begin(history), std::end(history), 0, [](uint32_t r, const auto &p) { return r + p.transported; });
|
||||
auto count = std::size(history);
|
||||
return {.production = ClampTo<uint16_t>(production / count), .transported = ClampTo<uint16_t>(transported / count)};
|
||||
}
|
||||
|
||||
template <>
|
||||
Industry::AcceptedHistory SumHistory(std::span<const Industry::AcceptedHistory> history)
|
||||
{
|
||||
uint32_t accepted = std::accumulate(std::begin(history), std::end(history), 0, [](uint32_t r, const auto &a) { return r + a.accepted; });
|
||||
uint32_t waiting = std::accumulate(std::begin(history), std::end(history), 0, [](uint32_t r, const auto &a) { return r + a.waiting; });;
|
||||
auto count = std::size(history);
|
||||
return {.accepted = ClampTo<uint16_t>(accepted / count), .waiting = ClampTo<uint16_t>(waiting / count)};
|
||||
}
|
||||
|
||||
/**
|
||||
* Monthly update of industry statistics.
|
||||
* @param i Industry to update.
|
||||
*/
|
||||
static void UpdateIndustryStatistics(Industry *i)
|
||||
{
|
||||
auto month = TimerGameEconomy::month;
|
||||
UpdateValidHistory(i->valid_history, HISTORY_YEAR, month);
|
||||
|
||||
for (auto &p : i->produced) {
|
||||
if (IsValidCargoType(p.cargo)) {
|
||||
if (p.history[THIS_MONTH].production != 0) i->last_prod_year = TimerGameEconomy::year;
|
||||
|
||||
/* Move history from this month to last month. */
|
||||
std::rotate(std::rbegin(p.history), std::rbegin(p.history) + 1, std::rend(p.history));
|
||||
p.history[THIS_MONTH].production = 0;
|
||||
p.history[THIS_MONTH].transported = 0;
|
||||
RotateHistory(p.history, i->valid_history, HISTORY_YEAR, month);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &a : i->accepted) {
|
||||
if (!IsValidCargoType(a.cargo)) continue;
|
||||
if (a.history == nullptr) continue;
|
||||
|
||||
(*a.history)[THIS_MONTH].waiting = GetAndResetAccumulatedAverage<uint16_t>(a.accumulated_waiting);
|
||||
RotateHistory(*a.history, i->valid_history, HISTORY_YEAR, month);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2787,14 +2810,14 @@ int WhoCanServiceIndustry(Industry *ind)
|
||||
* We cannot check the first of shared orders only, since the first vehicle in such a chain
|
||||
* may have a different cargo type.
|
||||
*/
|
||||
for (const Order *o : v->Orders()) {
|
||||
if (o->IsType(OT_GOTO_STATION) && !(o->GetUnloadType() & OUFB_TRANSFER)) {
|
||||
for (const Order &o : v->Orders()) {
|
||||
if (o.IsType(OT_GOTO_STATION) && !(o.GetUnloadType() & OUFB_TRANSFER)) {
|
||||
/* Vehicle visits a station to load or unload */
|
||||
Station *st = Station::Get(o->GetDestination().ToStationID());
|
||||
Station *st = Station::Get(o.GetDestination().ToStationID());
|
||||
assert(st != nullptr);
|
||||
|
||||
/* Same cargo produced by industry is dropped here => not serviced by vehicle v */
|
||||
if ((o->GetUnloadType() & OUFB_UNLOAD) && !c_accepts) break;
|
||||
if ((o.GetUnloadType() & OUFB_UNLOAD) && !c_accepts) break;
|
||||
|
||||
if (ind->stations_near.find(st) != ind->stations_near.end()) {
|
||||
if (v->owner == _local_company) return 2; // Company services industry
|
||||
@@ -2856,11 +2879,12 @@ static void ChangeIndustryProduction(Industry *i, bool monthly)
|
||||
|
||||
bool callback_enabled = indspec->callback_mask.Test(monthly ? IndustryCallbackMask::MonthlyProdChange : IndustryCallbackMask::ProductionChange);
|
||||
if (callback_enabled) {
|
||||
uint16_t res = GetIndustryCallback(monthly ? CBID_INDUSTRY_MONTHLYPROD_CHANGE : CBID_INDUSTRY_PRODUCTION_CHANGE, 0, Random(), i, i->type, i->location.tile);
|
||||
std::array<int32_t, 1> regs100;
|
||||
uint16_t res = GetIndustryCallback(monthly ? CBID_INDUSTRY_MONTHLYPROD_CHANGE : CBID_INDUSTRY_PRODUCTION_CHANGE, 0, Random(), i, i->type, i->location.tile, regs100);
|
||||
if (res != CALLBACK_FAILED) { // failed callback means "do nothing"
|
||||
suppress_message = HasBit(res, 7);
|
||||
/* Get the custom message if any */
|
||||
if (HasBit(res, 8)) str = MapGRFStringID(indspec->grf_prop.grfid, GRFStringID(GB(GetRegister(0x100), 0, 16)));
|
||||
if (HasBit(res, 8)) str = MapGRFStringID(indspec->grf_prop.grfid, GRFStringID(GB(regs100[0], 0, 16)));
|
||||
res = GB(res, 0, 4);
|
||||
switch (res) {
|
||||
default: NOT_REACHED();
|
||||
@@ -2878,7 +2902,7 @@ static void ChangeIndustryProduction(Industry *i, bool monthly)
|
||||
increment = res == 0x0D ? -1 : 1;
|
||||
break;
|
||||
case 0xF: // Set production to third byte of register 0x100
|
||||
i->prod_level = Clamp(GB(GetRegister(0x100), 16, 8), PRODLEVEL_MINIMUM, PRODLEVEL_MAXIMUM);
|
||||
i->prod_level = Clamp(GB(regs100[0], 16, 8), PRODLEVEL_MINIMUM, PRODLEVEL_MAXIMUM);
|
||||
recalculate_multipliers = true;
|
||||
break;
|
||||
}
|
||||
@@ -3053,7 +3077,7 @@ static void ChangeIndustryProduction(Industry *i, bool monthly)
|
||||
* For small maps, it implies that less than one change per month is required, while on bigger maps,
|
||||
* it would be way more. The daily loop handles those changes.
|
||||
*/
|
||||
static IntervalTimer<TimerGameEconomy> _economy_industries_daily({TimerGameEconomy::DAY, TimerGameEconomy::Priority::INDUSTRY}, [](auto)
|
||||
static const IntervalTimer<TimerGameEconomy> _economy_industries_daily({TimerGameEconomy::DAY, TimerGameEconomy::Priority::INDUSTRY}, [](auto)
|
||||
{
|
||||
_economy.industry_daily_change_counter += _economy.industry_daily_increment;
|
||||
|
||||
@@ -3095,7 +3119,7 @@ static IntervalTimer<TimerGameEconomy> _economy_industries_daily({TimerGameEcono
|
||||
InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, IDIWD_PRODUCTION_CHANGE);
|
||||
});
|
||||
|
||||
static IntervalTimer<TimerGameEconomy> _economy_industries_monthly({TimerGameEconomy::MONTH, TimerGameEconomy::Priority::INDUSTRY}, [](auto)
|
||||
static const IntervalTimer<TimerGameEconomy> _economy_industries_monthly({TimerGameEconomy::MONTH, TimerGameEconomy::Priority::INDUSTRY}, [](auto)
|
||||
{
|
||||
Backup<CompanyID> cur_company(_current_company, OWNER_NONE);
|
||||
|
||||
@@ -3247,6 +3271,7 @@ extern const TileTypeProcs _tile_type_industry_procs = {
|
||||
nullptr, // vehicle_enter_tile_proc
|
||||
GetFoundation_Industry, // get_foundation_proc
|
||||
TerraformTile_Industry, // terraform_tile_proc
|
||||
nullptr, // check_build_above_proc
|
||||
};
|
||||
|
||||
bool IndustryCompare::operator() (const IndustryListEntry &lhs, const IndustryListEntry &rhs) const
|
||||
|
||||
Reference in New Issue
Block a user