Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change: Decouple town cargo production from cargo type. #11378

Merged
merged 5 commits into from
Feb 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/cargotype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "safeguards.h"

CargoSpec CargoSpec::array[NUM_CARGO];
std::array<std::vector<const CargoSpec *>, NUM_TPE> CargoSpec::town_production_cargoes{};

/**
* Bitmask of cargo types available. This includes phony cargoes like regearing cargoes.
Expand Down Expand Up @@ -192,6 +193,7 @@ static bool CargoSpecClassSorter(const CargoSpec * const &a, const CargoSpec * c
/** Initialize the list of sorted cargo specifications. */
void InitializeSortedCargoSpecs()
{
for (auto &tpc : CargoSpec::town_production_cargoes) tpc.clear();
_sorted_cargo_specs.clear();
/* Add each cargo spec to the list, and determine the largest cargo icon size. */
for (const CargoSpec *cargo : CargoSpec::Iterate()) {
Expand All @@ -210,6 +212,8 @@ void InitializeSortedCargoSpecs()
_standard_cargo_mask = 0;
uint8_t nb_standard_cargo = 0;
for (const auto &cargo : _sorted_cargo_specs) {
assert(cargo->town_production_effect != INVALID_TPE);
CargoSpec::town_production_cargoes[cargo->town_production_effect].push_back(cargo);
if (cargo->classes & CC_SPECIAL) break;
nb_standard_cargo++;
SetBit(_standard_cargo_mask, cargo->Index());
Expand Down
40 changes: 29 additions & 11 deletions src/cargotype.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,30 @@
typedef uint32_t CargoLabel;

/** Town growth effect when delivering cargo. */
enum TownEffect : byte {
TE_BEGIN = 0,
TE_NONE = TE_BEGIN, ///< Cargo has no effect.
TE_PASSENGERS, ///< Cargo behaves passenger-like.
TE_MAIL, ///< Cargo behaves mail-like.
TE_GOODS, ///< Cargo behaves goods/candy-like.
TE_WATER, ///< Cargo behaves water-like.
TE_FOOD, ///< Cargo behaves food/fizzy-drinks-like.
TE_END, ///< End of town effects.
NUM_TE = TE_END, ///< Amount of town effects.
enum TownAcceptanceEffect : byte {
TAE_BEGIN = 0,
TAE_NONE = TAE_BEGIN, ///< Cargo has no effect.
TAE_PASSENGERS, ///< Cargo behaves passenger-like.
TAE_MAIL, ///< Cargo behaves mail-like.
TAE_GOODS, ///< Cargo behaves goods/candy-like.
TAE_WATER, ///< Cargo behaves water-like.
TAE_FOOD, ///< Cargo behaves food/fizzy-drinks-like.
TAE_END, ///< End of town effects.
NUM_TAE = TAE_END, ///< Amount of town effects.
};

/** Town effect when producing cargo. */
enum TownProductionEffect : byte {
TPE_NONE, ///< Town will not produce this cargo type.
TPE_PASSENGERS, ///< Cargo behaves passenger-like for production.
TPE_MAIL, ///< Cargo behaves mail-like for production.
NUM_TPE,

/**
* Invalid town production effect. Used as a sentinel to indicate if a NewGRF has explicitly set an effect.
* This does not 'exist' after cargo types are finalised.
*/
INVALID_TPE,
};

/** Cargo classes. */
Expand Down Expand Up @@ -64,7 +78,8 @@ struct CargoSpec {
uint8_t transit_periods[2];

bool is_freight; ///< Cargo type is considered to be freight (affects train freight multiplier).
TownEffect town_effect; ///< The effect that delivering this cargo type has on towns. Also affects destination of subsidies.
TownAcceptanceEffect town_acceptance_effect; ///< The effect that delivering this cargo type has on towns. Also affects destination of subsidies.
TownProductionEffect town_production_effect{INVALID_TPE}; ///< The effect on town cargo production.
uint8_t callback_mask; ///< Bitmask of cargo callbacks that have to be called

StringID name; ///< Name of this type of cargo.
Expand Down Expand Up @@ -171,6 +186,9 @@ struct CargoSpec {
*/
static IterateWrapper Iterate(size_t from = 0) { return IterateWrapper(from); }

/** List of cargo specs for each Town Product Effect. */
static std::array<std::vector<const CargoSpec *>, NUM_TPE> town_production_cargoes;

private:
static CargoSpec array[NUM_CARGO]; ///< Array holding all CargoSpecs

Expand Down
2 changes: 1 addition & 1 deletion src/economy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1132,7 +1132,7 @@ static Money DeliverGoods(int num_pieces, CargoID cargo_type, StationID dest, ui

/* Increase town's counter for town effects */
const CargoSpec *cs = CargoSpec::Get(cargo_type);
st->town->received[cs->town_effect].new_act += accepted_total;
st->town->received[cs->town_acceptance_effect].new_act += accepted_total;

/* Determine profit */
Money profit = GetTransportedGoodsIncome(accepted_total, distance, periods_in_transit, cargo_type);
Expand Down
11 changes: 7 additions & 4 deletions src/industry_gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2428,10 +2428,11 @@ struct CargoesRow {
if (!IsValidCargoID(cargo_fld->u.cargo.supp_cargoes[i])) ind_fld->u.industry.other_produced[i] = others[--other_count];
}
} else {
/* Houses only display what is demanded. */
/* Houses only display cargo that towns produce. */
for (uint i = 0; i < cargo_fld->u.cargo.num_cargoes; i++) {
CargoID cid = cargo_fld->u.cargo.vertical_cargoes[i];
if (cid == CT_PASSENGERS || cid == CT_MAIL) cargo_fld->ConnectCargo(cid, true);
TownProductionEffect tpe = CargoSpec::Get(cid)->town_production_effect;
if (tpe == TPE_PASSENGERS || tpe == TPE_MAIL) cargo_fld->ConnectCargo(cid, true);
}
}
}
Expand Down Expand Up @@ -2683,8 +2684,10 @@ struct IndustryCargoesWindow : public Window {
static bool HousesCanSupply(const CargoID *cargoes, uint length)
{
for (uint i = 0; i < length; i++) {
if (!IsValidCargoID(cargoes[i])) continue;
if (cargoes[i] == CT_PASSENGERS || cargoes[i] == CT_MAIL) return true;
CargoID cid = cargoes[i];
if (!IsValidCargoID(cid)) continue;
TownProductionEffect tpe = CargoSpec::Get(cid)->town_production_effect;
if (tpe == TPE_PASSENGERS || tpe == TPE_MAIL) return true;
}
return false;
}
Expand Down
20 changes: 14 additions & 6 deletions src/newgrf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3066,15 +3066,15 @@ static ChangeInfoResult CargoChangeInfo(uint cid, int numinfo, int prop, ByteRea
uint8_t substitute_type = buf->ReadByte();

switch (substitute_type) {
case 0x00: cs->town_effect = TE_PASSENGERS; break;
case 0x02: cs->town_effect = TE_MAIL; break;
case 0x05: cs->town_effect = TE_GOODS; break;
case 0x09: cs->town_effect = TE_WATER; break;
case 0x0B: cs->town_effect = TE_FOOD; break;
case 0x00: cs->town_acceptance_effect = TAE_PASSENGERS; break;
case 0x02: cs->town_acceptance_effect = TAE_MAIL; break;
case 0x05: cs->town_acceptance_effect = TAE_GOODS; break;
case 0x09: cs->town_acceptance_effect = TAE_WATER; break;
case 0x0B: cs->town_acceptance_effect = TAE_FOOD; break;
default:
GrfMsg(1, "CargoChangeInfo: Unknown town growth substitute value {}, setting to none.", substitute_type);
FALLTHROUGH;
case 0xFF: cs->town_effect = TE_NONE; break;
case 0xFF: cs->town_acceptance_effect = TAE_NONE; break;
}
break;
}
Expand Down Expand Up @@ -9186,6 +9186,14 @@ static void FinaliseEngineArray()
void FinaliseCargoArray()
{
for (CargoSpec &cs : CargoSpec::array) {
if (cs.town_production_effect == INVALID_TPE) {
/* Set default town production effect by cargo label. */
switch (cs.label) {
case 'PASS': cs.town_production_effect = TPE_PASSENGERS; break;
case 'MAIL': cs.town_production_effect = TPE_MAIL; break;
default: cs.town_production_effect = TPE_NONE; break;
}
}
if (!cs.IsValid()) {
cs.name = cs.name_single = cs.units_volume = STR_NEWGRF_INVALID_CARGO;
cs.quantifier = STR_NEWGRF_INVALID_CARGO_QUANTITY;
Expand Down
16 changes: 8 additions & 8 deletions src/newgrf_town.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,14 @@
case 0xC9: return GB(ClampTo<uint16_t>(this->t->supplied[CT_MAIL].old_act), 8, 8);
case 0xCA: return this->t->GetPercentTransported(CT_PASSENGERS);
case 0xCB: return this->t->GetPercentTransported(CT_MAIL);
case 0xCC: return this->t->received[TE_FOOD].new_act;
case 0xCD: return GB(this->t->received[TE_FOOD].new_act, 8, 8);
case 0xCE: return this->t->received[TE_WATER].new_act;
case 0xCF: return GB(this->t->received[TE_WATER].new_act, 8, 8);
case 0xD0: return this->t->received[TE_FOOD].old_act;
case 0xD1: return GB(this->t->received[TE_FOOD].old_act, 8, 8);
case 0xD2: return this->t->received[TE_WATER].old_act;
case 0xD3: return GB(this->t->received[TE_WATER].old_act, 8, 8);
case 0xCC: return this->t->received[TAE_FOOD].new_act;
case 0xCD: return GB(this->t->received[TAE_FOOD].new_act, 8, 8);
case 0xCE: return this->t->received[TAE_WATER].new_act;
case 0xCF: return GB(this->t->received[TAE_WATER].new_act, 8, 8);
case 0xD0: return this->t->received[TAE_FOOD].old_act;
case 0xD1: return GB(this->t->received[TAE_FOOD].old_act, 8, 8);
case 0xD2: return this->t->received[TAE_WATER].old_act;
case 0xD3: return GB(this->t->received[TAE_WATER].old_act, 8, 8);
case 0xD4: return this->t->road_build_months;
case 0xD5: return this->t->fund_buildings_months;
}
Expand Down
22 changes: 11 additions & 11 deletions src/saveload/afterload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2225,15 +2225,15 @@ bool AfterLoadGame()
s->remaining = 12 - s->remaining; // convert "age" to "remaining"
s->awarded = INVALID_COMPANY; // not awarded to anyone
const CargoSpec *cs = CargoSpec::Get(s->cargo_type);
switch (cs->town_effect) {
case TE_PASSENGERS:
case TE_MAIL:
switch (cs->town_acceptance_effect) {
case TAE_PASSENGERS:
case TAE_MAIL:
/* Town -> Town */
s->src_type = s->dst_type = SourceType::Town;
if (Town::IsValidID(s->src) && Town::IsValidID(s->dst)) continue;
break;
case TE_GOODS:
case TE_FOOD:
case TAE_GOODS:
case TAE_FOOD:
/* Industry -> Town */
s->src_type = SourceType::Industry;
s->dst_type = SourceType::Town;
Expand All @@ -2251,9 +2251,9 @@ bool AfterLoadGame()
* Town -> Town subsidies are converted using simple heuristic */
s->remaining = 24 - s->remaining; // convert "age of awarded subsidy" to "remaining"
const CargoSpec *cs = CargoSpec::Get(s->cargo_type);
switch (cs->town_effect) {
case TE_PASSENGERS:
case TE_MAIL: {
switch (cs->town_acceptance_effect) {
case TAE_PASSENGERS:
case TAE_MAIL: {
/* Town -> Town */
const Station *ss = Station::GetIfValid(s->src);
const Station *sd = Station::GetIfValid(s->dst);
Expand Down Expand Up @@ -2813,12 +2813,12 @@ bool AfterLoadGame()
/* Set the default cargo requirement for town growth */
switch (_settings_game.game_creation.landscape) {
case LT_ARCTIC:
if (FindFirstCargoWithTownEffect(TE_FOOD) != nullptr) t->goal[TE_FOOD] = TOWN_GROWTH_WINTER;
if (FindFirstCargoWithTownAcceptanceEffect(TAE_FOOD) != nullptr) t->goal[TAE_FOOD] = TOWN_GROWTH_WINTER;
break;

case LT_TROPIC:
if (FindFirstCargoWithTownEffect(TE_FOOD) != nullptr) t->goal[TE_FOOD] = TOWN_GROWTH_DESERT;
if (FindFirstCargoWithTownEffect(TE_WATER) != nullptr) t->goal[TE_WATER] = TOWN_GROWTH_DESERT;
if (FindFirstCargoWithTownAcceptanceEffect(TAE_FOOD) != nullptr) t->goal[TAE_FOOD] = TOWN_GROWTH_DESERT;
if (FindFirstCargoWithTownAcceptanceEffect(TAE_WATER) != nullptr) t->goal[TAE_WATER] = TOWN_GROWTH_DESERT;
break;
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/saveload/oldloader_sl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -601,10 +601,10 @@ static const OldChunks town_chunk[] = {

OCL_NULL( 2 ), ///< pct_pass_transported / pct_mail_transported, now computed on the fly

OCL_SVAR( OC_TTD | OC_UINT16, Town, received[TE_FOOD].new_act ),
OCL_SVAR( OC_TTD | OC_UINT16, Town, received[TE_WATER].new_act ),
OCL_SVAR( OC_TTD | OC_UINT16, Town, received[TE_FOOD].old_act ),
OCL_SVAR( OC_TTD | OC_UINT16, Town, received[TE_WATER].old_act ),
OCL_SVAR( OC_TTD | OC_UINT16, Town, received[TAE_FOOD].new_act ),
OCL_SVAR( OC_TTD | OC_UINT16, Town, received[TAE_WATER].new_act ),
OCL_SVAR( OC_TTD | OC_UINT16, Town, received[TAE_FOOD].old_act ),
OCL_SVAR( OC_TTD | OC_UINT16, Town, received[TAE_WATER].old_act ),

OCL_SVAR( OC_UINT8, Town, road_build_months ),
OCL_SVAR( OC_UINT8, Town, fund_buildings_months ),
Expand Down
12 changes: 6 additions & 6 deletions src/saveload/town_sl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ class SlTownReceived : public DefaultSaveLoadHandler<SlTownReceived, Town> {

void Load(Town *t) const override
{
size_t length = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? (size_t)TE_END : SlGetStructListLength(TE_END);
size_t length = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? (size_t)TAE_END : SlGetStructListLength(TAE_END);
for (size_t i = 0; i < length; i++) {
SlObject(&t->received[i], this->GetLoadDescription());
}
Expand Down Expand Up @@ -239,12 +239,12 @@ static const SaveLoad _town_desc[] = {
SLE_CONDVAR(Town, supplied[CT_MAIL].new_act, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
SLE_CONDVAR(Town, supplied[CT_MAIL].new_act, SLE_UINT32, SLV_9, SLV_165),

SLE_CONDVAR(Town, received[TE_FOOD].old_act, SLE_UINT16, SL_MIN_VERSION, SLV_165),
SLE_CONDVAR(Town, received[TE_WATER].old_act, SLE_UINT16, SL_MIN_VERSION, SLV_165),
SLE_CONDVAR(Town, received[TE_FOOD].new_act, SLE_UINT16, SL_MIN_VERSION, SLV_165),
SLE_CONDVAR(Town, received[TE_WATER].new_act, SLE_UINT16, SL_MIN_VERSION, SLV_165),
SLE_CONDVARNAME(Town, received[TAE_FOOD].old_act, "received[TE_FOOD].old_act", SLE_UINT16, SL_MIN_VERSION, SLV_165),
SLE_CONDVARNAME(Town, received[TAE_WATER].old_act, "received[TE_WATER].old_act", SLE_UINT16, SL_MIN_VERSION, SLV_165),
SLE_CONDVARNAME(Town, received[TAE_FOOD].new_act, "received[TE_FOOD].new_act", SLE_UINT16, SL_MIN_VERSION, SLV_165),
SLE_CONDVARNAME(Town, received[TAE_WATER].new_act, "received[TE_WATER].new_act", SLE_UINT16, SL_MIN_VERSION, SLV_165),

SLE_CONDARR(Town, goal, SLE_UINT32, NUM_TE, SLV_165, SL_MAX_VERSION),
SLE_CONDARR(Town, goal, SLE_UINT32, NUM_TAE, SLV_165, SL_MAX_VERSION),

SLE_CONDSSTR(Town, text, SLE_STR | SLF_ALLOW_CONTROL, SLV_168, SL_MAX_VERSION),

Expand Down
4 changes: 2 additions & 2 deletions src/script/api/script_cargo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

/* static */ bool ScriptCargo::IsValidTownEffect(TownEffect towneffect_type)
{
return (towneffect_type >= (TownEffect)TE_BEGIN && towneffect_type < (TownEffect)TE_END);
return (towneffect_type >= (TownEffect)TAE_BEGIN && towneffect_type < (TownEffect)TAE_END);
}

/* static */ std::optional<std::string> ScriptCargo::GetName(CargoID cargo_type)
Expand Down Expand Up @@ -67,7 +67,7 @@
{
if (!IsValidCargo(cargo_type)) return TE_NONE;

return (ScriptCargo::TownEffect)::CargoSpec::Get(cargo_type)->town_effect;
return (ScriptCargo::TownEffect)::CargoSpec::Get(cargo_type)->town_acceptance_effect;
}

/* static */ Money ScriptCargo::GetCargoIncome(CargoID cargo_type, SQInteger distance, SQInteger days_in_transit)
Expand Down
12 changes: 6 additions & 6 deletions src/script/api/script_cargo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ class ScriptCargo : public ScriptObject {
*/
enum TownEffect {
/* Note: these values represent part of the in-game TownEffect enum */
TE_NONE = ::TE_NONE, ///< This cargo has no effect on a town
TE_PASSENGERS = ::TE_PASSENGERS, ///< This cargo supplies passengers to a town
TE_MAIL = ::TE_MAIL, ///< This cargo supplies mail to a town
TE_GOODS = ::TE_GOODS, ///< This cargo supplies goods to a town
TE_WATER = ::TE_WATER, ///< This cargo supplies water to a town
TE_FOOD = ::TE_FOOD, ///< This cargo supplies food to a town
TE_NONE = ::TAE_NONE, ///< This cargo has no effect on a town
TE_PASSENGERS = ::TAE_PASSENGERS, ///< This cargo supplies passengers to a town
TE_MAIL = ::TAE_MAIL, ///< This cargo supplies mail to a town
TE_GOODS = ::TAE_GOODS, ///< This cargo supplies goods to a town
TE_WATER = ::TAE_WATER, ///< This cargo supplies water to a town
TE_FOOD = ::TAE_FOOD, ///< This cargo supplies food to a town
};

/**
Expand Down
2 changes: 1 addition & 1 deletion src/script/api/script_town.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@

goal = Clamp<SQInteger>(goal, 0, UINT32_MAX);

return ScriptObject::Command<CMD_TOWN_CARGO_GOAL>::Do(town_id, (::TownEffect)towneffect_id, goal);
return ScriptObject::Command<CMD_TOWN_CARGO_GOAL>::Do(town_id, (::TownAcceptanceEffect)towneffect_id, goal);
}

/* static */ SQInteger ScriptTown::GetCargoGoal(TownID town_id, ScriptCargo::TownEffect towneffect_id)
Expand Down
2 changes: 1 addition & 1 deletion src/script/api/script_townlist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ ScriptTownList::ScriptTownList(HSQUIRRELVM vm)

ScriptTownEffectList::ScriptTownEffectList()
{
for (int i = TE_BEGIN; i < TE_END; i++) {
for (int i = TAE_BEGIN; i < TAE_END; i++) {
this->AddItem(i);
}
}
14 changes: 10 additions & 4 deletions src/subsidy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,9 +286,13 @@ bool FindSubsidyPassengerRoute()
{
if (!Subsidy::CanAllocateItem()) return false;

/* Pick a random TPE_PASSENGER type */
uint32_t r = RandomRange(static_cast<uint>(CargoSpec::town_production_cargoes[TPE_PASSENGERS].size()));
CargoID cid = CargoSpec::town_production_cargoes[TPE_PASSENGERS][r]->Index();

const Town *src = Town::GetRandom();
if (src->cache.population < SUBSIDY_PAX_MIN_POPULATION ||
src->GetPercentTransported(CT_PASSENGERS) > SUBSIDY_MAX_PCT_TRANSPORTED) {
src->GetPercentTransported(cid) > SUBSIDY_MAX_PCT_TRANSPORTED) {
return false;
}

Expand All @@ -298,9 +302,9 @@ bool FindSubsidyPassengerRoute()
}

if (DistanceManhattan(src->xy, dst->xy) > SUBSIDY_MAX_DISTANCE) return false;
if (CheckSubsidyDuplicate(CT_PASSENGERS, SourceType::Town, src->index, SourceType::Town, dst->index)) return false;
if (CheckSubsidyDuplicate(cid, SourceType::Town, src->index, SourceType::Town, dst->index)) return false;

CreateSubsidy(CT_PASSENGERS, SourceType::Town, src->index, SourceType::Town, dst->index);
CreateSubsidy(cid, SourceType::Town, src->index, SourceType::Town, dst->index);

return true;
}
Expand Down Expand Up @@ -332,7 +336,9 @@ bool FindSubsidyTownCargoRoute()
}

/* Passenger subsidies are not handled here. */
town_cargo_produced[CT_PASSENGERS] = 0;
for (const CargoSpec *cs : CargoSpec::town_production_cargoes[TPE_PASSENGERS]) {
town_cargo_produced[cs->Index()] = 0;
}

uint8_t cargo_count = town_cargo_produced.GetCount();

Expand Down