1
0
Fork 0

Codechange: change Source into a class with conversion helpers

A Source is either a CompanyID (Headquarters), IndustryID or TownID.
When making those types stronger a lot of casts would be needed, but
with these simple helpers the intent is shown more clearly.
pull/13511/head
Rubidium 2025-02-08 15:02:13 +01:00 committed by rubidium42
parent 2929411130
commit 155d7de132
14 changed files with 87 additions and 54 deletions

View File

@ -427,6 +427,7 @@ add_files(
soundloader_type.h
soundloader_raw.cpp
soundloader_wav.cpp
source_type.h
sprite.cpp
sprite.h
spritecache.cpp

View File

@ -130,23 +130,4 @@ struct CargoArray : std::array<uint, NUM_CARGO> {
}
};
/** Types of cargo source and destination */
enum class SourceType : uint8_t {
Industry, ///< Source/destination is an industry
Town, ///< Source/destination is a town
Headquarters, ///< Source/destination are company headquarters
};
typedef uint16_t SourceID; ///< Contains either industry ID, town ID or company ID (or INVALID_SOURCE)
static const SourceID INVALID_SOURCE = 0xFFFF; ///< Invalid/unknown index of source
/** A location from where cargo can come from (or go to). Specifically industries, towns and headquarters. */
struct Source {
SourceID id; ///< Index of industry/town/HQ, INVALID_SOURCE if unknown/invalid.
SourceType type; ///< Type of \c source_id.
auto operator<=>(const Source &source) const = default;
};
#endif /* CARGO_TYPE_H */

View File

