diff --git a/src/feature.cpp b/src/feature.cpp index 3becf1f38bd..f14b0318adf 100644 --- a/src/feature.cpp +++ b/src/feature.cpp @@ -52,16 +52,14 @@ #include "random.h" /* The statistics for the features */ -FEATURE_STATS *asFeatureStats; -UDWORD numFeatureStats; +std::vector asFeatureStats; //Value is stored for easy access to this feature in destroyDroid()/destroyStruct() FEATURE_STATS *oilResFeature = nullptr; void featureInitVars() { - asFeatureStats = nullptr; - numFeatureStats = 0; + asFeatureStats.clear(); oilResFeature = nullptr; } @@ -70,70 +68,69 @@ bool loadFeatureStats(WzConfig &ini) { ASSERT(ini.isAtDocumentRoot(), "WzConfig instance is in the middle of traversal"); std::vector list = ini.childGroups(); - asFeatureStats = new FEATURE_STATS[list.size()]; - numFeatureStats = list.size(); + asFeatureStats.reserve(list.size()); for (int i = 0; i < list.size(); ++i) { ini.beginGroup(list[i]); - asFeatureStats[i] = FEATURE_STATS(STAT_FEATURE + i); - FEATURE_STATS *p = &asFeatureStats[i]; - p->name = ini.string(WzString::fromUtf8("name")); - p->id = list[i]; + asFeatureStats.emplace_back(STAT_FEATURE + i); + FEATURE_STATS& p = asFeatureStats.at(i); + p.name = ini.string(WzString::fromUtf8("name")); + p.id = list[i]; WzString subType = ini.value("type").toWzString(); if (subType == "TANK WRECK") { - p->subType = FEAT_TANK; + p.subType = FEAT_TANK; } else if (subType == "GENERIC ARTEFACT") { - p->subType = FEAT_GEN_ARTE; + p.subType = FEAT_GEN_ARTE; } else if (subType == "OIL RESOURCE") { - p->subType = FEAT_OIL_RESOURCE; + p.subType = FEAT_OIL_RESOURCE; } else if (subType == "BOULDER") { - p->subType = FEAT_BOULDER; + p.subType = FEAT_BOULDER; } else if (subType == "VEHICLE") { - p->subType = FEAT_VEHICLE; + p.subType = FEAT_VEHICLE; } else if (subType == "BUILDING") { - p->subType = FEAT_BUILDING; + p.subType = FEAT_BUILDING; } else if (subType == "OIL DRUM") { - p->subType = FEAT_OIL_DRUM; + p.subType = FEAT_OIL_DRUM; } else if (subType == "TREE") { - p->subType = FEAT_TREE; + p.subType = FEAT_TREE; } else if (subType == "SKYSCRAPER") { - p->subType = FEAT_SKYSCRAPER; + p.subType = FEAT_SKYSCRAPER; } else { ASSERT(false, "Unknown feature type: %s", subType.toUtf8().c_str()); } - p->psImd = modelGet(ini.value("model").toWzString()); - p->baseWidth = ini.value("width", 1).toInt(); - p->baseBreadth = ini.value("breadth", 1).toInt(); - p->tileDraw = ini.value("tileDraw", 1).toInt(); - p->allowLOS = ini.value("lineOfSight", 1).toInt(); - p->visibleAtStart = ini.value("startVisible", 1).toInt(); - p->damageable = ini.value("damageable", 1).toInt(); - p->body = ini.value("hitpoints", 1).toInt(); - p->armourValue = ini.value("armour", 1).toInt(); + p.psImd = modelGet(ini.value("model").toWzString()); + p.baseWidth = ini.value("width", 1).toInt(); + p.baseBreadth = ini.value("breadth", 1).toInt(); + p.tileDraw = ini.value("tileDraw", 1).toInt(); + p.allowLOS = ini.value("lineOfSight", 1).toInt(); + p.visibleAtStart = ini.value("startVisible", 1).toInt(); + p.damageable = ini.value("damageable", 1).toInt(); + p.body = ini.value("hitpoints", 1).toInt(); + p.armourValue = ini.value("armour", 1).toInt(); //and the oil resource - assumes only one! - if (asFeatureStats[i].subType == FEAT_OIL_RESOURCE) + if (p.subType == FEAT_OIL_RESOURCE) { - oilResFeature = &asFeatureStats[i]; + oilResFeature = &p; } ini.endGroup(); } @@ -144,9 +141,7 @@ bool loadFeatureStats(WzConfig &ini) /* Release the feature stats memory */ void featureStatsShutDown() { - delete[] asFeatureStats; - asFeatureStats = nullptr; - numFeatureStats = 0; + asFeatureStats.clear(); } /** Deals with damage to a feature @@ -539,7 +534,7 @@ SDWORD getFeatureStatFromName(const WzString &name) { FEATURE_STATS *psStat; - for (unsigned inc = 0; inc < numFeatureStats; inc++) + for (unsigned inc = 0, size = asFeatureStats.size(); inc < size; inc++) { psStat = &asFeatureStats[inc]; if (psStat->id.compare(name) == 0) diff --git a/src/feature.h b/src/feature.h index 66fff893440..b654bf54560 100644 --- a/src/feature.h +++ b/src/feature.h @@ -28,8 +28,7 @@ #include "lib/framework/wzconfig.h" /* The statistics for the features */ -extern FEATURE_STATS *asFeatureStats; -extern UDWORD numFeatureStats; +extern std::vector asFeatureStats; //Value is stored for easy access to this feature in destroyDroid()/destroyStruct() extern FEATURE_STATS *oilResFeature; diff --git a/src/game.cpp b/src/game.cpp index 0b4c6ff2a9c..2141a27733c 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -6789,7 +6789,7 @@ bool loadSaveFeature(char *pFileData, UDWORD filesize) FEATURE_SAVEHEADER *psHeader; SAVE_FEATURE_V14 *psSaveFeature; FEATURE *pFeature; - UDWORD count, i, statInc; + UDWORD count, i; FEATURE_STATS *psStats = nullptr; bool found; UDWORD sizeOfSaveFeature; @@ -6852,12 +6852,12 @@ bool loadSaveFeature(char *pFileData, UDWORD filesize) //get the stats for this feature found = false; - for (statInc = 0; statInc < numFeatureStats; statInc++) + for (FEATURE_STATS& stat : asFeatureStats) { - psStats = asFeatureStats + statInc; //loop until find the same name - if (psStats->id.compare(psSaveFeature->name) == 0) + if (stat.id.compare(psSaveFeature->name) == 0) { + psStats = &stat; found = true; break; } @@ -6905,8 +6905,8 @@ static bool loadWzMapFeature(WzMap::Map &wzMap, std::unordered_mapid.compare(name) == 0) + if (stat.id.compare(name) == 0) { + psStats = &stat; found = true; break; } @@ -7702,7 +7701,7 @@ static bool writeMessageFile(const char *pFileName) for (int player = 0; player < game.maxPlayers; player++) { ASSERT(player < MAX_PLAYERS, "player out of bounds: %d", player); - for (MESSAGE *psMessage = apsMessages[player]; psMessage != nullptr; psMessage = psMessage->psNext) + for (const MESSAGE *psMessage : apsMessages[player]) { ini.beginGroup("message_" + WzString::number(numMessages++)); ini.setValue("id", numMessages - 1); // for future use diff --git a/src/hci.cpp b/src/hci.cpp index 0dca5079309..35c7104326b 100644 --- a/src/hci.cpp +++ b/src/hci.cpp @@ -1270,12 +1270,12 @@ void intOpenDebugMenu(OBJECT_TYPE id) editPosMode = IED_NOPOS; break; case OBJ_FEATURE: - for (unsigned i = 0; i < std::min(numFeatureStats, MAXFEATURES); ++i) + for (unsigned i = 0, end = std::min(asFeatureStats.size(), MAXFEATURES); i < end; ++i) { - apsFeatureList[i] = asFeatureStats + i; + apsFeatureList[i] = &asFeatureStats.at(i); } ppsStatsList = (BASE_STATS **)apsFeatureList; - intAddDebugStatsForm(ppsStatsList, std::min(numFeatureStats, MAXFEATURES)); + intAddDebugStatsForm(ppsStatsList, std::min(asFeatureStats.size(), MAXFEATURES)); intMode = INT_EDITSTAT; editPosMode = IED_NOPOS; break; diff --git a/src/intelmap.cpp b/src/intelmap.cpp index b7f54ebd34a..219847483ec 100644 --- a/src/intelmap.cpp +++ b/src/intelmap.cpp @@ -539,7 +539,7 @@ void W_INTELLIGENCEOVERLAY_FORM::initialize(bool _playCurrent, bool animate) /* Add the message buttons */ //add each button - for (MESSAGE *psMessage = apsMessages[selectedPlayer]; psMessage != nullptr; psMessage = psMessage->psNext) + for (MESSAGE *psMessage : apsMessages[selectedPlayer]) { /*if (psMessage->type == MSG_TUTORIAL) { @@ -901,22 +901,20 @@ static void StartMessageSequences(MESSAGE *psMessage, bool Start) static void intCleanUpIntelMap() { - MESSAGE *psMessage, *psNext; bool removedAMessage = false; if (selectedPlayer < MAX_PLAYERS) { //remove any research messages that have been read - for (psMessage = apsMessages[selectedPlayer]; psMessage != nullptr; psMessage = - psNext) + mutating_list_iterate(apsMessages[selectedPlayer], [&removedAMessage](MESSAGE* psMessage) { - psNext = psMessage->psNext; if (psMessage->type == MSG_RESEARCH && psMessage->read) { removeMessage(psMessage, selectedPlayer); removedAMessage = true; } - } + return IterationResult::CONTINUE_ITERATION; + }); } if (removedAMessage) { @@ -1205,20 +1203,16 @@ void addVideoText(SEQ_DISPLAY *psSeqDisplay, UDWORD sequence) /*sets psCurrentMsg for the Intelligence screen*/ void setCurrentMsg() { - MESSAGE *psMsg, *psLastMsg; - ASSERT_OR_RETURN(, selectedPlayer < MAX_PLAYERS, "Unsupported selectedPlayer: %" PRIu32 "", selectedPlayer); - psLastMsg = nullptr; - for (psMsg = apsMessages[selectedPlayer]; psMsg != nullptr; psMsg = - psMsg->psNext) + for (auto it = apsMessages[selectedPlayer].rbegin(), end = apsMessages[selectedPlayer].rend(); it != end; ++it) { - if (psMsg->type != MSG_PROXIMITY) + if ((*it)->type != MSG_PROXIMITY) { - psLastMsg = psMsg; + psCurrentMsg = *it; + return; } } - psCurrentMsg = psLastMsg; } /*sets which states need to be paused when the intelligence screen is up*/ diff --git a/src/message.cpp b/src/message.cpp index 605382cb7ef..29171e52453 100644 --- a/src/message.cpp +++ b/src/message.cpp @@ -48,7 +48,7 @@ static UDWORD msgID = 0; static int currentNumProxDisplays = 0; -MESSAGE *apsMessages[MAX_PLAYERS]; +PerPlayerMessageLists apsMessages; /* The list of proximity displays allocated */ PerPlayerProximityDisplayLists apsProxDisp; @@ -85,90 +85,47 @@ static inline MESSAGE *createMessage(MESSAGE_TYPE msgType, UDWORD player) * list is a pointer to the message list * Order is now CAMPAIGN, MISSION, RESEARCH/PROXIMITY */ -static inline void addMessageToList(MESSAGE *list[MAX_PLAYERS], MESSAGE *msg, UDWORD player) +static inline void addMessageToList(PerPlayerMessageLists& list, MESSAGE *msg, UDWORD player) { - MESSAGE *psCurr = nullptr, *psPrev = nullptr; - ASSERT_OR_RETURN(, msg != nullptr, "Invalid message pointer"); ASSERT_OR_RETURN(, player < MAX_PLAYERS, "Bad player"); // If there is no message list, create one - if (list[player] == nullptr) + if (list[player].empty()) { - list[player] = msg; - msg->psNext = nullptr; - + list[player].emplace_front(msg); return; } switch (msg->type) { case MSG_CAMPAIGN: + { /*add it before the first mission/research/prox message */ - for (psCurr = list[player]; psCurr != nullptr; psCurr = psCurr->psNext) + const auto it = std::find_if(list[player].begin(), list[player].end(), [](MESSAGE* psCurr) { - if (psCurr->type == MSG_MISSION || - psCurr->type == MSG_RESEARCH || - psCurr->type == MSG_PROXIMITY) - { - break; - } - - psPrev = psCurr; - } - - if (psPrev) - { - psPrev->psNext = msg; - msg->psNext = psCurr; - } - else - { - //must be top of list - psPrev = list[player]; - list[player] = msg; - msg->psNext = psPrev; - } - + return psCurr->type == MSG_MISSION || + psCurr->type == MSG_RESEARCH || + psCurr->type == MSG_PROXIMITY; + }); + list[player].emplace(it, msg); break; + } case MSG_MISSION: + { /*add it before the first research/prox message */ - for (psCurr = list[player]; psCurr != nullptr; psCurr = psCurr->psNext) + const auto it = std::find_if(list[player].begin(), list[player].end(), [](MESSAGE* psCurr) { - if (psCurr->type == MSG_RESEARCH || - psCurr->type == MSG_PROXIMITY) - { - break; - } - - psPrev = psCurr; - } - - if (psPrev) - { - psPrev->psNext = msg; - msg->psNext = psCurr; - } - else - { - //must be top of list - psPrev = list[player]; - list[player] = msg; - msg->psNext = psPrev; - } - + return psCurr->type == MSG_RESEARCH || + psCurr->type == MSG_PROXIMITY; + }); + list[player].emplace(it, msg); break; + } case MSG_RESEARCH: case MSG_PROXIMITY: /*add it to the bottom of the list */ - - // Iterate to the last item in the list - for (psCurr = list[player]; psCurr->psNext != nullptr; psCurr = psCurr->psNext) {} - - // Append the new message to the end of the list - psCurr->psNext = msg; - msg->psNext = nullptr; - + list[player].emplace_back(msg); break; default: debug(LOG_ERROR, "unknown message type"); @@ -182,53 +139,28 @@ static inline void addMessageToList(MESSAGE *list[MAX_PLAYERS], MESSAGE *msg, UD * list is a pointer to the message list * del is a pointer to the message to remove */ -static inline void removeMessageFromList(MESSAGE *list[], MESSAGE *del, UDWORD player) +static inline void removeMessageFromList(PerPlayerMessageLists& list, MESSAGE *del, UDWORD player) { - MESSAGE *psPrev = nullptr, *psCurr; - ASSERT_OR_RETURN(, del != nullptr, "Invalid message pointer"); ASSERT_OR_RETURN(, player < MAX_PLAYERS, "Bad player"); - // If the message to remove is the first one in the list then mark the next one as the first - if (list[player] == del) - { - list[player] = list[player]->psNext; - delete del; - return; - } - - // Iterate through the list and find the item before the message to delete - for (psCurr = list[player]; (psCurr != del) && (psCurr != nullptr); psCurr = psCurr->psNext) - { - psPrev = psCurr; - } - - ASSERT(psCurr != nullptr, "message not found in list"); - - if (psCurr != nullptr) - { - // Modify the "next" pointer of the previous item to - // point to the "next" item of the item to delete. - psPrev->psNext = psCurr->psNext; - delete del; - } + auto it = std::find(list[player].begin(), list[player].end(), del); + ASSERT_OR_RETURN(, it != list[player].end(), "Message %p not found in list", static_cast(del)); + list[player].erase(it); + delete del; } -static inline void releaseAllMessages(MESSAGE *list[]) +static inline void releaseAllMessages(PerPlayerMessageLists& list) { - UDWORD i; - MESSAGE *psCurr, *psNext; - // Iterate through all players' message lists - for (i = 0; i < MAX_PLAYERS; i++) + for (MessageList& pl : list) { // Iterate through all messages in list - for (psCurr = list[i]; psCurr != nullptr; psCurr = psNext) + for (MESSAGE* psCurr : pl) { - psNext = psCurr->psNext; delete psCurr; } - list[i] = nullptr; + pl.clear(); } } @@ -241,7 +173,7 @@ bool messageInitVars() for (i = 0; i < MAX_PLAYERS; i++) { - apsMessages[i] = nullptr; + apsMessages[i].clear(); apsProxDisp[i].clear(); } @@ -766,20 +698,18 @@ bool messageShutdown() //check for any messages using this viewdata and remove them static void checkMessages(VIEWDATA *psViewData) { - MESSAGE *psCurr, *psNext; - bool removedAMessage = false; for (unsigned i = 0; i < MAX_PLAYERS; i++) { - for (psCurr = apsMessages[i]; psCurr != nullptr; psCurr = psNext) + mutating_list_iterate(apsMessages[i], [&removedAMessage, i, psViewData](MESSAGE* psCurr) { - psNext = psCurr->psNext; if (psCurr->pViewData == psViewData) { removeMessage(psCurr, i); removedAMessage = true; } - } + return IterationResult::CONTINUE_ITERATION; + }); } if (removedAMessage) @@ -788,22 +718,20 @@ static void checkMessages(VIEWDATA *psViewData) } } -void releaseAllFlicMessages(MESSAGE *list[]) +void releaseAllFlicMessages(PerPlayerMessageLists& list) { - MESSAGE *psCurr, *psNext; - // Iterate through all players' message lists for (unsigned int i = 0; i < MAX_PLAYERS; i++) { // Iterate through all messages in list - for (psCurr = list[i]; psCurr != nullptr; psCurr = psNext) + mutating_list_iterate(list[i], [i](MESSAGE* psCurr) { - psNext = psCurr->psNext; if (psCurr->type == MSG_MISSION || psCurr->type == MSG_CAMPAIGN) { removeMessage(psCurr, i); } - } + return IterationResult::CONTINUE_ITERATION; + }); } } @@ -842,7 +770,7 @@ MESSAGE *findMessage(const VIEWDATA *pViewData, MESSAGE_TYPE type, UDWORD player ASSERT_OR_RETURN(nullptr, player < MAX_PLAYERS, "Bad player"); ASSERT_OR_RETURN(nullptr , type < MSG_TYPES, "Bad message type"); - for (MESSAGE *psCurr = apsMessages[player]; psCurr != nullptr; psCurr = psCurr->psNext) + for (MESSAGE *psCurr : apsMessages[player]) { if (psCurr->type == type && psCurr->pViewData == pViewData) { @@ -859,7 +787,7 @@ MESSAGE *findMessage(const BASE_OBJECT *psObj, MESSAGE_TYPE type, UDWORD player) ASSERT_OR_RETURN(nullptr, player < MAX_PLAYERS, "Bad player"); ASSERT_OR_RETURN(nullptr , type < MSG_TYPES, "Bad message type"); - for (MESSAGE *psCurr = apsMessages[player]; psCurr != nullptr; psCurr = psCurr->psNext) + for (MESSAGE *psCurr : apsMessages[player]) { if (psCurr->type == type && psCurr->psObj == psObj) { diff --git a/src/message.h b/src/message.h index 7119d7d6822..305a021ded2 100644 --- a/src/message.h +++ b/src/message.h @@ -32,7 +32,9 @@ #define NO_AUDIO_MSG -1 /** The lists of messages allocated. */ -extern MESSAGE *apsMessages[MAX_PLAYERS]; +using PerPlayerMessageLists = PerPlayerObjectLists; +using MessageList = typename PerPlayerMessageLists::value_type; +extern PerPlayerMessageLists apsMessages; /** The IMD to use for the proximity messages. */ extern iIMDBaseShape *pProximityMsgIMD; @@ -79,7 +81,7 @@ VIEWDATA *getViewData(const WzString &name); std::vector getViewDataKeys(); // Get rid of mission objectives -void releaseAllFlicMessages(MESSAGE *list[]); +void releaseAllFlicMessages(PerPlayerMessageLists& list); /** Release the viewdata memory. */ void viewDataShutDown(const char *fileName); diff --git a/src/messagedef.h b/src/messagedef.h index 5dfeee52385..cfc415e8a1e 100644 --- a/src/messagedef.h +++ b/src/messagedef.h @@ -127,8 +127,6 @@ struct MESSAGE bool read = false; // flag to indicate whether message has been read UDWORD player; // which player this message belongs to MSG_DATA_TYPE dataType; - - MESSAGE *psNext = nullptr; // pointer to the next in the list }; //used to display the proximity messages diff --git a/src/multigifts.cpp b/src/multigifts.cpp index a76cf68c287..5e75c485dde 100644 --- a/src/multigifts.cpp +++ b/src/multigifts.cpp @@ -729,8 +729,8 @@ void technologyGiveAway(const STRUCTURE *pS) } int featureIndex; - for (featureIndex = 0; featureIndex < numFeatureStats && asFeatureStats[featureIndex].subType != FEAT_GEN_ARTE; ++featureIndex) {} - if (featureIndex >= numFeatureStats) + for (featureIndex = 0; featureIndex < asFeatureStats.size() && asFeatureStats[featureIndex].subType != FEAT_GEN_ARTE; ++featureIndex) {} + if (featureIndex >= asFeatureStats.size()) { debug(LOG_WARNING, "No artefact feature!"); return; @@ -774,7 +774,6 @@ void sendMultiPlayerFeature(uint32_t ref, uint32_t x, uint32_t y, uint32_t id) void recvMultiPlayerFeature(NETQUEUE queue) { uint32_t ref = 0xff, x = 0, y = 0, id = 0; - unsigned int i; NETbeginDecode(queue, GAME_DEBUG_ADD_FEATURE); { @@ -793,7 +792,7 @@ void recvMultiPlayerFeature(NETQUEUE queue) } // Find the feature stats list that contains the feature type we want to build - for (i = 0; i < numFeatureStats; ++i) + for (size_t i = 0, end = asFeatureStats.size(); i < end; ++i) { // If we found the correct feature type if (asFeatureStats[i].ref == ref) diff --git a/src/multiplay.cpp b/src/multiplay.cpp index e1db693e2b5..8e821864017 100644 --- a/src/multiplay.cpp +++ b/src/multiplay.cpp @@ -2186,7 +2186,7 @@ MESSAGE *findBeaconMsg(UDWORD player, SDWORD sender) { ASSERT_OR_RETURN(nullptr, player < MAX_PLAYERS, "Unsupported player: %" PRIu32 "", player); - for (MESSAGE *psCurr = apsMessages[player]; psCurr != nullptr; psCurr = psCurr->psNext) + for (MESSAGE *psCurr : apsMessages[player]) { //look for VIEW_BEACON, should only be 1 per player if (psCurr->dataType == MSG_DATA_BEACON) diff --git a/src/wzscriptdebug.cpp b/src/wzscriptdebug.cpp index 331b84fb364..5ec1f1f78e2 100644 --- a/src/wzscriptdebug.cpp +++ b/src/wzscriptdebug.cpp @@ -178,7 +178,7 @@ static RowDataModel fillMessageModel() RowDataModel result(6); for (int i = 0; i < MAX_PLAYERS; i++) { - for (const MESSAGE *psCurr = apsMessages[i]; psCurr != nullptr; psCurr = psCurr->psNext) + for (const MESSAGE *psCurr : apsMessages[i]) { ASSERT(psCurr->type < msg_type.size(), "Bad message type"); ASSERT(psCurr->dataType < msg_data_type.size(), "Bad viewdata type");