From d1d3e75948cbf3dba09c451a02faf1d2d0645cf7 Mon Sep 17 00:00:00 2001 From: Pavel Solodovnikov Date: Mon, 1 Jan 2024 20:55:38 +0300 Subject: [PATCH 1/6] Switch `PROXIMITY_DISPLAY` list to `std::list` Signed-off-by: Pavel Solodovnikov --- src/display3d.cpp | 2 +- src/game.cpp | 16 ++--- src/hci.cpp | 28 ++++----- src/intdisplay.cpp | 149 +++++++++++++++++++++++---------------------- src/message.cpp | 54 ++++++---------- src/message.h | 5 +- src/messagedef.h | 1 - 7 files changed, 118 insertions(+), 137 deletions(-) diff --git a/src/display3d.cpp b/src/display3d.cpp index 29e89e5bee7..e82ee6c7e6c 100644 --- a/src/display3d.cpp +++ b/src/display3d.cpp @@ -2284,7 +2284,7 @@ static void displayProximityMsgs(const glm::mat4& viewMatrix, const glm::mat4 &p if (selectedPlayer >= MAX_PLAYERS) { return; /* no-op */ } /* Go through all the proximity Displays*/ - for (PROXIMITY_DISPLAY *psProxDisp = apsProxDisp[selectedPlayer]; psProxDisp != nullptr; psProxDisp = psProxDisp->psNext) + for (PROXIMITY_DISPLAY* psProxDisp : apsProxDisp[selectedPlayer]) { if (!(psProxDisp->psMessage->read)) { diff --git a/src/game.cpp b/src/game.cpp index 1c438202512..0b4c6ff2a9c 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -2537,7 +2537,7 @@ bool loadGame(const char *pGameToLoad, bool keepObjects, bool freeMem, bool User apsFeatureLists[player].clear(); apsFlagPosLists[player].clear(); //clear all the messages? - apsProxDisp[player] = nullptr; + apsProxDisp[player].clear(); apsSensorList[0].clear(); apsExtractorLists[player].clear(); } @@ -7712,16 +7712,12 @@ static bool writeMessageFile(const char *pFileName) if (psMessage->type == MSG_PROXIMITY) { //get the matching proximity message - PROXIMITY_DISPLAY *psProx = nullptr; - for (psProx = apsProxDisp[player]; psProx != nullptr; psProx = psProx->psNext) + auto psProxIt = std::find_if(apsProxDisp[player].begin(), apsProxDisp[player].end(), [psMessage](PROXIMITY_DISPLAY* psProx) { - //compare the pointers - if (psProx->psMessage == psMessage) - { - break; - } - } - ASSERT(psProx != nullptr, "Save message; proximity display not found for message"); + return psProx->psMessage == psMessage; //compare the pointers + }); + ASSERT(psProxIt != apsProxDisp[player].end(), "Save message; proximity display not found for message"); + PROXIMITY_DISPLAY* psProx = *psProxIt; if (psProx && psProx->type == POS_PROXDATA) { //message has viewdata so store the name diff --git a/src/hci.cpp b/src/hci.cpp index afca26eece6..8bb1c356eb9 100644 --- a/src/hci.cpp +++ b/src/hci.cpp @@ -2648,7 +2648,6 @@ void forceHidePowerBar(bool forceSetPowerBarUpState) /* Add the Proximity message buttons */ bool intAddProximityButton(PROXIMITY_DISPLAY *psProxDisp, UDWORD inc) { - PROXIMITY_DISPLAY *psProxDisp2; UDWORD cnt; if (selectedPlayer >= MAX_PLAYERS) @@ -2666,9 +2665,13 @@ bool intAddProximityButton(PROXIMITY_DISPLAY *psProxDisp, UDWORD inc) for (cnt = IDPROX_START; cnt < IDPROX_END; cnt++) { // go down the prox msgs and see if it's free. - for (psProxDisp2 = apsProxDisp[selectedPlayer]; psProxDisp2 && psProxDisp2->buttonID != cnt; psProxDisp2 = psProxDisp2->psNext) {} + const auto& proxDispList = apsProxDisp[selectedPlayer]; + auto proxDispIt = std::find_if(proxDispList.begin(), proxDispList.end(), [cnt](PROXIMITY_DISPLAY* pd) + { + return pd->buttonID == cnt; + }); - if (psProxDisp2 == nullptr) // value was unused. + if (proxDispIt == proxDispList.end()) // value was unused. { sBFormInit.id = cnt; break; @@ -2710,8 +2713,6 @@ void intRemoveProximityButton(PROXIMITY_DISPLAY *psProxDisp) /*deals with the proximity message when clicked on*/ void processProximityButtons(UDWORD id) { - PROXIMITY_DISPLAY *psProxDisp; - if (!doWeDrawProximitys()) { return; @@ -2720,20 +2721,17 @@ void processProximityButtons(UDWORD id) if (selectedPlayer >= MAX_PLAYERS) { return; /* no-op */ } //find which proximity display this relates to - psProxDisp = nullptr; - for (psProxDisp = apsProxDisp[selectedPlayer]; psProxDisp; psProxDisp = psProxDisp->psNext) + const auto& proxDispList = apsProxDisp[selectedPlayer]; + auto proxDispIt = std::find_if(proxDispList.begin(), proxDispList.end(), [id](PROXIMITY_DISPLAY* psProxDisp) { - if (psProxDisp->buttonID == id) - { - break; - } - } - if (psProxDisp) + return psProxDisp->buttonID == id; + }); + if (proxDispIt != proxDispList.end()) { //if not been read - display info - if (!psProxDisp->psMessage->read) + if (!(*proxDispIt)->psMessage->read) { - displayProximityMessage(psProxDisp); + displayProximityMessage(*proxDispIt); } } } diff --git a/src/intdisplay.cpp b/src/intdisplay.cpp index b1c52abb97e..10967560c37 100644 --- a/src/intdisplay.cpp +++ b/src/intdisplay.cpp @@ -1691,7 +1691,6 @@ void IntTransportButton::display(int xOffset, int yOffset) /* Draws blips on radar to represent Proximity Display and damaged structures */ void drawRadarBlips(int radarX, int radarY, float pixSizeH, float pixSizeV, const glm::mat4 &modelViewProjection) { - PROXIMITY_DISPLAY *psProxDisp; UWORD imageID; UDWORD delay = 150; UDWORD i; @@ -1712,28 +1711,29 @@ void drawRadarBlips(int radarX, int radarY, float pixSizeH, float pixSizeV, cons for (i = 0; i < MAX_PLAYERS; i++) { /* Go through all the proximity Displays*/ - for (psProxDisp = apsProxDisp[i]; psProxDisp != nullptr; psProxDisp = psProxDisp->psNext) + mutating_list_iterate(apsProxDisp[i], [&removedAMessage, i](PROXIMITY_DISPLAY* psProxDisp) { if (psProxDisp->psMessage->dataType == MSG_DATA_BEACON) { - MESSAGE *psCurrMsg = psProxDisp->psMessage; - VIEWDATA *pViewData = psCurrMsg->pViewData; + MESSAGE* psCurrMsg = psProxDisp->psMessage; + VIEWDATA* pViewData = psCurrMsg->pViewData; - ASSERT_OR_RETURN(, pViewData != nullptr, "Message without data!"); + ASSERT_OR_RETURN(IterationResult::CONTINUE_ITERATION, pViewData != nullptr, "Message without data!"); if (pViewData->type == VIEW_BEACON) { - ASSERT_OR_RETURN(, pViewData->pData != nullptr, "Help message without data!"); - if (pViewData->pData != nullptr && (((VIEW_PROXIMITY *)pViewData->pData)->timeAdded + 60000) <= gameTime) + ASSERT_OR_RETURN(IterationResult::CONTINUE_ITERATION, pViewData->pData != nullptr, "Help message without data!"); + if (pViewData->pData != nullptr && (((VIEW_PROXIMITY*)pViewData->pData)->timeAdded + 60000) <= gameTime) { - debug(LOG_MSG, "blip timeout for %d, from %d", i, (((VIEW_PROXIMITY *)pViewData->pData)->sender)); + debug(LOG_MSG, "blip timeout for %d, from %d", i, (((VIEW_PROXIMITY*)pViewData->pData)->sender)); removeMessage(psCurrMsg, i); //remove beacon removedAMessage = true; - break; //there can only be 1 beacon per player + return IterationResult::BREAK_ITERATION; //there can only be 1 beacon per player } } } - } + return IterationResult::CONTINUE_ITERATION; + }); } if (removedAMessage) { @@ -1741,84 +1741,87 @@ void drawRadarBlips(int radarX, int radarY, float pixSizeH, float pixSizeV, cons } /* Go through all the proximity Displays */ - for (psProxDisp = (selectedPlayer < MAX_PLAYERS) ? apsProxDisp[selectedPlayer] : nullptr; psProxDisp != nullptr; psProxDisp = psProxDisp->psNext) + if (selectedPlayer < MAX_PLAYERS) { - unsigned animationLength = ARRAY_SIZE(imagesEnemy) - 1; // Same size as imagesResource and imagesArtifact. - const uint16_t *images; - - if (psProxDisp->psMessage->player != selectedPlayer) + for (PROXIMITY_DISPLAY* psProxDisp : apsProxDisp[selectedPlayer]) { - continue; - } + unsigned animationLength = ARRAY_SIZE(imagesEnemy) - 1; // Same size as imagesResource and imagesArtifact. + const uint16_t* images; - if (psProxDisp->type == POS_PROXDATA) - { - PROX_TYPE proxType = ((VIEW_PROXIMITY *)psProxDisp->psMessage->pViewData->pData)->proxType; - images = imagesProxTypes[proxType]; - } - else - { - const FEATURE *psFeature = castFeature(psProxDisp->psMessage->psObj); + if (psProxDisp->psMessage->player != selectedPlayer) + { + continue; + } - ASSERT_OR_RETURN(, psFeature && psFeature->psStats, "Bad feature message"); - if (psFeature && psFeature->psStats && psFeature->psStats->subType == FEAT_OIL_RESOURCE) + if (psProxDisp->type == POS_PROXDATA) { - images = imagesResource; - if (fireOnLocation(psFeature->pos.x, psFeature->pos.y)) - { - images = imagesBurningResource; - animationLength = ARRAY_SIZE(imagesBurningResource) - 1; // Longer animation for burning oil wells. - } + PROX_TYPE proxType = ((VIEW_PROXIMITY*)psProxDisp->psMessage->pViewData->pData)->proxType; + images = imagesProxTypes[proxType]; } else { - images = imagesArtifact; + const FEATURE* psFeature = castFeature(psProxDisp->psMessage->psObj); + + ASSERT_OR_RETURN(, psFeature && psFeature->psStats, "Bad feature message"); + if (psFeature && psFeature->psStats && psFeature->psStats->subType == FEAT_OIL_RESOURCE) + { + images = imagesResource; + if (fireOnLocation(psFeature->pos.x, psFeature->pos.y)) + { + images = imagesBurningResource; + animationLength = ARRAY_SIZE(imagesBurningResource) - 1; // Longer animation for burning oil wells. + } + } + else + { + images = imagesArtifact; + } } - } - // Draw the 'blips' on the radar - use same timings as radar blips if the message is read - don't animate - if (psProxDisp->psMessage->read) - { - imageID = images[0]; - } - else - { - // Draw animated - if (realTime - psProxDisp->timeLastDrawn > delay) + // Draw the 'blips' on the radar - use same timings as radar blips if the message is read - don't animate + if (psProxDisp->psMessage->read) { - ++psProxDisp->strobe; - psProxDisp->timeLastDrawn = realTime; + imageID = images[0]; + } + else + { + // Draw animated + if (realTime - psProxDisp->timeLastDrawn > delay) + { + ++psProxDisp->strobe; + psProxDisp->timeLastDrawn = realTime; + } + psProxDisp->strobe %= animationLength; + imageID = images[1 + psProxDisp->strobe]; } - psProxDisp->strobe %= animationLength; - imageID = images[1 + psProxDisp->strobe]; - } - if (psProxDisp->type == POS_PROXDATA) - { - const VIEW_PROXIMITY *psViewProx = (VIEW_PROXIMITY *)psProxDisp->psMessage->pViewData->pData; + if (psProxDisp->type == POS_PROXDATA) + { + const VIEW_PROXIMITY* psViewProx = (VIEW_PROXIMITY*)psProxDisp->psMessage->pViewData->pData; - x = static_cast((psViewProx->x / TILE_UNITS - scrollMinX) * pixSizeH); - y = static_cast((psViewProx->y / TILE_UNITS - scrollMinY) * pixSizeV); - } - else if (psProxDisp->type == POS_PROXOBJ) - { - x = static_cast((psProxDisp->psMessage->psObj->pos.x / TILE_UNITS - scrollMinX) * pixSizeH); - y = static_cast((psProxDisp->psMessage->psObj->pos.y / TILE_UNITS - scrollMinY) * pixSizeV); - } - else - { - ASSERT(false, "Bad message type"); - continue; - } + x = static_cast((psViewProx->x / TILE_UNITS - scrollMinX) * pixSizeH); + y = static_cast((psViewProx->y / TILE_UNITS - scrollMinY) * pixSizeV); + } + else if (psProxDisp->type == POS_PROXOBJ) + { + x = static_cast((psProxDisp->psMessage->psObj->pos.x / TILE_UNITS - scrollMinX) * pixSizeH); + y = static_cast((psProxDisp->psMessage->psObj->pos.y / TILE_UNITS - scrollMinY) * pixSizeV); + } + else + { + ASSERT(false, "Bad message type"); + continue; + } - // NOTE: On certain missions (limbo & expand), there is still valid data that is stored outside the - // normal radar/mini-map view. We must now calculate the radar/mini-map's bounding box, and clip - // everything outside the box. - if ((x + radarX) < width * pixSizeV / 2 && (x + radarX) > -width * pixSizeV / 2 - && (y + radarY) < height * pixSizeH / 2 && (y + radarY) > -height * pixSizeH / 2) - { - // Draw the 'blip' - iV_DrawImage(IntImages, imageID, x + radarX, y + radarY, modelViewProjection); + // NOTE: On certain missions (limbo & expand), there is still valid data that is stored outside the + // normal radar/mini-map view. We must now calculate the radar/mini-map's bounding box, and clip + // everything outside the box. + if ((x + radarX) < width * pixSizeV / 2 && (x + radarX) > -width * pixSizeV / 2 + && (y + radarY) < height * pixSizeH / 2 && (y + radarY) > -height * pixSizeH / 2) + { + // Draw the 'blip' + iV_DrawImage(IntImages, imageID, x + radarX, y + radarY, modelViewProjection); + } } } if (audio_GetPreviousQueueTrackRadarBlipPos(&x, &y)) diff --git a/src/message.cpp b/src/message.cpp index 1d044f37221..605382cb7ef 100644 --- a/src/message.cpp +++ b/src/message.cpp @@ -51,7 +51,7 @@ static int currentNumProxDisplays = 0; MESSAGE *apsMessages[MAX_PLAYERS]; /* The list of proximity displays allocated */ -PROXIMITY_DISPLAY *apsProxDisp[MAX_PLAYERS]; +PerPlayerProximityDisplayLists apsProxDisp; /* The IMD to use for the proximity messages */ iIMDBaseShape *pProximityMsgIMD; @@ -242,7 +242,7 @@ bool messageInitVars() for (i = 0; i < MAX_PLAYERS; i++) { apsMessages[i] = nullptr; - apsProxDisp[i] = nullptr; + apsProxDisp[i].clear(); } pProximityMsgIMD = nullptr; @@ -305,8 +305,7 @@ static void addProximityDisplay(MESSAGE *psMessage, bool proxPos, UDWORD player) // Now add it to the top of the list. Be aware that this // check means that messages and proximity displays can // become out of sync - but this should never happen. - psToAdd->psNext = apsProxDisp[player]; - apsProxDisp[player] = psToAdd; + apsProxDisp[player].emplace_front(psToAdd); currentNumProxDisplays++; } else @@ -343,41 +342,25 @@ MESSAGE *addMessage(MESSAGE_TYPE msgType, bool proxPos, UDWORD player) /* remove a proximity display */ static void removeProxDisp(MESSAGE *psMessage, UDWORD player) { - PROXIMITY_DISPLAY *psCurr, *psPrev; - ASSERT_OR_RETURN(, player < MAX_PLAYERS, "Bad player"); ASSERT_OR_RETURN(, psMessage != nullptr, "Bad message"); - if (!apsProxDisp[player]) + if (apsProxDisp[player].empty()) { return; // no corresponding proximity display } //find the proximity display for this message - if (apsProxDisp[player]->psMessage == psMessage) + auto it = std::find_if(apsProxDisp[player].begin(), apsProxDisp[player].end(), [psMessage](PROXIMITY_DISPLAY* psCurr) { - psCurr = apsProxDisp[player]; - - apsProxDisp[player] = apsProxDisp[player]->psNext; - intRemoveProximityButton(psCurr); - delete psCurr; - } - else + return psCurr->psMessage == psMessage; + }); + if (it != apsProxDisp[player].end()) { - psPrev = apsProxDisp[player]; - for (psCurr = apsProxDisp[player]; psCurr != nullptr; psCurr = - psCurr->psNext) - { - //compare the pointers - if (psCurr->psMessage == psMessage) - { - psPrev->psNext = psCurr->psNext; - intRemoveProximityButton(psCurr); - delete psCurr; - break; - } - psPrev = psCurr; - } + PROXIMITY_DISPLAY* psDisp = *it; + apsProxDisp[player].erase(it); + intRemoveProximityButton(psDisp); + delete psDisp; } } @@ -406,20 +389,19 @@ void freeMessages() /* removes all the proximity displays */ void releaseAllProxDisp() { - UDWORD player; - PROXIMITY_DISPLAY *psCurr, *psNext; bool removedAMessage = false; - for (player = 0; player < MAX_PLAYERS; player++) + for (size_t player = 0, end = apsProxDisp.size(); player < end; ++player) { - for (psCurr = apsProxDisp[player]; psCurr != nullptr; psCurr = psNext) + mutating_list_iterate(apsProxDisp[player], [&removedAMessage, player](PROXIMITY_DISPLAY* psCurr) { - psNext = psCurr->psNext; //remove message associated with this display removeMessage(psCurr->psMessage, player); removedAMessage = true; - } - apsProxDisp[player] = nullptr; + + return IterationResult::CONTINUE_ITERATION; + }); + apsProxDisp[player].clear(); } //re-initialise variables currentNumProxDisplays = 0; diff --git a/src/message.h b/src/message.h index e5cb0dcd03e..7119d7d6822 100644 --- a/src/message.h +++ b/src/message.h @@ -27,6 +27,7 @@ #include "structure.h" #include "messagedef.h" #include "lib/framework/wzstring.h" +#include "objmem.h" #define NO_AUDIO_MSG -1 @@ -37,7 +38,9 @@ extern MESSAGE *apsMessages[MAX_PLAYERS]; extern iIMDBaseShape *pProximityMsgIMD; /** The list of proximity displays allocated. */ -extern PROXIMITY_DISPLAY *apsProxDisp[MAX_PLAYERS]; +using PerPlayerProximityDisplayLists = PerPlayerObjectLists; +using ProximityDisplayList = typename PerPlayerProximityDisplayLists::value_type; +extern PerPlayerProximityDisplayLists apsProxDisp; extern bool releaseObjectives; diff --git a/src/messagedef.h b/src/messagedef.h index 5e09422bc5e..5dfeee52385 100644 --- a/src/messagedef.h +++ b/src/messagedef.h @@ -138,7 +138,6 @@ struct PROXIMITY_DISPLAY : public OBJECT_POSITION UDWORD timeLastDrawn = 0; // stores the time the 'button' was last drawn for animation UDWORD strobe = 0; // id of image last used UDWORD buttonID = 0; // id of the button for the interface - PROXIMITY_DISPLAY *psNext = nullptr; // pointer to the next in the list }; #endif // __INCLUDED_MESSAGEDEF_H__ From f0432a76d45c348b01b87b684f2b9ce0c127b04a Mon Sep 17 00:00:00 2001 From: Pavel Solodovnikov Date: Tue, 2 Jan 2024 21:44:58 +0300 Subject: [PATCH 2/6] Remove unused `psNext` pointer in `FLAG_POSITION` struct Signed-off-by: Pavel Solodovnikov --- src/hci.cpp | 1 - src/structuredef.h | 1 - 2 files changed, 2 deletions(-) diff --git a/src/hci.cpp b/src/hci.cpp index 8bb1c356eb9..0dca5079309 100644 --- a/src/hci.cpp +++ b/src/hci.cpp @@ -1300,7 +1300,6 @@ static void intProcessEditStats(UDWORD id) debugMenuDroidDeliveryPoint.factoryInc = 0; debugMenuDroidDeliveryPoint.player = selectedPlayer; debugMenuDroidDeliveryPoint.selected = false; - debugMenuDroidDeliveryPoint.psNext = nullptr; startDeliveryPosition(&debugMenuDroidDeliveryPoint); } else diff --git a/src/structuredef.h b/src/structuredef.h index 81119cfeb05..c1fe9ac5bf5 100644 --- a/src/structuredef.h +++ b/src/structuredef.h @@ -70,7 +70,6 @@ struct FLAG_POSITION : public OBJECT_POSITION Vector3i coords = Vector3i(0, 0, 0); //the world coords of the Position UBYTE factoryInc; //indicates whether the first, second etc factory UBYTE factoryType; //indicates whether standard, cyborg or vtol factory - FLAG_POSITION *psNext; }; enum STRUCT_STRENGTH From 5d7cc8989190557dd2a67b6ad4dc3c49dc597ad1 Mon Sep 17 00:00:00 2001 From: Pavel Solodovnikov Date: Wed, 3 Jan 2024 16:33:38 +0300 Subject: [PATCH 3/6] Switch `apsMessages` and `asFeatureStats` to `std::list` and `std::vector`, respectively Signed-off-by: Pavel Solodovnikov --- src/feature.cpp | 63 ++++++++---------- src/feature.h | 3 +- src/game.cpp | 23 ++++--- src/hci.cpp | 6 +- src/intelmap.cpp | 22 +++---- src/message.cpp | 150 +++++++++++------------------------------- src/message.h | 6 +- src/messagedef.h | 2 - src/multigifts.cpp | 7 +- src/multiplay.cpp | 2 +- src/wzscriptdebug.cpp | 2 +- 11 files changed, 100 insertions(+), 186 deletions(-) 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"); From e408010fa97917b25c94f8cfcac1380b4d386ebc Mon Sep 17 00:00:00 2001 From: Pavel Solodovnikov Date: Sat, 6 Jan 2024 22:38:12 +0300 Subject: [PATCH 4/6] objmem.h: Check return type of handler lambda in `mutating_list_iterate` Signed-off-by: Pavel Solodovnikov --- src/objmem.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/objmem.h b/src/objmem.h index f452e068925..614c8a3a646 100644 --- a/src/objmem.h +++ b/src/objmem.h @@ -29,6 +29,7 @@ #include #include #include +#include /* The lists of objects allocated */ template @@ -166,6 +167,9 @@ enum class IterationResult template void mutating_list_iterate(std::list& list, MaybeErasingLoopBodyHandler handler) { + static_assert(std::is_same, IterationResult>::value, + "Loop body handler should return IterationResult"); + typename std::remove_reference_t::iterator it = list.begin(), itNext; while (it != list.end()) { From 130d0c33a262d4055fb27f68bb2c34a4b7741295 Mon Sep 17 00:00:00 2001 From: Pavel Solodovnikov Date: Sun, 7 Jan 2024 02:36:20 +0300 Subject: [PATCH 5/6] Use `mutating_list_iterate` more for droid/structure lists Replace while-based loops introduced by https://github.com/Warzone2100/warzone2100/pull/3572 with `mutating_list_iterate`. Signed-off-by: Pavel Solodovnikov --- src/game.cpp | 13 +-- src/keybind.cpp | 24 +++-- src/loop.cpp | 46 ++++----- src/mission.cpp | 239 ++++++++++++++++++--------------------------- src/multijoin.cpp | 76 ++++++-------- src/multilimit.cpp | 12 +-- src/multiplay.cpp | 36 +++---- 7 files changed, 177 insertions(+), 269 deletions(-) diff --git a/src/game.cpp b/src/game.cpp index 2141a27733c..44b1f05c147 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -5330,18 +5330,16 @@ static bool loadSaveDroidPointers(const WzString &pFileName, PerPlayerDroidLists continue; // special hack for campaign missions, cannot have targets } - DroidList::iterator droidIt = (*ppsCurrentDroidLists)[player].begin(), droidItNext; - while (droidIt != (*ppsCurrentDroidLists)[player].end()) + for (DROID* d : (*ppsCurrentDroidLists)[player]) { - droidItNext = std::next(droidIt); - psDroid = *droidIt; - if (psDroid->id == id) + if (d->id == id) { + psDroid = d; break; } - if (isTransporter(psDroid) && psDroid->psGroup != nullptr) // Check for droids in the transporter. + if (isTransporter(d) && d->psGroup != nullptr) // Check for droids in the transporter. { - for (DROID *psTrDroid : psDroid->psGroup->psList) + for (DROID *psTrDroid : d->psGroup->psList) { if (psTrDroid->id == id) { @@ -5350,7 +5348,6 @@ static bool loadSaveDroidPointers(const WzString &pFileName, PerPlayerDroidLists } } } - droidIt = droidItNext; } foundDroid: if (!psDroid) diff --git a/src/keybind.cpp b/src/keybind.cpp index 920ffe7c186..de6a210560d 100644 --- a/src/keybind.cpp +++ b/src/keybind.cpp @@ -385,13 +385,11 @@ void kf_CloneSelected(int limit) return; // no-op } - DroidList::iterator droidIt = apsDroidLists[selectedPlayer].begin(), droidItNext; - while (droidIt != apsDroidLists[selectedPlayer].end()) + mutating_list_iterate(apsDroidLists[selectedPlayer], [limit, &sTemplate](DROID* d) { - droidItNext = std::next(droidIt); - if ((*droidIt)->selected) + if (d->selected) { - enumerateTemplates(selectedPlayer, [psDroid = *droidIt, &sTemplate](DROID_TEMPLATE * psTempl) { + enumerateTemplates(selectedPlayer, [psDroid = d, &sTemplate](DROID_TEMPLATE* psTempl) { if (psTempl->name.compare(psDroid->aName) == 0) { sTemplate = psTempl; @@ -402,15 +400,15 @@ void kf_CloneSelected(int limit) if (!sTemplate) { - debug(LOG_ERROR, "Cloning vat has been destroyed. We can't find the template for this droid: %s, id:%u, type:%d!", (*droidIt)->aName, (*droidIt)->id, (*droidIt)->droidType); - return; + debug(LOG_ERROR, "Cloning vat has been destroyed. We can't find the template for this droid: %s, id:%u, type:%d!", d->aName, d->id, d->droidType); + return IterationResult::BREAK_ITERATION; } // create a new droid army for (int i = 0; i < limit; i++) { - Vector2i pos = (*droidIt)->pos.xy() + iSinCosR(40503 * i, iSqrt(50 * 50 * (i + 1))); // 40503 = 65536/φ (A bit more than a right angle) - DROID *psNewDroid = buildDroid(sTemplate, pos.x, pos.y, (*droidIt)->player, false, nullptr); + Vector2i pos = d->pos.xy() + iSinCosR(40503 * i, iSqrt(50 * 50 * (i + 1))); // 40503 = 65536/φ (A bit more than a right angle) + DROID* psNewDroid = buildDroid(sTemplate, pos.x, pos.y, d->player, false, nullptr); if (psNewDroid) { addDroid(psNewDroid, apsDroidLists); @@ -421,15 +419,15 @@ void kf_CloneSelected(int limit) debug(LOG_ERROR, "Cloning has failed for template:%s id:%d", getID(sTemplate), sTemplate->multiPlayerID); } } - std::string msg = astringf(_("Player %u is cheating a new droid army of: %d × %s."), selectedPlayer, limit, (*droidIt)->aName); + std::string msg = astringf(_("Player %u is cheating a new droid army of: %d × %s."), selectedPlayer, limit, d->aName); sendInGameSystemMessage(msg.c_str()); Cheated = true; audio_PlayTrack(ID_SOUND_NEXUS_LAUGH1); - return; + return IterationResult::BREAK_ITERATION; } debug(LOG_INFO, "Nothing was selected?"); - droidIt = droidItNext; - } + return IterationResult::CONTINUE_ITERATION; + }); } void kf_MakeMeHero() diff --git a/src/loop.cpp b/src/loop.cpp index bd1ebb7f80b..8297ca2f4d8 100644 --- a/src/loop.cpp +++ b/src/loop.cpp @@ -542,40 +542,28 @@ static void gameStateUpdate() //update the current power available for a player updatePlayerPower(i); - DroidList::iterator droidIt = apsDroidLists[i].begin(), droidItNext; - while (droidIt != apsDroidLists[i].end()) + mutating_list_iterate(apsDroidLists[i], [](DROID* d) { - // Copy the next pointer - not 100% sure if the droid could get destroyed but this covers us anyway - droidItNext = std::next(droidIt); - droidUpdate(*droidIt); - droidIt = droidItNext; - } - - droidIt = mission.apsDroidLists[i].begin(); - while (droidIt != mission.apsDroidLists[i].end()) + droidUpdate(d); + return IterationResult::CONTINUE_ITERATION; + }); + mutating_list_iterate(mission.apsDroidLists[i], [](DROID* d) { - /* Copy the next pointer - not 100% sure if the droid could - get destroyed but this covers us anyway */ - droidItNext = std::next(droidIt); - missionDroidUpdate(*droidIt); - droidIt = droidItNext; - } + missionDroidUpdate(d); + return IterationResult::CONTINUE_ITERATION; + }); - // FIXME: These for-loops are code duplicationo - StructureList::iterator structIt = apsStructLists[i].begin(), structItNext; - while (structIt != apsStructLists[i].end()) + // FIXME: These for-loops are code duplication + mutating_list_iterate(apsStructLists[i], [](STRUCTURE* s) { - structItNext = std::next(structIt); - structureUpdate(*structIt, false); - structIt = structItNext; - } - structIt = mission.apsStructLists[i].begin(); - while (structIt != mission.apsStructLists[i].end()) + structureUpdate(s, false); + return IterationResult::CONTINUE_ITERATION; + }); + mutating_list_iterate(mission.apsStructLists[i], [](STRUCTURE* s) { - structItNext = std::next(structIt); - structureUpdate(*structIt, true); // update for mission - structIt = structItNext; - } + structureUpdate(s, true); // update for mission + return IterationResult::CONTINUE_ITERATION; + }); } missionTimerUpdate(); diff --git a/src/mission.cpp b/src/mission.cpp index eb6b5276d53..8818d70a37b 100644 --- a/src/mission.cpp +++ b/src/mission.cpp @@ -580,7 +580,7 @@ void addTransporterTimerInterface() void missionFlyTransportersIn(SDWORD iPlayer, bool bTrackTransporter) { UWORD iX, iY, iZ; - SDWORD iLandX, iLandY, iDx, iDy; + SDWORD iLandX, iLandY; ASSERT_OR_RETURN(, iPlayer < MAX_PLAYERS, "Flying nonexistent player %d's transporters in", iPlayer); @@ -590,11 +590,9 @@ void missionFlyTransportersIn(SDWORD iPlayer, bool bTrackTransporter) iZ = (UWORD)(map_Height(iX, iY) + OFFSCREEN_HEIGHT); //get the droids for the mission - DroidList::iterator droidIt = mission.apsDroidLists[iPlayer].begin(), droidItNext; - while (droidIt != mission.apsDroidLists[iPlayer].end()) + mutating_list_iterate(mission.apsDroidLists[iPlayer], [iPlayer, bTrackTransporter, iX, iY, iZ, iLandX, iLandY](DROID* psTransporter) { - droidItNext = std::next(droidIt); - DROID* psTransporter = *droidIt; + SDWORD iDx, iDy; if (psTransporter->droidType == DROID_SUPERTRANSPORTER) { @@ -647,18 +645,17 @@ void missionFlyTransportersIn(SDWORD iPlayer, bool bTrackTransporter) audio_PlayObjDynamicTrack(psTransporter, ID_SOUND_BLIMP_FLIGHT, moveCheckDroidMovingAndVisible); //only want to fly one transporter in at a time now - AB 14/01/99 - break; + return IterationResult::BREAK_ITERATION; } } - droidIt = droidItNext; - } + return IterationResult::CONTINUE_ITERATION; + }); } /* Saves the necessary data when moving from a home base Mission to an OffWorld mission */ static void saveMissionData() { UDWORD inc; - STRUCTURE *psStructBeingBuilt; bool bRepairExists; debug(LOG_SAVE, "called"); @@ -670,18 +667,16 @@ static void saveMissionData() bRepairExists = false; //set any structures currently being built to completed for the selected player - StructureList::iterator structIt = apsStructLists[selectedPlayer].begin(), structItNext; - while (structIt != apsStructLists[selectedPlayer].end()) + mutating_list_iterate(apsStructLists[selectedPlayer], [&bRepairExists](STRUCTURE* psStruct) { - structItNext = std::next(structIt); - STRUCTURE* psStruct = *structIt; + STRUCTURE* psStructBeingBuilt; if (psStruct->status == SS_BEING_BUILT) { //find a droid working on it for (const DROID* psDroid : apsDroidLists[selectedPlayer]) { - if ((psStructBeingBuilt = (STRUCTURE *)orderStateObj(psDroid, DORDER_BUILD)) - && psStructBeingBuilt == psStruct) + if ((psStructBeingBuilt = (STRUCTURE*)orderStateObj(psDroid, DORDER_BUILD)) + && psStructBeingBuilt == psStruct) { // just give it all its build points structureBuild(psStruct, nullptr, structureBuildPointsToCompletion(*psStruct)); @@ -695,8 +690,8 @@ static void saveMissionData() { bRepairExists = true; } - structIt = structItNext; - } + return IterationResult::CONTINUE_ITERATION; + }); //repair all droids back at home base if have a repair facility if (bRepairExists) @@ -713,6 +708,7 @@ static void saveMissionData() //clear droid orders for all droids except constructors still building for (DROID* psDroid : apsDroidLists[selectedPlayer]) { + STRUCTURE* psStructBeingBuilt; if ((psStructBeingBuilt = (STRUCTURE *)orderStateObj(psDroid, DORDER_BUILD))) { if (psStructBeingBuilt->status == SS_BUILT) @@ -882,17 +878,14 @@ void saveMissionLimboData() processPreviousCampDroids(); // move droids properly - does all the clean up code - DroidList::iterator psDroid = apsDroidLists[selectedPlayer].begin(), psNext; - while (psDroid != apsDroidLists[selectedPlayer].end()) + mutating_list_iterate(apsDroidLists[selectedPlayer], [](DROID* psDroid) { - psNext = std::next(psDroid); - DROID* psDroidRaw = *psDroid; - if (droidRemove(psDroidRaw, apsDroidLists)) + if (droidRemove(psDroid, apsDroidLists)) { - addDroid(psDroidRaw, mission.apsDroidLists); + addDroid(psDroid, mission.apsDroidLists); } - psDroid = psNext; - } + return IterationResult::CONTINUE_ITERATION; + }); apsDroidLists[selectedPlayer].clear(); // any selectedPlayer's factories/research need to be put on holdProduction/holdresearch @@ -912,19 +905,16 @@ void saveMissionLimboData() //this is called via a script function to place the Limbo droids once the mission has started void placeLimboDroids() { - UDWORD droidX, droidY; - PICKTILE pickRes; - debug(LOG_SAVE, "called"); ASSERT(selectedPlayer < MAX_PLAYERS, "selectedPlayer %" PRIu32 " exceeds MAX_PLAYERS", selectedPlayer); // Copy the droids across for the selected Player - DroidList::iterator droidIt = apsLimboDroids[selectedPlayer].begin(), droidItNext; - while (droidIt != apsLimboDroids[selectedPlayer].end()) + mutating_list_iterate(apsLimboDroids[selectedPlayer], [](DROID* psDroid) { - droidItNext = std::next(droidIt); - DROID* psDroid = *droidIt; + UDWORD droidX, droidY; + PICKTILE pickRes; + if (droidRemove(psDroid, apsLimboDroids)) { addDroid(psDroid, apsDroidLists); @@ -932,7 +922,7 @@ void placeLimboDroids() if (isTransporter(psDroid)) { vanishDroid(psDroid); - continue; + return IterationResult::CONTINUE_ITERATION; } //set up location for each of the droids droidX = map_coord(getLandingX(LIMBO_LANDING)); @@ -959,8 +949,8 @@ void placeLimboDroids() { ASSERT(false, "placeLimboUnits: Unable to remove unit from Limbo list"); } - droidIt = droidItNext; - } + return IterationResult::CONTINUE_ITERATION; + }); } /*restores the necessary data on completion of a Limbo Expand mission*/ @@ -972,11 +962,8 @@ void restoreMissionLimboData() /*the droids stored in the mission droid list need to be added back into the current droid list*/ - DroidList::iterator droidIt = mission.apsDroidLists[selectedPlayer].begin(), droidItNext; - while (droidIt != mission.apsDroidLists[selectedPlayer].end()) + mutating_list_iterate(mission.apsDroidLists[selectedPlayer], [](DROID* psDroid) { - droidItNext = std::next(droidIt); - DROID* psDroid = *droidIt; //remove out of stored list and add to current Droid list if (droidRemove(psDroid, mission.apsDroidLists)) { @@ -985,8 +972,8 @@ void restoreMissionLimboData() orderDroid(psDroid, DORDER_STOP, ModeImmediate); //the location of the droid should be valid! } - droidIt = droidItNext; - } + return IterationResult::CONTINUE_ITERATION; + }); ASSERT(mission.apsDroidLists[selectedPlayer].empty(), "list should be empty"); } @@ -1002,15 +989,12 @@ void saveCampaignData() if (getDroidsToSafetyFlag()) { // Move any Transporters into the mission list - DroidList::iterator droidIt = apsDroidLists[selectedPlayer].begin(), droidItNext; - while (droidIt != apsDroidLists[selectedPlayer].end()) + mutating_list_iterate(apsDroidLists[selectedPlayer], [](DROID* psDroid) { - droidItNext = std::next(droidIt); - DROID* psDroid = *droidIt; if (isTransporter(psDroid)) { // Empty the transporter into the mission list - ASSERT_OR_RETURN(, psDroid->psGroup != nullptr, "Transporter does not have a group"); + ASSERT_OR_RETURN(IterationResult::CONTINUE_ITERATION, psDroid->psGroup != nullptr, "Transporter does not have a group"); mutating_list_iterate(psDroid->psGroup->psList, [psDroid](DROID* psCurr) { @@ -1037,8 +1021,8 @@ void saveCampaignData() addDroid(psDroid, mission.apsDroidLists); } } - droidIt = droidItNext; - } + return IterationResult::CONTINUE_ITERATION; + }); } else { @@ -1061,19 +1045,13 @@ void saveCampaignData() mission.apsDroidLists[selectedPlayer].reverse(); //find the *first* transporter - DroidList::iterator droidIt = mission.apsDroidLists[selectedPlayer].begin(), droidItNext; - while (droidIt != mission.apsDroidLists[selectedPlayer].end()) + mutating_list_iterate(mission.apsDroidLists[selectedPlayer], [](DROID* psDroid) { - droidItNext = std::next(droidIt); - DROID* psDroid = *droidIt; if (isTransporter(psDroid)) { //fill it with droids from the mission list - DroidList::iterator safeDroidIt = mission.apsDroidLists[selectedPlayer].begin(), safeDroidItNext; - while (safeDroidIt != mission.apsDroidLists[selectedPlayer].end()) + mutating_list_iterate(mission.apsDroidLists[selectedPlayer], [psDroid](DROID* psSafeDroid) { - safeDroidItNext = std::next(safeDroidIt); - DROID* psSafeDroid = *safeDroidIt; if (psSafeDroid != psDroid) { //add to the Transporter, checking for when full @@ -1086,28 +1064,26 @@ void saveCampaignData() } else { - break; + return IterationResult::BREAK_ITERATION; } } - safeDroidIt = safeDroidItNext; - } + return IterationResult::CONTINUE_ITERATION; + }); //only want to fill one transporter - break; + return IterationResult::BREAK_ITERATION; } - droidIt = droidItNext; - } + return IterationResult::CONTINUE_ITERATION; + }); } //clear all other droids for (int inc = 0; inc < MAX_PLAYERS; inc++) { - DroidList::iterator droidIt = apsDroidLists[inc].begin(), droidItNext; - while (droidIt != apsDroidLists[inc].end()) + mutating_list_iterate(apsDroidLists[inc], [](DROID* d) { - droidItNext = std::next(droidIt); - vanishDroid(*droidIt); - droidIt = droidItNext; - } + vanishDroid(d); + return IterationResult::CONTINUE_ITERATION; + }); } //clear out the audio @@ -1259,21 +1235,17 @@ static void clearCampaignUnits() /*This deals with droids at the end of an offworld mission*/ static void processMission() { - UDWORD droidX, droidY; - PICKTILE pickRes; - ASSERT(selectedPlayer < MAX_PLAYERS, "selectedPlayer %" PRIu32 " exceeds MAX_PLAYERS", selectedPlayer); //and the rest on the mission map - for now? - DroidList::iterator droidIt = apsDroidLists[selectedPlayer].begin(), droidItNext; - while (droidIt != apsDroidLists[selectedPlayer].end()) + mutating_list_iterate(apsDroidLists[selectedPlayer], [](DROID* psDroid) { - droidItNext = std::next(droidIt); - DROID* psDroid = *droidIt; + UDWORD droidX, droidY; + PICKTILE pickRes; //reset order - do this to all the droids that are returning from offWorld orderDroid(psDroid, DORDER_STOP, ModeImmediate); // clean up visibility - visRemoveVisibility((BASE_OBJECT *)psDroid); + visRemoveVisibility((BASE_OBJECT*)psDroid); //remove out of stored list and add to current Droid list if (droidRemove(psDroid, apsDroidLists)) { @@ -1298,8 +1270,8 @@ static void processMission() // This is mainly for VTOLs setDroidBase(psDroid, nullptr); } - droidIt = droidItNext; - } + return IterationResult::CONTINUE_ITERATION; + }); } @@ -1313,11 +1285,8 @@ void processMissionLimbo() ASSERT(selectedPlayer < MAX_PLAYERS, "selectedPlayer %" PRIu32 " exceeds MAX_PLAYERS", selectedPlayer); //all droids (for selectedPlayer only) are placed into the limbo list - DroidList::iterator droidIt = apsDroidLists[selectedPlayer].begin(), droidItNext; - while (droidIt != apsDroidLists[selectedPlayer].end()) + mutating_list_iterate(apsDroidLists[selectedPlayer], [&numDroidsAddedToLimboList](DROID* psDroid) { - droidItNext = std::next(droidIt); - DROID* psDroid = *droidIt; //KILL OFF TRANSPORTER - should never be one but.... if (isTransporter(psDroid)) { @@ -1345,8 +1314,8 @@ void processMissionLimbo() } } } - droidIt = droidItNext; - } + return IterationResult::CONTINUE_ITERATION; + }); } /*switch the pointers for the map and droid lists so that droid placement @@ -1576,48 +1545,43 @@ static void missionResetDroids() for (unsigned int player = 0; player < MAX_PLAYERS; player++) { - DroidList::iterator droidIt = apsDroidLists[player].begin(), droidItNext; - while (droidIt != apsDroidLists[player].end()) + mutating_list_iterate(apsDroidLists[player], [](DROID* d) { - droidItNext = std::next(droidIt); // Reset order - unless constructor droid that is mid-build - if (((*droidIt)->droidType == DROID_CONSTRUCT - || (*droidIt)->droidType == DROID_CYBORG_CONSTRUCT) - && orderStateObj((*droidIt), DORDER_BUILD)) + if ((d->droidType == DROID_CONSTRUCT + || d->droidType == DROID_CYBORG_CONSTRUCT) + && orderStateObj(d, DORDER_BUILD)) { // Need to set the action time to ignore the previous mission time - (*droidIt)->actionStarted = gameTime; + d->actionStarted = gameTime; } else { - orderDroid(*droidIt, DORDER_STOP, ModeImmediate); + orderDroid(d, DORDER_STOP, ModeImmediate); } //KILL OFF TRANSPORTER - if (isTransporter(*droidIt)) + if (isTransporter(d)) { - vanishDroid(*droidIt); + vanishDroid(d); } - droidIt = droidItNext; - } + return IterationResult::CONTINUE_ITERATION; + }); } - DroidList::iterator droidIt = apsDroidLists[selectedPlayer].begin(), droidItNext; - while (droidIt != apsDroidLists[selectedPlayer].end()) + mutating_list_iterate(apsDroidLists[selectedPlayer], [](DROID* psDroid) { - droidItNext = std::next(droidIt); - DROID* psDroid = *droidIt; bool placed = false; //for all droids that have never left home base if (psDroid->pos.x == INVALID_XY && psDroid->pos.y == INVALID_XY) { - STRUCTURE *psStruct = psDroid->psBaseStruct; - FACTORY *psFactory = nullptr; + STRUCTURE* psStruct = psDroid->psBaseStruct; + FACTORY* psFactory = nullptr; if (psStruct && StructIsFactory(psStruct)) { - psFactory = (FACTORY *)psStruct->pFunctionality; + psFactory = (FACTORY*)psStruct->pFunctionality; } //find a location next to the factory if (psFactory) @@ -1681,13 +1645,13 @@ static void missionResetDroids() // Do all the things in build droid that never did when it was built! // check the droid is a reasonable distance from the edge of the map if (psDroid->pos.x <= world_coord(EDGE_SIZE) || - psDroid->pos.y <= world_coord(EDGE_SIZE) || - psDroid->pos.x >= world_coord(mapWidth - EDGE_SIZE) || - psDroid->pos.y >= world_coord(mapHeight - EDGE_SIZE)) + psDroid->pos.y <= world_coord(EDGE_SIZE) || + psDroid->pos.x >= world_coord(mapWidth - EDGE_SIZE) || + psDroid->pos.y >= world_coord(mapHeight - EDGE_SIZE)) { debug(LOG_ERROR, "missionResetUnits: unit too close to edge of map - removing"); vanishDroid(psDroid); - continue; + return IterationResult::CONTINUE_ITERATION; } // People always stand upright @@ -1705,8 +1669,8 @@ static void missionResetDroids() vanishDroid(psDroid); } } - droidIt = droidItNext; - } + return IterationResult::CONTINUE_ITERATION; + }); } /*unloads the Transporter passed into the mission at the specified x/y @@ -2922,36 +2886,29 @@ void missionDestroyObjects() { // AI player, clear out old data - DroidList::iterator droidIt = apsDroidLists[Player].begin(), droidItNext; - while (droidIt != apsDroidLists[Player].end()) + mutating_list_iterate(apsDroidLists[Player], [](DROID* d) { - droidItNext = std::next(droidIt); - removeDroidBase(*droidIt); - droidIt = droidItNext; - } + removeDroidBase(d); + return IterationResult::CONTINUE_ITERATION; + }); //clear out the mission lists as well to make sure no Transporters exist apsDroidLists[Player] = std::move(mission.apsDroidLists[Player]); - droidIt = apsDroidLists[Player].begin(); - while (droidIt != apsDroidLists[Player].end()) + mutating_list_iterate(apsDroidLists[Player], [](DROID* psDroid) { - droidItNext = std::next(droidIt); - DROID* psDroid = *droidIt; //make sure its died flag is not set since we've swapped the apsDroidList pointers over psDroid->died = false; removeDroidBase(psDroid); - droidIt = droidItNext; - } + return IterationResult::CONTINUE_ITERATION; + }); mission.apsDroidLists[Player].clear(); - StructureList::iterator structIt = apsStructLists[Player].begin(), structItNext; - while (structIt != apsStructLists[Player].end()) + mutating_list_iterate(apsStructLists[Player], [](STRUCTURE* s) { - structItNext = std::next(structIt); - removeStruct(*structIt, true); - structIt = structItNext; - } + removeStruct(s, true); + return IterationResult::CONTINUE_ITERATION; + }); } } @@ -3010,11 +2967,8 @@ void processPreviousCampDroids() // See if any are left if (!mission.apsDroidLists[selectedPlayer].empty()) { - DroidList::iterator droidIt = mission.apsDroidLists[selectedPlayer].begin(), droidItNext; - while (droidIt != mission.apsDroidLists[selectedPlayer].end()) + mutating_list_iterate(mission.apsDroidLists[selectedPlayer], [](DROID* psDroid) { - droidItNext = std::next(droidIt); - DROID* psDroid = *droidIt; // We want to kill off all droids now! - AB 27/01/99 // KILL OFF TRANSPORTER if (droidRemove(psDroid, mission.apsDroidLists)) @@ -3022,8 +2976,8 @@ void processPreviousCampDroids() addDroid(psDroid, apsDroidLists); vanishDroid(psDroid); } - droidIt = droidItNext; - } + return IterationResult::CONTINUE_ITERATION; + }); } } @@ -3231,11 +3185,8 @@ void emptyTransporters(bool bOffWorld) ASSERT_OR_RETURN(, selectedPlayer < MAX_PLAYERS, "selectedPlayer %" PRIu32 " >= MAX_PLAYERS", selectedPlayer); //see if there are any Transporters in the world - DroidList::iterator transIt = apsDroidLists[selectedPlayer].begin(), transItNext; - while (transIt != apsDroidLists[selectedPlayer].end()) + mutating_list_iterate(apsDroidLists[selectedPlayer], [bOffWorld](DROID* psTransporter) { - transItNext = std::next(transIt); - DROID* psTransporter = *transIt; if (isTransporter(psTransporter)) { //if flying in, empty the contents @@ -3286,14 +3237,12 @@ void emptyTransporters(bool bOffWorld) vanishDroid(psTransporter); } } - transIt = transItNext; - } + return IterationResult::CONTINUE_ITERATION; + }); + //deal with any transporters that are waiting to come over - transIt = mission.apsDroidLists[selectedPlayer].begin(); - while (transIt != mission.apsDroidLists[selectedPlayer].end()) + mutating_list_iterate(mission.apsDroidLists[selectedPlayer], [](DROID* psTransporter) { - transItNext = std::next(transIt); - DROID* psTransporter = *transIt; if (isTransporter(psTransporter)) { //for each droid within the transporter... @@ -3312,8 +3261,8 @@ void emptyTransporters(bool bOffWorld) }); } //don't need to destroy the transporter here - it is dealt with by the endMission process - transIt = transItNext; - } + return IterationResult::CONTINUE_ITERATION; + }); } /*bCheating = true == start of cheat diff --git a/src/multijoin.cpp b/src/multijoin.cpp index 31f17bdb9bb..1502448f5ed 100644 --- a/src/multijoin.cpp +++ b/src/multijoin.cpp @@ -134,39 +134,35 @@ void destroyPlayerResources(UDWORD player, bool quietly) } debug(LOG_DEATH, "killing off all droids for player %d", player); - DroidList::iterator droidIt = apsDroidLists[player].begin(), droidItNext; - while (droidIt != apsDroidLists[player].end()) // delete all droids + // delete all droids + mutating_list_iterate(apsDroidLists[player], [quietly](DROID* d) { - droidItNext = std::next(droidIt); if (quietly) // don't show effects { - killDroid(*droidIt); + killDroid(d); } else // show effects { - destroyDroid(*droidIt, gameTime); + destroyDroid(d, gameTime); } - droidIt = droidItNext; - } + return IterationResult::CONTINUE_ITERATION; + }); debug(LOG_DEATH, "killing off all structures for player %d", player); - StructureList::iterator psStructIt = apsStructLists[player].begin(), psNextIt; - while (psStructIt != apsStructLists[player].end()) // delete all structs + // delete all structs + mutating_list_iterate(apsStructLists[player], [quietly](STRUCTURE* psStruct) { - psNextIt = std::next(psStructIt); - // FIXME: look why destroyStruct() doesn't put back the feature like removeStruct() does - if (quietly || (*psStructIt)->pStructureType->type == REF_RESOURCE_EXTRACTOR) // don't show effects + if (quietly || psStruct->pStructureType->type == REF_RESOURCE_EXTRACTOR) // don't show effects { - removeStruct(*psStructIt, true); + removeStruct(psStruct, true); } else // show effects { - destroyStruct(*psStructIt, gameTime); + destroyStruct(psStruct, gameTime); } - - psStructIt = psNextIt; - } + return IterationResult::CONTINUE_ITERATION; + }); return; } @@ -174,27 +170,23 @@ void destroyPlayerResources(UDWORD player, bool quietly) static bool destroyMatchingStructs(UDWORD player, std::function cmp, bool quietly) { bool destroyedAnyStructs = false; - StructureList::iterator psStructIt = apsStructLists[player].begin(), psNextIt; - while (psStructIt != apsStructLists[player].end()) + mutating_list_iterate(apsStructLists[player], [quietly, &cmp, &destroyedAnyStructs](STRUCTURE* psStruct) { - psNextIt = std::next(psStructIt); - - if (cmp(*psStructIt)) + if (cmp(psStruct)) { // FIXME: look why destroyStruct() doesn't put back the feature like removeStruct() does - if (quietly || (*psStructIt)->pStructureType->type == REF_RESOURCE_EXTRACTOR) // don't show effects + if (quietly || psStruct->pStructureType->type == REF_RESOURCE_EXTRACTOR) // don't show effects { - removeStruct(*psStructIt, true); + removeStruct(psStruct, true); } else // show effects { - destroyStruct(*psStructIt, gameTime); + destroyStruct(psStruct, gameTime); } destroyedAnyStructs = true; } - - psStructIt = psNextIt; - } + return IterationResult::CONTINUE_ITERATION; + }); return destroyedAnyStructs; } @@ -261,16 +253,14 @@ bool splitResourcesAmongTeam(UDWORD player) return a.itemsRecv < b.itemsRecv; }); }; - DroidList::iterator droidIt = apsDroidLists[player].begin(), droidItNext; - while (droidIt != apsDroidLists[player].end()) + mutating_list_iterate(apsDroidLists[player], [&droidsGiftedPerTarget, &incrRecvItem](DROID* d) { - droidItNext = std::next(droidIt); bool transferredDroid = false; - if (!isDead(*droidIt)) + if (!isDead(d)) { for (size_t i = 0; i < droidsGiftedPerTarget.size(); ++i) { - if (giftSingleDroid(*droidIt, droidsGiftedPerTarget[i].player, false)) + if (giftSingleDroid(d, droidsGiftedPerTarget[i].player, false)) { transferredDroid = true; incrRecvItem(i); @@ -282,10 +272,10 @@ bool splitResourcesAmongTeam(UDWORD player) if (!transferredDroid) { - destroyDroid(*droidIt, gameTime); + destroyDroid(d, gameTime); } - droidIt = droidItNext; - } + return IterationResult::CONTINUE_ITERATION; + }); auto distributeMatchingStructs = [&](std::function cmp) { @@ -301,19 +291,15 @@ bool splitResourcesAmongTeam(UDWORD player) }); }; - StructureList::iterator psStructIt = apsStructLists[player].begin(), psNextIt; - while (psStructIt != apsStructLists[player].end()) + mutating_list_iterate(apsStructLists[player], [&cmp, &structsGiftedPerTarget, &incrRecvStruct](STRUCTURE* psStruct) { - psNextIt = std::next(psStructIt); - - if (cmp(*psStructIt)) + if (cmp(psStruct)) { - giftSingleStructure(*psStructIt, structsGiftedPerTarget.front().player, false); + giftSingleStructure(psStruct, structsGiftedPerTarget.front().player, false); incrRecvStruct(0); } - - psStructIt = psNextIt; - } + return IterationResult::CONTINUE_ITERATION; + }); }; // Distribute key structures diff --git a/src/multilimit.cpp b/src/multilimit.cpp index d5c9e2df55e..89e027669c7 100644 --- a/src/multilimit.cpp +++ b/src/multilimit.cpp @@ -380,19 +380,15 @@ bool applyLimitSet() { while (asStructureStats[id].curCount[player] > asStructureStats[id].upgrade[player].limit) { - StructureList::iterator structIt = apsStructLists[player].begin(), structItNext; - while (structIt != apsStructLists[player].end()) + mutating_list_iterate(apsStructLists[player], [id](STRUCTURE* psStruct) { - structItNext = std::next(structIt); - STRUCTURE* psStruct = *structIt; if (psStruct->pStructureType->type == asStructureStats[id].type) { removeStruct(psStruct, true); - break; + return IterationResult::BREAK_ITERATION; } - structIt = structItNext; - } - + return IterationResult::CONTINUE_ITERATION; + }); } } } diff --git a/src/multiplay.cpp b/src/multiplay.cpp index 8e821864017..3c4a0419fe3 100644 --- a/src/multiplay.cpp +++ b/src/multiplay.cpp @@ -2431,47 +2431,41 @@ bool makePlayerSpectator(uint32_t playerIndex, bool removeAllStructs, bool quiet // Destroy all droids debug(LOG_DEATH, "killing off all droids for player %d", playerIndex); - DroidList::iterator droidIt = apsDroidLists[playerIndex].begin(), droidItNext; - while (droidIt != apsDroidLists[playerIndex].end()) // delete all droids + mutating_list_iterate(apsDroidLists[playerIndex], [quietly](DROID* d) { - droidItNext = std::next(droidIt); if (quietly) // don't show effects { - killDroid(*droidIt); + killDroid(d); } else // show effects { - destroyDroid(*droidIt, gameTime); + destroyDroid(d, gameTime); } - droidIt = droidItNext; - } + return IterationResult::CONTINUE_ITERATION; + }); // Destroy structs debug(LOG_DEATH, "killing off structures for player %d", playerIndex); - StructureList::iterator psStructIt = apsStructLists[playerIndex].begin(), psNextIt; - while (psStructIt != apsStructLists[playerIndex].end()) // delete structs + mutating_list_iterate(apsStructLists[playerIndex], [quietly, removeAllStructs](STRUCTURE* psStruct) { - psNextIt = std::next(psStructIt); - if (removeAllStructs - || (*psStructIt)->pStructureType->type == REF_POWER_GEN - || (*psStructIt)->pStructureType->type == REF_RESEARCH - || (*psStructIt)->pStructureType->type == REF_COMMAND_CONTROL - || StructIsFactory((*psStructIt))) + || psStruct->pStructureType->type == REF_POWER_GEN + || psStruct->pStructureType->type == REF_RESEARCH + || psStruct->pStructureType->type == REF_COMMAND_CONTROL + || StructIsFactory(psStruct)) { // FIXME: look why destroyStruct() doesn't put back the feature like removeStruct() does - if (quietly || (*psStructIt)->pStructureType->type == REF_RESOURCE_EXTRACTOR) // don't show effects + if (quietly || psStruct->pStructureType->type == REF_RESOURCE_EXTRACTOR) // don't show effects { - removeStruct(*psStructIt, true); + removeStruct(psStruct, true); } else // show effects { - destroyStruct(*psStructIt, gameTime); + destroyStruct(psStruct, gameTime); } } - - psStructIt = psNextIt; - } + return IterationResult::CONTINUE_ITERATION; + }); } if (!quietly) From e06b7d2cec31e48bf6e19aa42b3d6cd033344a74 Mon Sep 17 00:00:00 2001 From: Pavel Solodovnikov Date: Sun, 7 Jan 2024 21:40:52 +0300 Subject: [PATCH 6/6] Use `operator[]` instead of `.at()` for `asFeatureStats` element access Don't use `.at()` method, which performs additional bounds checking in cases where we know upfront that the element exists. Signed-off-by: Pavel Solodovnikov --- src/feature.cpp | 2 +- src/hci.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/feature.cpp b/src/feature.cpp index f14b0318adf..52f2382f4d7 100644 --- a/src/feature.cpp +++ b/src/feature.cpp @@ -73,7 +73,7 @@ bool loadFeatureStats(WzConfig &ini) { ini.beginGroup(list[i]); asFeatureStats.emplace_back(STAT_FEATURE + i); - FEATURE_STATS& p = asFeatureStats.at(i); + FEATURE_STATS& p = asFeatureStats[i]; p.name = ini.string(WzString::fromUtf8("name")); p.id = list[i]; WzString subType = ini.value("type").toWzString(); diff --git a/src/hci.cpp b/src/hci.cpp index 35c7104326b..7b9efeab3e9 100644 --- a/src/hci.cpp +++ b/src/hci.cpp @@ -1272,7 +1272,7 @@ void intOpenDebugMenu(OBJECT_TYPE id) case OBJ_FEATURE: for (unsigned i = 0, end = std::min(asFeatureStats.size(), MAXFEATURES); i < end; ++i) { - apsFeatureList[i] = &asFeatureStats.at(i); + apsFeatureList[i] = &asFeatureStats[i]; } ppsStatsList = (BASE_STATS **)apsFeatureList; intAddDebugStatsForm(ppsStatsList, std::min(asFeatureStats.size(), MAXFEATURES));