@ -118,17 +118,17 @@ void AddCargoDelivery(CargoType cargo_type, CompanyID company, uint32_t amount,
{
if (amount == 0) return;
if (src.id != INVALID_SOURCE) {
if (src.IsValid()) {
/* Handle pickup update. */
switch (src.type) {
case SourceType::Industry: {
CargoMonitorID num = EncodeCargoIndustryMonitor(company, cargo_type, src.id);
CargoMonitorID num = EncodeCargoIndustryMonitor(company, cargo_type, src.ToIndustryID());
CargoMonitorMap::iterator iter = _cargo_pickups.find(num);
if (iter != _cargo_pickups.end()) iter->second += amount;
break;
}
case SourceType::Town: {
CargoMonitorID num = EncodeCargoTownMonitor(company, cargo_type, src.id);
CargoMonitorID num = EncodeCargoTownMonitor(company, cargo_type, src.ToTownID());
CargoMonitorMap::iterator iter = _cargo_pickups.find(num);
if (iter != _cargo_pickups.end()) iter->second += amount;
break;

View File

@ -132,7 +132,7 @@ void CargoPacket::Reduce(uint count)
/* static */ void CargoPacket::InvalidateAllFrom(Source src)
{
for (CargoPacket *cp : CargoPacket::Iterate()) {
if (cp->source == src) cp->source.id = INVALID_SOURCE;
if (cp->source == src) cp->source.MakeInvalid();
}
}

View File

@ -15,6 +15,7 @@
#include "station_type.h"
#include "order_type.h"
#include "cargo_type.h"
#include "source_type.h"
#include "vehicle_type.h"
#include "core/multimap.hpp"
#include "saveload/saveload.h"
@ -53,7 +54,7 @@ private:
TileIndex source_xy = INVALID_TILE; ///< The origin of the cargo.
Vector travelled{0, 0}; ///< If cargo is in station: the vector from the unload tile to the source tile. If in vehicle: an intermediate value.
Source source{INVALID_SOURCE, SourceType::Industry}; ///< Source of the cargo
Source source{Source::Invalid, SourceType::Industry}; ///< Source of the cargo
#ifdef WITH_ASSERT
bool in_vehicle = false; ///< NOSAVE: Whether this cargo is in a vehicle or not.
@ -504,9 +505,8 @@ public:
{
return cp1->source_xy == cp2->source_xy &&
cp1->periods_in_transit == cp2->periods_in_transit &&
cp1->source.type == cp2->source.type &&
cp1->first_station == cp2->first_station &&
cp1->source.id == cp2->source.id;
cp1->source == cp2->source;
}
};

View File

@ -1114,7 +1114,7 @@ static Money DeliverGoods(int num_pieces, CargoType cargo_type, StationID dest,
Station *st = Station::Get(dest);
/* Give the goods to the industry. */
uint accepted_ind = DeliverGoodsToIndustry(st, cargo_type, num_pieces, src.type == SourceType::Industry ? src.id : INVALID_INDUSTRY, company->index);
uint accepted_ind = DeliverGoodsToIndustry(st, cargo_type, num_pieces, src.type == SourceType::Industry ? src.ToIndustryID() : INVALID_INDUSTRY, company->index);
/* If this cargo type is always accepted, accept all */
uint accepted_total = HasBit(st->always_accepted, cargo_type) ? num_pieces : accepted_ind;

View File

@ -16,6 +16,7 @@
#include "vehicle_type.h"
#include "company_type.h"
#include "settings_type.h"
#include "source_type.h"
#include "core/random_func.hpp"
void ResetPriceBaseMultipliers();

View File

@ -2280,19 +2280,19 @@ bool AfterLoadGame()
case TAE_MAIL:
/* Town -> Town */
s->src.type = s->dst.type = SourceType::Town;
if (Town::IsValidID(s->src.id) && Town::IsValidID(s->dst.id)) continue;
if (Town::IsValidID(s->src.ToTownID()) && Town::IsValidID(s->dst.ToTownID())) continue;
break;
case TAE_GOODS:
case TAE_FOOD:
/* Industry -> Town */
s->src.type = SourceType::Industry;
s->dst.type = SourceType::Town;
if (Industry::IsValidID(s->src.id) && Town::IsValidID(s->dst.id)) continue;
if (Industry::IsValidID(s->src.ToIndustryID()) && Town::IsValidID(s->dst.ToTownID())) continue;
break;
default:
/* Industry -> Industry */
s->src.type = s->dst.type = SourceType::Industry;
if (Industry::IsValidID(s->src.id) && Industry::IsValidID(s->dst.id)) continue;
if (Industry::IsValidID(s->src.ToIndustryID()) && Industry::IsValidID(s->dst.ToIndustryID())) continue;
break;
}
} else {
@ -2310,8 +2310,8 @@ bool AfterLoadGame()
if (ss != nullptr && sd != nullptr && ss->owner == sd->owner &&
Company::IsValidID(ss->owner)) {
s->src.type = s->dst.type = SourceType::Town;
s->src.id = ss->town->index;
s->dst.id = sd->town->index;
s->src.SetIndex(ss->town->index);
s->dst.SetIndex(sd->town->index);
s->awarded = ss->owner;
continue;
}

View File

@ -82,7 +82,7 @@
/* static */ SQInteger ScriptSubsidy::GetSourceIndex(SubsidyID subsidy_id)
{
if (!IsValidSubsidy(subsidy_id)) return INVALID_SOURCE;
if (!IsValidSubsidy(subsidy_id)) return Source::Invalid;
return ::Subsidy::Get(subsidy_id)->src.id;
}
@ -96,7 +96,7 @@
/* static */ SQInteger ScriptSubsidy::GetDestinationIndex(SubsidyID subsidy_id)
{
if (!IsValidSubsidy(subsidy_id)) return INVALID_SOURCE;
if (!IsValidSubsidy(subsidy_id)) return Source::Invalid;
return ::Subsidy::Get(subsidy_id)->dst.id;
}

48
src/source_type.h 100644
View File

@ -0,0 +1,48 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file source_type.h Type for the source of cargo. */
#ifndef SOURCE_TYPE_H
#define SOURCE_TYPE_H
#include "company_type.h"
#include "industry_type.h"
#include "town_type.h"
/** Types of cargo source and destination */
enum class SourceType : uint8_t {
Industry = 0, ///< Source/destination is an industry
Town = 1, ///< Source/destination is a town
Headquarters = 2, ///< Source/destination are company headquarters
};
using SourceID = uint16_t; ///< Contains either industry ID, town ID or company ID (or Source::Invalid)
static_assert(sizeof(SourceID) >= sizeof(CompanyID));
static_assert(sizeof(SourceID) >= sizeof(IndustryID));
static_assert(sizeof(SourceID) >= sizeof(TownID));
/** A location from where cargo can come from (or go to). Specifically industries, towns and headquarters. */
struct Source {
public:
static constexpr SourceID Invalid = 0xFFFF; ///< Invalid/unknown index of source
SourceID id; ///< Index of industry/town/HQ, Source::Invalid if unknown/invalid.
SourceType type; ///< Type of \c source_id.
constexpr CompanyID ToCompanyID() const { assert(this->type == SourceType::Headquarters); return static_cast<CompanyID>(this->id); }
constexpr IndustryID ToIndustryID() const { assert(this->type == SourceType::Industry); return static_cast<IndustryID>(this->id); }
constexpr TownID ToTownID() const { assert(this->type == SourceType::Town); return static_cast<TownID>(this->id); }
constexpr void MakeInvalid() { this->id = Source::Invalid; }
constexpr void SetIndex(SourceID index) { this->id = index; }
constexpr bool IsValid() const noexcept { return this->id != Source::Invalid; }
auto operator<=>(const Source &source) const = default;
};
#endif /* SOURCE_TYPE_H */

View File

@ -123,8 +123,8 @@ std::pair<NewsReferenceType, NewsReferenceType> SetupSubsidyDecodeParam(const Su
static inline void SetPartOfSubsidyFlag(Source source, PartOfSubsidy flag)
{
switch (source.type) {
case SourceType::Industry: Industry::Get(source.id)->part_of_subsidy |= flag; return;
case SourceType::Town: Town::Get(source.id)->cache.part_of_subsidy |= flag; return;
case SourceType::Industry: Industry::Get(source.ToIndustryID())->part_of_subsidy |= flag; return;
case SourceType::Town: Town::Get(source.ToTownID())->cache.part_of_subsidy |= flag; return;
default: NOT_REACHED();
}
}
@ -188,8 +188,8 @@ static bool CheckSubsidyDuplicate(CargoType cargo, Source src, Source dst)
*/
static bool CheckSubsidyDistance(Source src, Source dst)
{
TileIndex tile_src = (src.type == SourceType::Town) ? Town::Get(src.id)->xy : Industry::Get(src.id)->location.tile;
TileIndex tile_dst = (dst.type == SourceType::Town) ? Town::Get(dst.id)->xy : Industry::Get(dst.id)->location.tile;
TileIndex tile_src = (src.type == SourceType::Town) ? Town::Get(src.ToTownID())->xy : Industry::Get(src.ToIndustryID())->location.tile;
TileIndex tile_dst = (dst.type == SourceType::Town) ? Town::Get(dst.ToTownID())->xy : Industry::Get(dst.ToIndustryID())->location.tile;
return (DistanceManhattan(tile_src, tile_dst) <= SUBSIDY_MAX_DISTANCE);
}
@ -237,20 +237,20 @@ CommandCost CmdCreateSubsidy(DoCommandFlag flags, CargoType cargo_type, Source s
switch (src.type) {
case SourceType::Town:
if (!Town::IsValidID(src.id)) return CMD_ERROR;
if (!Town::IsValidID(src.ToTownID())) return CMD_ERROR;
break;
case SourceType::Industry:
if (!Industry::IsValidID(src.id)) return CMD_ERROR;
if (!Industry::IsValidID(src.ToIndustryID())) return CMD_ERROR;
break;
default:
return CMD_ERROR;
}
switch (dst.type) {
case SourceType::Town:
if (!Town::IsValidID(dst.id)) return CMD_ERROR;
if (!Town::IsValidID(dst.ToTownID())) return CMD_ERROR;
break;
case SourceType::Industry:
if (!Industry::IsValidID(dst.id)) return CMD_ERROR;
if (!Industry::IsValidID(dst.ToIndustryID())) return CMD_ERROR;
break;
default:
return CMD_ERROR;
@ -403,7 +403,7 @@ bool FindSubsidyIndustryCargoRoute()
bool FindSubsidyCargoDestination(CargoType cargo_type, Source src)
{
/* Choose a random destination. */
Source dst{INVALID_SOURCE, Chance16(1, 2) ? SourceType::Town : SourceType::Industry};
Source dst{Source::Invalid, Chance16(1, 2) ? SourceType::Town : SourceType::Industry};
switch (dst.type) {
case SourceType::Town: {
@ -422,7 +422,7 @@ bool FindSubsidyCargoDestination(CargoType cargo_type, Source src)
/* Check if the town can accept this cargo. */
if (town_cargo_accepted[cargo_type] < 8) return false;
dst.id = dst_town->index;
dst.SetIndex(dst_town->index);
break;
}
@ -434,7 +434,7 @@ bool FindSubsidyCargoDestination(CargoType cargo_type, Source src)
/* The industry must accept the cargo */
if (!dst_ind->IsCargoAccepted(cargo_type)) return false;
dst.id = dst_ind->index;
dst.SetIndex(dst_ind->index);
break;
}
@ -539,13 +539,13 @@ static IntervalTimer<TimerGameEconomy> _economy_subsidies_monthly({TimerGameEcon
bool CheckSubsidised(CargoType cargo_type, CompanyID company, Source src, const Station *st)
{
/* If the source isn't subsidised, don't continue */
if (src.id == INVALID_SOURCE) return false;
if (!src.IsValid()) return false;
switch (src.type) {
case SourceType::Industry:
if (!(Industry::Get(src.id)->part_of_subsidy & POS_SRC)) return false;
if (!(Industry::Get(src.ToIndustryID())->part_of_subsidy & POS_SRC)) return false;
break;
case SourceType::Town:
if (!(Town::Get(src.id)->cache.part_of_subsidy & POS_SRC)) return false;
if (!(Town::Get(src.ToTownID())->cache.part_of_subsidy & POS_SRC)) return false;
break;
default: return false;
}
@ -579,7 +579,7 @@ bool CheckSubsidised(CargoType cargo_type, CompanyID company, Source src, const
switch (s->dst.type) {
case SourceType::Industry:
for (const auto &i : st->industries_near) {
if (s->dst.id == i.industry->index) {
if (s->dst.ToIndustryID() == i.industry->index) {
assert(i.industry->part_of_subsidy & POS_DST);
subsidised = true;
if (!s->IsAwarded()) s->AwardTo(company);
@ -588,7 +588,7 @@ bool CheckSubsidised(CargoType cargo_type, CompanyID company, Source src, const
break;
case SourceType::Town:
for (const Town *tp : towns_near) {
if (s->dst.id == tp->index) {
if (s->dst.ToTownID() == tp->index) {
assert(tp->cache.part_of_subsidy & POS_DST);
subsidised = true;
if (!s->IsAwarded()) s->AwardTo(company);

View File

@ -12,6 +12,7 @@
#include "cargo_type.h"
#include "company_type.h"
#include "source_type.h"
#include "subsidy_type.h"
#include "core/pool_type.hpp"

View File

@ -12,6 +12,7 @@
#include "command_type.h"
#include "cargo_type.h"
#include "source_type.h"
#include "misc/endian_buffer.hpp"
CommandCost CmdCreateSubsidy(DoCommandFlag flags, CargoType cargo_type, Source src, Source dst);

View File

@ -83,8 +83,8 @@ struct SubsidyListWindow : Window {
/* determine src coordinate for subsidy and try to scroll to it */
TileIndex xy;
switch (s->src.type) {
case SourceType::Industry: xy = Industry::Get(s->src.id)->location.tile; break;
case SourceType::Town: xy = Town::Get(s->src.id)->xy; break;
case SourceType::Industry: xy = Industry::Get(s->src.ToIndustryID())->location.tile; break;
case SourceType::Town: xy = Town::Get(s->src.ToTownID())->xy; break;
default: NOT_REACHED();
}
@ -93,8 +93,8 @@ struct SubsidyListWindow : Window {
/* otherwise determine dst coordinate for subsidy and scroll to it */
switch (s->dst.type) {
case SourceType::Industry: xy = Industry::Get(s->dst.id)->location.tile; break;
case SourceType::Town: xy = Town::Get(s->dst.id)->xy; break;
case SourceType::Industry: xy = Industry::Get(s->dst.ToIndustryID())->location.tile; break;
case SourceType::Town: xy = Town::Get(s->dst.ToTownID())->xy; break;
default: NOT_REACHED();
}