diff --git a/src/ai/api/ai_subsidylist.cpp b/src/ai/api/ai_subsidylist.cpp --- a/src/ai/api/ai_subsidylist.cpp +++ b/src/ai/api/ai_subsidylist.cpp @@ -10,6 +10,6 @@ AISubsidyList::AISubsidyList() { const Subsidy *s; FOR_ALL_SUBSIDIES(s) { - this->AddItem(s->Index()); + this->AddItem(s->index); } } diff --git a/src/economy.cpp b/src/economy.cpp --- a/src/economy.cpp +++ b/src/economy.cpp @@ -332,12 +332,13 @@ void ChangeOwnershipOfCompanyItems(Owner FOR_ALL_SUBSIDIES(s) { if (s->awarded == old_owner) { if (new_owner == INVALID_OWNER) { - DeleteSubsidy(s); + delete s; } else { s->awarded = new_owner; } } } + if (new_owner == INVALID_OWNER) RebuildSubsidisedSourceAndDestinationCache(); /* Take care of rating in towns */ FOR_ALL_TOWNS(t) { diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -1902,7 +1902,7 @@ bool AfterLoadGame() } } /* Awarded subsidy or invalid source/destination, invalidate */ - s->cargo_type = CT_INVALID; + delete s; } } diff --git a/src/saveload/oldloader_sl.cpp b/src/saveload/oldloader_sl.cpp --- a/src/saveload/oldloader_sl.cpp +++ b/src/saveload/oldloader_sl.cpp @@ -1477,7 +1477,10 @@ static const OldChunks subsidy_chunk[] = static bool LoadOldSubsidy(LoadgameState *ls, int num) { - return LoadChunk(ls, &Subsidy::array[num], subsidy_chunk); + Subsidy *s = new (num) Subsidy(); + bool ret = LoadChunk(ls, s, subsidy_chunk); + if (s->cargo_type == CT_INVALID) delete s; + return ret; } static const OldChunks game_difficulty_chunk[] = { diff --git a/src/saveload/subsidy_sl.cpp b/src/saveload/subsidy_sl.cpp --- a/src/saveload/subsidy_sl.cpp +++ b/src/saveload/subsidy_sl.cpp @@ -24,7 +24,7 @@ void Save_SUBS() { Subsidy *s; FOR_ALL_SUBSIDIES(s) { - SlSetArrayIndex(s->Index()); + SlSetArrayIndex(s->index); SlObject(s, _subsidies_desc); } } @@ -33,7 +33,8 @@ void Load_SUBS() { int index; while ((index = SlIterateArray()) != -1) { - SlObject(&Subsidy::array[index], _subsidies_desc); + Subsidy *s = new (index) Subsidy(); + SlObject(s, _subsidies_desc); } } diff --git a/src/subsidy.cpp b/src/subsidy.cpp --- a/src/subsidy.cpp +++ b/src/subsidy.cpp @@ -15,10 +15,12 @@ #include "window_func.h" #include "subsidy_base.h" #include "subsidy_func.h" +#include "core/pool_func.hpp" #include "table/strings.h" -/* static */ Subsidy Subsidy::array[MAX_COMPANIES]; +SubsidyPool _subsidy_pool("Subsidy"); +INSTANTIATE_POOL_METHODS(Subsidy) /** * Marks subsidy as awarded, creates news and AI event @@ -46,44 +48,17 @@ void Subsidy::AwardTo(CompanyID company) (NewsReferenceType)reftype.a, this->src, (NewsReferenceType)reftype.b, this->dst, company_name ); - AI::BroadcastNewEvent(new AIEventSubsidyAwarded(this->Index())); + AI::BroadcastNewEvent(new AIEventSubsidyAwarded(this->index)); InvalidateWindow(WC_SUBSIDIES_LIST, 0); } /** - * Allocates one subsidy - * @return pointer to first invalid subsidy, NULL if there is none - */ -/* static */ Subsidy *Subsidy::AllocateItem() -{ - for (Subsidy *s = Subsidy::array; s < endof(Subsidy::array); s++) { - if (!s->IsValid()) { - s->awarded = INVALID_COMPANY; - return s; - } - } - - return NULL; -} - -/** - * Resets the array of subsidies marking all invalid - */ -/* static */ void Subsidy::Clean() -{ - memset(Subsidy::array, 0, sizeof(Subsidy::array)); - for (Subsidy *s = Subsidy::array; s < endof(Subsidy::array); s++) { - s->cargo_type = CT_INVALID; - } -} - -/** * Initializes subsidies, files don't have to include subsidy_base,h this way */ void InitializeSubsidies() { - Subsidy::Clean(); + _subsidy_pool.CleanPool(); } Pair SetupSubsidyDecodeParam(const Subsidy *s, bool mode) @@ -157,12 +132,6 @@ void RebuildSubsidisedSourceAndDestinati } } -void DeleteSubsidy(Subsidy *s) -{ - s->cargo_type = CT_INVALID; - RebuildSubsidisedSourceAndDestinationCache(); -} - void DeleteSubsidyWith(SourceType type, SourceID index) { bool dirty = false; @@ -170,12 +139,15 @@ void DeleteSubsidyWith(SourceType type, Subsidy *s; FOR_ALL_SUBSIDIES(s) { if ((s->src_type == type && s->src == index) || (s->dst_type == type && s->dst == index)) { - s->cargo_type = CT_INVALID; + delete s; dirty = true; } } - if (dirty) InvalidateWindow(WC_SUBSIDIES_LIST, 0); + if (dirty) { + InvalidateWindow(WC_SUBSIDIES_LIST, 0); + RebuildSubsidisedSourceAndDestinationCache(); + } } struct FoundRoute { @@ -267,7 +239,7 @@ static bool CheckSubsidyDuplicate(Subsid if (s != ss && ss->cargo_type == s->cargo_type && ss->src_type == s->src_type && ss->src == s->src && ss->dst_type == s->dst_type && ss->dst == s->dst) { - s->cargo_type = CT_INVALID; + delete s; return true; } } @@ -285,30 +257,29 @@ void SubsidyMonthlyLoop() if (!s->IsAwarded()) { Pair reftype = SetupSubsidyDecodeParam(s, 1); AddNewsItem(STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED, NS_SUBSIDIES, (NewsReferenceType)reftype.a, s->src, (NewsReferenceType)reftype.b, s->dst); - AI::BroadcastNewEvent(new AIEventSubsidyOfferExpired(s->Index())); + AI::BroadcastNewEvent(new AIEventSubsidyOfferExpired(s->index)); } else { if (s->awarded == _local_company) { Pair reftype = SetupSubsidyDecodeParam(s, 1); AddNewsItem(STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE, NS_SUBSIDIES, (NewsReferenceType)reftype.a, s->src, (NewsReferenceType)reftype.b, s->dst); } - AI::BroadcastNewEvent(new AIEventSubsidyExpired(s->Index())); + AI::BroadcastNewEvent(new AIEventSubsidyExpired(s->index)); } - DeleteSubsidy(s); + delete s; modified = true; } } + if (modified) RebuildSubsidisedSourceAndDestinationCache(); + /* 25% chance to go on */ - if (Chance16(1, 4)) { - /* Find a free slot*/ - s = Subsidy::AllocateItem(); - if (s == NULL) goto no_add; - + if (Subsidy::CanAllocateItem() && Chance16(1, 4)) { uint n = 1000; do { FoundRoute fr; FindSubsidyPassengerRoute(&fr); if (fr.distance <= SUBSIDY_MAX_DISTANCE) { + s = new Subsidy(); s->cargo_type = CT_PASSENGERS; s->src_type = s->dst_type = ST_TOWN; s->src = ((Town *)fr.from)->index; @@ -317,6 +288,7 @@ void SubsidyMonthlyLoop() } FindSubsidyCargoRoute(&fr); if (fr.distance <= SUBSIDY_MAX_DISTANCE) { + s = new Subsidy(); s->cargo_type = fr.cargo; s->src_type = ST_INDUSTRY; s->src = ((Industry *)fr.from)->index; @@ -333,20 +305,20 @@ void SubsidyMonthlyLoop() add_subsidy: if (!CheckSubsidyDuplicate(s)) { s->remaining = SUBSIDY_OFFER_MONTHS; + s->awarded = INVALID_COMPANY; Pair reftype = SetupSubsidyDecodeParam(s, 0); AddNewsItem(STR_NEWS_SERVICE_SUBSIDY_OFFERED, NS_SUBSIDIES, (NewsReferenceType)reftype.a, s->src, (NewsReferenceType)reftype.b, s->dst); SetPartOfSubsidyFlag(s->src_type, s->src, POS_SRC); SetPartOfSubsidyFlag(s->dst_type, s->dst, POS_DST); - AI::BroadcastNewEvent(new AIEventSubsidyOffer(s->Index())); + AI::BroadcastNewEvent(new AIEventSubsidyOffer(s->index)); modified = true; break; } } } while (n--); } -no_add:; - if (modified) - InvalidateWindow(WC_SUBSIDIES_LIST, 0); + + if (modified) InvalidateWindow(WC_SUBSIDIES_LIST, 0); } /** diff --git a/src/subsidy_base.h b/src/subsidy_base.h --- a/src/subsidy_base.h +++ b/src/subsidy_base.h @@ -8,9 +8,13 @@ #include "cargo_type.h" #include "company_type.h" #include "subsidy_type.h" +#include "core/pool_type.hpp" + +typedef Pool SubsidyPool; +extern SubsidyPool _subsidy_pool; /** Struct about subsidies, offered and awarded */ -struct Subsidy { +struct Subsidy : SubsidyPool::PoolItem<&_subsidy_pool> { CargoID cargo_type; ///< Cargo type involved in this subsidy, CT_INVALID for invalid subsidy byte remaining; ///< Remaining months when this subsidy is valid CompanyByte awarded; ///< Subsidy is awarded to this company; INVALID_COMPANY if it's not awarded to anyone @@ -20,6 +24,11 @@ struct Subsidy { SourceID dst; ///< Index of destination. Either TownID or IndustryID /** + * We need an (empty) constructor so struct isn't zeroed (as C++ standard states) + */ + FORCEINLINE Subsidy() { } + + /** * Tests whether this subsidy has been awarded to someone * @return is this subsidy awarded? */ @@ -29,60 +38,6 @@ struct Subsidy { } void AwardTo(CompanyID company); - - /** - * Determines index of this subsidy - * @return index (in the Subsidy::array array) - */ - FORCEINLINE SubsidyID Index() const - { - return this - Subsidy::array; - } - - /** - * Tests for validity of this subsidy - * @return is this subsidy valid? - */ - FORCEINLINE bool IsValid() const - { - return this->cargo_type != CT_INVALID; - } - - - static Subsidy array[MAX_COMPANIES]; ///< Array holding all subsidies - - /** - * Total number of subsidies, both valid and invalid - * @return length of Subsidy::array - */ - static FORCEINLINE size_t GetArraySize() - { - return lengthof(Subsidy::array); - } - - /** - * Tests whether given index is an index of valid subsidy - * @param index index to check - * @return can this index be used to access a valid subsidy? - */ - static FORCEINLINE bool IsValidID(size_t index) - { - return index < Subsidy::GetArraySize() && Subsidy::Get(index)->IsValid(); - } - - /** - * Returns pointer to subsidy with given index - * @param index index of subsidy - * @return pointer to subsidy with given index - */ - static FORCEINLINE Subsidy *Get(size_t index) - { - assert(index < Subsidy::GetArraySize()); - return &Subsidy::array[index]; - } - - static Subsidy *AllocateItem(); - static void Clean(); }; /** Constants related to subsidies */ @@ -95,8 +50,7 @@ enum { SUBSIDY_MAX_DISTANCE = 70, ///< Max. length of subsidised route (DistanceManhattan) }; -#define FOR_ALL_SUBSIDIES_FROM(var, start) for (size_t subsidy_index = start; var = NULL, subsidy_index < Subsidy::GetArraySize(); subsidy_index++) \ - if ((var = Subsidy::Get(subsidy_index))->IsValid()) +#define FOR_ALL_SUBSIDIES_FROM(var, start) FOR_ALL_ITEMS_FROM(Subsidy, subsidy_index, var, start) #define FOR_ALL_SUBSIDIES(var) FOR_ALL_SUBSIDIES_FROM(var, 0) #endif /* SUBSIDY_BASE_H */