diff --git a/src/objmem.cpp b/src/objmem.cpp index 8f04dccfe81..153fcdf4b09 100644 --- a/src/objmem.cpp +++ b/src/objmem.cpp @@ -671,33 +671,59 @@ void addFlagPosition(FLAG_POSITION *psFlagPosToAdd) apsFlagPosLists[psFlagPosToAdd->player] = psFlagPosToAdd; } -/* Remove a Flag Position from the Lists */ -void removeFlagPosition(FLAG_POSITION *psDel) +// Remove it from the list, but don't delete it! +static bool removeFlagPositionFromList(FLAG_POSITION *psRemove) { FLAG_POSITION *psPrev = nullptr, *psCurr; - ASSERT_OR_RETURN(, psDel != nullptr, "Invalid Flag Position pointer"); + ASSERT_OR_RETURN(false, psRemove != nullptr, "Invalid Flag Position pointer"); - if (apsFlagPosLists[psDel->player] == psDel) + if (apsFlagPosLists[psRemove->player] == psRemove) { - apsFlagPosLists[psDel->player] = apsFlagPosLists[psDel->player]->psNext; - free(psDel); + apsFlagPosLists[psRemove->player] = apsFlagPosLists[psRemove->player]->psNext; + return true; } else { - for (psCurr = apsFlagPosLists[psDel->player]; (psCurr != psDel) && - (psCurr != nullptr); psCurr = psCurr->psNext) + for (psCurr = apsFlagPosLists[psRemove->player]; (psCurr != psRemove) && + (psCurr != nullptr); psCurr = psCurr->psNext) { psPrev = psCurr; } if (psCurr != nullptr) { psPrev->psNext = psCurr->psNext; - free(psCurr); + return true; } } + + return false; +} + +/* Remove a Flag Position from the Lists */ +void removeFlagPosition(FLAG_POSITION *psDel) +{ + ASSERT_OR_RETURN(, psDel != nullptr, "Invalid Flag Position pointer"); + + if (removeFlagPositionFromList(psDel)) + { + free(psDel); + } + else + { + ASSERT(false, "Did not find flag position in expected list?"); + } } +/* Transfer a Flag Position to a new player */ +void transferFlagPositionToPlayer(FLAG_POSITION *psFlagPos, UDWORD originalPlayer, UDWORD newPlayer) +{ + ASSERT_OR_RETURN(, psFlagPos != nullptr, "Invalid Flag Position pointer"); + ASSERT(originalPlayer == psFlagPos->player, "Unexpected originalPlayer (%" PRIu32 ") does not match current flagPos->player (%" PRIu32 ")", originalPlayer, psFlagPos->player); + ASSERT(removeFlagPositionFromList(psFlagPos), "Did not find flag position in expected list?"); + psFlagPos->player = newPlayer; + addFlagPosition(psFlagPos); +} // free all flag positions void freeAllFlagPositions() diff --git a/src/objmem.h b/src/objmem.h index a308b830213..9461650e6ce 100644 --- a/src/objmem.h +++ b/src/objmem.h @@ -97,6 +97,8 @@ bool createFlagPosition(FLAG_POSITION **ppsNew, UDWORD player); void addFlagPosition(FLAG_POSITION *psFlagPosToAdd); /* Remove a Flag Position from the Lists */ void removeFlagPosition(FLAG_POSITION *psDel); +/* Transfer a Flag Position to a new player */ +void transferFlagPositionToPlayer(FLAG_POSITION *psFlagPos, UDWORD originalPlayer, UDWORD newPlayer); // free all flag positions void freeAllFlagPositions(); diff --git a/src/structure.cpp b/src/structure.cpp index 628a984a402..5807234b54e 100644 --- a/src/structure.cpp +++ b/src/structure.cpp @@ -2044,6 +2044,124 @@ static bool setFunctionality(STRUCTURE *psBuilding, STRUCTURE_TYPE functionType) return true; } +static bool transferFixupFunctionality(STRUCTURE *psBuilding, STRUCTURE_TYPE functionType, UDWORD priorPlayer) +{ + ASSERT_OR_RETURN(false, psBuilding != nullptr, "Invalid pointer"); + CHECK_STRUCTURE(psBuilding); + + switch (functionType) + { + case REF_FACTORY: + case REF_CYBORG_FACTORY: + case REF_VTOL_FACTORY: + case REF_RESEARCH: + case REF_POWER_GEN: + case REF_RESOURCE_EXTRACTOR: + case REF_REPAIR_FACILITY: + case REF_REARM_PAD: + case REF_WALL: + case REF_GATE: + // Structure should already have functionality + ASSERT_OR_RETURN(false, psBuilding->pFunctionality, "Structure does not already have functionality pointer?"); + break; + + default: + psBuilding->pFunctionality = nullptr; + break; + } + + switch (functionType) + { + case REF_FACTORY: + case REF_CYBORG_FACTORY: + case REF_VTOL_FACTORY: + { + FACTORY *psFactory = &psBuilding->pFunctionality->factory; + + // Reset factoryNumFlag for prior player + auto psAssemblyPoint = psFactory->psAssemblyPoint; + if (psAssemblyPoint != nullptr) + { + if (psAssemblyPoint->factoryInc < factoryNumFlag[priorPlayer][psAssemblyPoint->factoryType].size()) + { + factoryNumFlag[priorPlayer][psAssemblyPoint->factoryType][psAssemblyPoint->factoryInc] = false; + } + + //need to cancel the repositioning of the DP if selectedPlayer and currently moving + if (priorPlayer == selectedPlayer && psAssemblyPoint->selected) + { + cancelDeliveryRepos(); + } + } + + // Transfer / fix-up factory assembly point, and number + transferFlagPositionToPlayer(psFactory->psAssemblyPoint, priorPlayer, psBuilding->player); + + switch (functionType) + { + case REF_FACTORY: + setFlagPositionInc(psBuilding->pFunctionality, psBuilding->player, FACTORY_FLAG); + break; + case REF_CYBORG_FACTORY: + setFlagPositionInc(psBuilding->pFunctionality, psBuilding->player, CYBORG_FLAG); + break; + case REF_VTOL_FACTORY: + setFlagPositionInc(psBuilding->pFunctionality, psBuilding->player, VTOL_FLAG); + break; + default: + ASSERT_OR_RETURN(false, false, "Invalid factory type"); + } + break; + } + case REF_POWER_GEN: + case REF_HQ: + case REF_REARM_PAD: + { + break; + } + case REF_RESOURCE_EXTRACTOR: + { + RES_EXTRACTOR *psResExtracter = &psBuilding->pFunctionality->resourceExtractor; + + // Make the structure inactive + psResExtracter->psPowerGen = nullptr; + break; + } + case REF_REPAIR_FACILITY: + { + REPAIR_FACILITY *psRepairFac = &psBuilding->pFunctionality->repairFacility; + + // POSSIBLE TODO: Do something about the group? (Or can we just keep it?) + + // Reset factoryNumFlag for prior player + auto psAssemblyPoint = psRepairFac->psDeliveryPoint; + if (psAssemblyPoint != nullptr) + { + if (psAssemblyPoint->factoryInc < factoryNumFlag[priorPlayer][psAssemblyPoint->factoryType].size()) + { + factoryNumFlag[priorPlayer][psAssemblyPoint->factoryType][psAssemblyPoint->factoryInc] = false; + } + + //need to cancel the repositioning of the DP if selectedPlayer and currently moving + if (priorPlayer == selectedPlayer && psAssemblyPoint->selected) + { + cancelDeliveryRepos(); + } + } + + // Transfer / fix-up factory assembly point, and number + transferFlagPositionToPlayer(psRepairFac->psDeliveryPoint, priorPlayer, psBuilding->player); + + setFlagPositionInc(psBuilding->pFunctionality, psBuilding->player, REPAIR_FLAG); + break; + } + // Structure types without a FUNCTIONALITY + default: + break; + } + + return true; +} // Set the command droid that factory production should go to void assignFactoryCommandDroid(STRUCTURE *psStruct, DROID *psCommander) @@ -6723,6 +6841,8 @@ STRUCTURE *giftSingleStructure(STRUCTURE *psStructure, UBYTE attackPlayer, bool } } + transferFixupFunctionality(psStructure, psStructure->pStructureType->type, originalPlayer); + if (psStructure->status == SS_BUILT) { buildingComplete(psStructure);