From 6b5215ee8cfe9b46d83d9952fac180a75f015fdd Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Thu, 8 Dec 2022 01:54:25 -0800 Subject: [PATCH 01/81] Initial commit - spawn a transport group and tell it to go somewhere --- Strategic/Map Screen Interface Map.cpp | 20 ++++++++++++ Strategic/Strategic AI.cpp | 42 +++++++++++++++++++++++++- Strategic/Strategic AI.h | 3 +- Strategic/Strategic Movement.h | 1 + Tactical/Interface Dialogue.cpp | 1 + Tactical/interface Dialogue.h | 3 ++ 6 files changed, 68 insertions(+), 2 deletions(-) diff --git a/Strategic/Map Screen Interface Map.cpp b/Strategic/Map Screen Interface Map.cpp index 185549d92..308a1b169 100644 --- a/Strategic/Map Screen Interface Map.cpp +++ b/Strategic/Map Screen Interface Map.cpp @@ -881,6 +881,26 @@ void fillMapColoursForVisitedSectors(INT32(&colorMap)[ MAXIMUM_VALID_Y_COORDINAT pGroup = pGroup->next; } } + + // rftr todo: transport groups + { + const auto targetColor = MAP_SHADE_LT_BLUE; + GROUP* pGroup = gpGroupList; + + while (pGroup) + { + if (pGroup->usGroupTeam == ENEMY_TEAM) + { + const UINT8 intention = pGroup->pEnemyGroup->ubIntention; + if (intention == TRANSPORT ) + { + colorMap[pGroup->ubSectorY-1][pGroup->ubSectorX-1] = targetColor; + } + } + + pGroup = pGroup->next; + } + } } diff --git a/Strategic/Strategic AI.cpp b/Strategic/Strategic AI.cpp index 573493b77..252089549 100644 --- a/Strategic/Strategic AI.cpp +++ b/Strategic/Strategic AI.cpp @@ -1,3 +1,4 @@ +#pragma optimize("",off) #ifdef PRECOMPILEDHEADERS #include "Strategic All.h" #include "GameSettings.h" @@ -2423,6 +2424,13 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Strategic5"); } } } + else if (pGroup->pEnemyGroup->ubIntention == TRANSPORT) + { + // rftr todo: something depending if we're in spawn or at target destination + + + // do we just call ReassignAIGroup or SendGroupToPool to dissolve and remove the group? + } else { //This is a floating group at his final destination... if( pGroup->pEnemyGroup->ubIntention != STAGING && pGroup->pEnemyGroup->ubIntention != REINFORCEMENTS ) @@ -5130,7 +5138,7 @@ void ExecuteStrategicAIAction( UINT16 usActionCode, INT16 sSectorX, INT16 sSecto if ( ubNumSoldiers ) { InitializeGroup(GROUP_TYPE_ATTACK, ubNumSoldiers, grouptroops[0], groupelites[0], grouprobots[0], groupjeeps[0], grouptanks[0], Random(10) < difficultyMod); - totalusedsoldiers += grouptroops[0] + groupelites[0] + grouprobots[0], grouptanks[0] + groupjeeps[0]; + totalusedsoldiers += grouptroops[0] + groupelites[0] + grouprobots[0] + grouptanks[0] + groupjeeps[0]; } pGroup = CreateNewEnemyGroupDepartingFromSector( SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), 0, grouptroops[0], groupelites[0], grouprobots[0], grouptanks[0], groupjeeps[0] ); @@ -5391,6 +5399,38 @@ void ExecuteStrategicAIAction( UINT16 usActionCode, INT16 sSectorX, INT16 sSecto gubNumAwareBattles = zDiffSetting[gGameOptions.ubDifficultyLevel].iNumAwareBattles; break; + case NPC_ACTION_DEPLOY_TRANSPORT_GROUP: + // rftr todo: create a new group in the capital (same as attack/patrol groups) and send it to a friendly town with a mine! + // limitations: max number of transport groups at any given time + // track recent transport group interceptions + // varying transport group quality/compositions +//void ExecuteStrategicAIAction( UINT16 usActionCode, INT16 sSectorX, INT16 sSectorY, +// INT32 option1, INT32 option2 ) + // copied from NPC_ACTION_SEND_SOLDIERS_TO_BATTLE_LOCATION, which happens after the first non-welcome wagon battle + // rftr todo: replace this with townid + ubSectorID = (UINT8)STRATEGIC_INDEX_TO_SECTOR_INFO( sWorldSectorLocationOfFirstBattle ); + pSector = &SectorInfo[ ubSectorID ]; + + // rftr: adjust group size and composition based on recent interceptions, game progress, etc + ubNumSoldiers = 17; + + //InitializeGroup(GROUP_TYPE_TRANSPORT, ubNumSoldiers, grouptroops[0], groupelites[0], grouprobots[0], groupjeeps[0], grouptanks[0], Random(10) < difficultyMod); + //totalusedsoldiers += grouptroops[0] + groupelites[0] + grouprobots[0] + grouptanks[0] + groupjeeps[0]; + + //pGroup = CreateNewEnemyGroupDepartingFromSector( SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), 0, grouptroops[0], groupelites[0], grouprobots[0], grouptanks[0], groupjeeps[0] ); + pGroup = CreateNewEnemyGroupDepartingFromSector( SEC_D5, 10, 5, 1, 0, 0, 1 ); + + //Madd: unlimited reinforcements? + if ( !gfUnlimitedTroops ) + { + giReinforcementPool -= ubNumSoldiers; + + giReinforcementPool = max( giReinforcementPool, 0 ); + } + + MoveSAIGroupToSector( &pGroup, ubSectorID, EVASIVE, TRANSPORT ); + break; + default: ScreenMsg( FONT_RED, MSG_DEBUG, L"QueenAI failed to handle action code %d.", usActionCode ); break; diff --git a/Strategic/Strategic AI.h b/Strategic/Strategic AI.h index 77d9c3a62..14fd3581f 100644 --- a/Strategic/Strategic AI.h +++ b/Strategic/Strategic AI.h @@ -78,7 +78,8 @@ BOOLEAN PermittedToFillPatrolGroup( INT32 iPatrolID ); enum GROUP_TYPE { GROUP_TYPE_ATTACK, - GROUP_TYPE_PATROL + GROUP_TYPE_PATROL, + GROUP_TYPE_TRANSPORT }; void ASDInitializePatrolGroup(GROUP *pGroup); diff --git a/Strategic/Strategic Movement.h b/Strategic/Strategic Movement.h index d8bdfacd1..5a117bf8c 100644 --- a/Strategic/Strategic Movement.h +++ b/Strategic/Strategic Movement.h @@ -15,6 +15,7 @@ enum //enemy intentions, PATROL, //enemy is moving around determining safe areas. REINFORCEMENTS, //enemy group has intentions to fortify position at final destination. ASSAULT, //enemy is ready to fight anything they encounter. + TRANSPORT, //rftr: enemy is carrying out non-combat tasks, but still has an escort NUM_ENEMY_INTENTIONS }; diff --git a/Tactical/Interface Dialogue.cpp b/Tactical/Interface Dialogue.cpp index 9644aab34..af6902ea8 100644 --- a/Tactical/Interface Dialogue.cpp +++ b/Tactical/Interface Dialogue.cpp @@ -3595,6 +3595,7 @@ void HandleNPCDoAction( UINT8 ubTargetNPC, UINT16 usActionCode, UINT8 ubQuoteNum case NPC_ACTION_SEND_SOLDIERS_TO_BALIME: case NPC_ACTION_GLOBAL_OFFENSIVE_1: case NPC_ACTION_GLOBAL_OFFENSIVE_2: + case NPC_ACTION_DEPLOY_TRANSPORT_GROUP: break; case NPC_ACTION_TRIGGER_QUEEN_BY_SAM_SITES_CONTROLLED: diff --git a/Tactical/interface Dialogue.h b/Tactical/interface Dialogue.h index 2ddc0605d..4b3d1b759 100644 --- a/Tactical/interface Dialogue.h +++ b/Tactical/interface Dialogue.h @@ -387,6 +387,9 @@ enum NPC_ACTION_GLOBAL_OFFENSIVE_1, NPC_ACTION_GLOBAL_OFFENSIVE_2, + + // rftr: transport groups + NPC_ACTION_DEPLOY_TRANSPORT_GROUP, NPC_ACTION_RECRUIT_PROFILE_TO_EPC = 700, NPC_ACTION_UNRECRUIT_EPC = 701, From 81530b522cd91b00ce2b4b8bb147eb46009bc302 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Thu, 8 Dec 2022 10:51:38 -0800 Subject: [PATCH 02/81] Update movement logic: - return home after reaching destination - dissolve group after reaching home - move slower than normal --- Strategic/Strategic AI.cpp | 10 ++++++++++ Strategic/Strategic Movement.cpp | 5 ++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Strategic/Strategic AI.cpp b/Strategic/Strategic AI.cpp index 252089549..5d0b22052 100644 --- a/Strategic/Strategic AI.cpp +++ b/Strategic/Strategic AI.cpp @@ -2428,6 +2428,16 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Strategic5"); { // rftr todo: something depending if we're in spawn or at target destination + // just arrived, let's go home + if (pGroup->ubSectorX != gModSettings.ubSAISpawnSectorX && pGroup->ubSectorY != gModSettings.ubSAISpawnSectorY) + { + pGroup->ubSectorIDOfLastReassignment = (UINT8)SECTOR( pGroup->ubSectorX, pGroup->ubSectorY ); + MoveSAIGroupToSector( &pGroup, SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), EVASIVE, TRANSPORT ); + } + else + { + SendGroupToPool(&pGroup); + } // do we just call ReassignAIGroup or SendGroupToPool to dissolve and remove the group? } diff --git a/Strategic/Strategic Movement.cpp b/Strategic/Strategic Movement.cpp index e06685456..3270be1a0 100644 --- a/Strategic/Strategic Movement.cpp +++ b/Strategic/Strategic Movement.cpp @@ -3639,7 +3639,10 @@ INT32 GetSectorMvtTimeForGroup( UINT8 ubSector, UINT8 ubDirection, GROUP *pGroup dEnemyGeneralsSpeedupFactor = max( 0.75f, dEnemyGeneralsSpeedupFactor - gStrategicStatus.usVIPsLeft * gGameExternalOptions.fEnemyGeneralStrategicMovementSpeedBonus ); } - iBestTraverseTime = dEnemyGeneralsSpeedupFactor * iBestTraverseTime; + // rftr todo: transport groups move slower than normal + const FLOAT transportSpeedFactor = 0.75f; + + iBestTraverseTime = dEnemyGeneralsSpeedupFactor * transportSpeedFactor * iBestTraverseTime; iBestTraverseTime = iBestTraverseTime * (100 + RebelCommand::GetHarriersSpeedPenalty(ubSector)) / 100; } From 8463a390289ce4329f2ab2b4127d5daba83f21be Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Sat, 10 Dec 2022 02:31:27 -0800 Subject: [PATCH 03/81] Randomly generated soldier backpacks go in the backpack slot (for LOBOT) --- Tactical/Inventory Choosing.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Tactical/Inventory Choosing.cpp b/Tactical/Inventory Choosing.cpp index 26212e84c..fe171ffc8 100644 --- a/Tactical/Inventory Choosing.cpp +++ b/Tactical/Inventory Choosing.cpp @@ -2264,7 +2264,15 @@ void ChooseLBEsForSoldierCreateStruct( SOLDIERCREATE_STRUCT *pp, INT8 bLBEClass { CreateItem( usItem, (INT8)(80 + Random( 21 )), &gTempObject ); gTempObject.fFlags |= OBJECT_UNDROPPABLE; - PlaceObjectInSoldierCreateStruct( pp, &gTempObject ); + // put backpacks into the backpack slot for LOBOT + if ((UsingNewInventorySystem()) && (Item[usItem].usItemClass & IC_LBEGEAR) && (LoadBearingEquipment[Item[usItem].ubClassIndex].lbeClass == BACKPACK)) + { + pp->Inv[BPACKPOCKPOS] = gTempObject; + } + else + { + PlaceObjectInSoldierCreateStruct( pp, &gTempObject ); + } } } From 7aa929f187888e071a78f7f614427dcc54c7a310 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Sat, 10 Dec 2022 02:50:47 -0800 Subject: [PATCH 04/81] TEST - modify soldier inventory after being created --- Strategic/Queen Command.cpp | 93 +++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/Strategic/Queen Command.cpp b/Strategic/Queen Command.cpp index 497d71b58..b50ea5502 100644 --- a/Strategic/Queen Command.cpp +++ b/Strategic/Queen Command.cpp @@ -1,3 +1,4 @@ +#pragma optimize("",off) //Queen Command.c #ifdef PRECOMPILEDHEADERS @@ -980,6 +981,16 @@ BOOLEAN PrepareEnemyForSectorBattle() unsigned firstSlot = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID; unsigned lastSlot = gTacticalStatus.Team[ ENEMY_TEAM ].bLastID; unsigned slotsAvailable = lastSlot-firstSlot+1; + + // rftr todo: cache this on game start? + // do some prep + std::vector gasCans; + std::vector firstAidKits; + std::vector medKits; + std::vector toolKits; + std::map> ammoBoxes; // map coolness to ammo vector + std::map> ammoCrates; // map coolness to ammo vector + BOOLEAN needToBuildItemCache = TRUE; while( pGroup && sNumSlots > 0 ) { if ( pGroup->usGroupTeam != OUR_TEAM && !pGroup->fVehicle && @@ -995,6 +1006,41 @@ BOOLEAN PrepareEnemyForSectorBattle() AssertGE((int)slotsAvailable, sNumSlots); + // rftr todo: cache this on game start? + // do some prep + if (pGroup->pEnemyGroup->ubIntention == TRANSPORT && needToBuildItemCache == TRUE) + { + // rftr todo: see if we can replace this with random items. + // requirement: probably a new flag in Items.xml, or something + // add new groups in RandomItem.xml + // the new items will reference the new group in randomitem, eg 23 in Items.xml matches uiIndex 23 in RandomItem.xml + // fallback if no random items found? for mods and stuff (thinking sdo) + needToBuildItemCache = FALSE; + for (UINT16 i = 0; i < MAXITEMS; ++i) + { + if (Item[i].gascan) gasCans.push_back(i); + else if (Item[i].firstaidkit) firstAidKits.push_back(i); + else if (Item[i].medicalkit) medKits.push_back(i); + else if (Item[i].toolkit) toolKits.push_back(i); + else if (Item[i].usItemClass & IC_AMMO) + { + if (Magazine[Item[i].ubClassIndex].ubMagType == AMMO_BOX + || Magazine[Item[i].ubClassIndex].ubMagType == AMMO_CRATE) + { + if ((gGameOptions.fGunNut || !Item[i].biggunlist) + && (gGameOptions.ubGameStyle == STYLE_SCIFI || !Item[i].scifi)) + { + if (Magazine[Item[i].ubClassIndex].ubMagType == AMMO_BOX) + ammoBoxes[Item[i].ubCoolness].push_back(i); + else + ammoCrates[Item[i].ubCoolness].push_back(i); + } + } + } + + } + } + for (unsigned slot = firstSlot; (slot <= lastSlot) && num && sNumSlots; ++slot) { pSoldier = &Menptr[ slot ]; @@ -1092,6 +1138,53 @@ BOOLEAN PrepareEnemyForSectorBattle() } break; } + + if (pGroup->pEnemyGroup->ubIntention == TRANSPORT) + { + // rftr todo: move this into its own function + // adjust soldier inventory for transport groups + + // ideas: + // soldiers have backpacks + kits + ammo box (BONUS: make sure the backpack goes in the backpack slot for lobot compatibility. that might be a fix outside of this feature tho) + // jeeps have ammo crates and/or lots of boxes. reduce bullet count in crate? + + // add ammo to the soldier's inventory! + OBJECTTYPE kit; + CreateItem(ammoBoxes[10][0], (INT8)(90+Random(10)), &kit); + if (FitsInSmallPocket(&kit)) + { + for(INT8 i = SMALLPOCKSTART; i < SMALLPOCKFINAL; i++ ) + { + if( pSoldier->inv[ i ].exists() == false && !(pSoldier->inv[ i ].fFlags & OBJECT_NO_OVERWRITE) ) + { + pSoldier->inv[ i ] = kit; + break; + } + } + } + else + { + for(INT8 i = BIGPOCKSTART; i < BIGPOCKFINAL; i++ ) + { //no space free in small pockets, so put it into a large pocket. + if( pSoldier->inv[ i ].exists() == false && !(pSoldier->inv[ i ].fFlags & OBJECT_NO_OVERWRITE) ) + { + pSoldier->inv[ i ] = kit; + break; + } + } + } + + + // force inventory to be dropped! + for (int i = 0; i < pSoldier->inv.size(); ++i) + { + OBJECTTYPE* item = &pSoldier->inv[i]; + if (item->exists() && Item[item->usItem].defaultundroppable == FALSE) + { + item->fFlags &= ~OBJECT_UNDROPPABLE; + } + } + } } // Flugente: instead of just crashing the game without any explanation to the user, ignore this issue if it still exists. From 3a46f9a619f98f072ab630a9e8405920fca27097 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Sun, 11 Dec 2022 00:50:05 -0800 Subject: [PATCH 05/81] Put group inventory update logic into its own function --- Strategic/Queen Command.cpp | 239 ++++++++++++++++++++++-------------- 1 file changed, 149 insertions(+), 90 deletions(-) diff --git a/Strategic/Queen Command.cpp b/Strategic/Queen Command.cpp index b50ea5502..09dcc0aa7 100644 --- a/Strategic/Queen Command.cpp +++ b/Strategic/Queen Command.cpp @@ -103,6 +103,7 @@ void HandleBloodCatDeaths( SECTORINFO *pSector ); extern void Ensure_RepairedGarrisonGroup( GARRISON_GROUP **ppGarrison, INT32 *pGarraySize ); +void UpdateTransportGroupInventory(std::map> &groupIdToSoldierMap); void ValidateEnemiesHaveWeapons() { @@ -852,11 +853,14 @@ BOOLEAN PrepareEnemyForSectorBattle() //For enemy groups, we fill up the slots until we have none left or all of the groups have been //processed. + // rftr todo: need to do this for reinforcements?? + std::map> groupIdToSoldierMap; // groupId -> soldierclass, count for( pGroup = gpGroupList; pGroup; pGroup = pGroup->next) { if ( pGroup->usGroupTeam == ENEMY_TEAM && !pGroup->fVehicle && pGroup->ubSectorX == gWorldSectorX && pGroup->ubSectorY == gWorldSectorY && !gbWorldSectorZ ) { //Process enemy group in sector. + const BOOLEAN isTransportGroup = pGroup->pEnemyGroup->ubIntention == TRANSPORT; if( sNumSlots > 0 ) { AssertGE(pGroup->pEnemyGroup->ubNumAdmins, pGroup->pEnemyGroup->ubAdminsInBattle); @@ -870,6 +874,9 @@ BOOLEAN PrepareEnemyForSectorBattle() } pGroup->pEnemyGroup->ubAdminsInBattle += ubNumAdmins; ubTotalAdmins += ubNumAdmins; + + if (isTransportGroup) + groupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_ADMINISTRATOR] += ubNumAdmins; } if( sNumSlots > 0 ) { //Add regular army forces. @@ -884,6 +891,9 @@ BOOLEAN PrepareEnemyForSectorBattle() } pGroup->pEnemyGroup->ubTroopsInBattle += ubNumTroops; ubTotalTroops += ubNumTroops; + + if (isTransportGroup) + groupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_ARMY] += ubNumTroops; } if( sNumSlots > 0 ) { //Add elite troops @@ -898,6 +908,9 @@ BOOLEAN PrepareEnemyForSectorBattle() } pGroup->pEnemyGroup->ubElitesInBattle += ubNumElites; ubTotalElites += ubNumElites; + + if (isTransportGroup) + groupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_ELITE] += ubNumElites; } if( sNumSlots > 0 ) { //Add robots @@ -912,6 +925,9 @@ BOOLEAN PrepareEnemyForSectorBattle() } pGroup->pEnemyGroup->ubRobotsInBattle += ubNumRobots; ubTotalRobots += ubNumRobots; + + if (isTransportGroup) + groupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_ROBOT] += ubNumRobots; } if( sNumSlots > 0 ) { //Add tanks @@ -926,6 +942,9 @@ BOOLEAN PrepareEnemyForSectorBattle() } pGroup->pEnemyGroup->ubTanksInBattle += ubNumTanks; ubTotalTanks += ubNumTanks; + + if (isTransportGroup) + groupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_TANK] += ubNumTanks; } if ( sNumSlots > 0 ) { @@ -941,6 +960,9 @@ BOOLEAN PrepareEnemyForSectorBattle() } pGroup->pEnemyGroup->ubJeepsInBattle += ubNumJeeps; ubTotalJeeps += ubNumJeeps; + + if (isTransportGroup) + groupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_JEEP] += ubNumJeeps; } //NOTE: //no provisions for profile troop leader or retreat groups yet. @@ -982,15 +1004,6 @@ BOOLEAN PrepareEnemyForSectorBattle() unsigned lastSlot = gTacticalStatus.Team[ ENEMY_TEAM ].bLastID; unsigned slotsAvailable = lastSlot-firstSlot+1; - // rftr todo: cache this on game start? - // do some prep - std::vector gasCans; - std::vector firstAidKits; - std::vector medKits; - std::vector toolKits; - std::map> ammoBoxes; // map coolness to ammo vector - std::map> ammoCrates; // map coolness to ammo vector - BOOLEAN needToBuildItemCache = TRUE; while( pGroup && sNumSlots > 0 ) { if ( pGroup->usGroupTeam != OUR_TEAM && !pGroup->fVehicle && @@ -1006,41 +1019,6 @@ BOOLEAN PrepareEnemyForSectorBattle() AssertGE((int)slotsAvailable, sNumSlots); - // rftr todo: cache this on game start? - // do some prep - if (pGroup->pEnemyGroup->ubIntention == TRANSPORT && needToBuildItemCache == TRUE) - { - // rftr todo: see if we can replace this with random items. - // requirement: probably a new flag in Items.xml, or something - // add new groups in RandomItem.xml - // the new items will reference the new group in randomitem, eg 23 in Items.xml matches uiIndex 23 in RandomItem.xml - // fallback if no random items found? for mods and stuff (thinking sdo) - needToBuildItemCache = FALSE; - for (UINT16 i = 0; i < MAXITEMS; ++i) - { - if (Item[i].gascan) gasCans.push_back(i); - else if (Item[i].firstaidkit) firstAidKits.push_back(i); - else if (Item[i].medicalkit) medKits.push_back(i); - else if (Item[i].toolkit) toolKits.push_back(i); - else if (Item[i].usItemClass & IC_AMMO) - { - if (Magazine[Item[i].ubClassIndex].ubMagType == AMMO_BOX - || Magazine[Item[i].ubClassIndex].ubMagType == AMMO_CRATE) - { - if ((gGameOptions.fGunNut || !Item[i].biggunlist) - && (gGameOptions.ubGameStyle == STYLE_SCIFI || !Item[i].scifi)) - { - if (Magazine[Item[i].ubClassIndex].ubMagType == AMMO_BOX) - ammoBoxes[Item[i].ubCoolness].push_back(i); - else - ammoCrates[Item[i].ubCoolness].push_back(i); - } - } - } - - } - } - for (unsigned slot = firstSlot; (slot <= lastSlot) && num && sNumSlots; ++slot) { pSoldier = &Menptr[ slot ]; @@ -1139,52 +1117,6 @@ BOOLEAN PrepareEnemyForSectorBattle() break; } - if (pGroup->pEnemyGroup->ubIntention == TRANSPORT) - { - // rftr todo: move this into its own function - // adjust soldier inventory for transport groups - - // ideas: - // soldiers have backpacks + kits + ammo box (BONUS: make sure the backpack goes in the backpack slot for lobot compatibility. that might be a fix outside of this feature tho) - // jeeps have ammo crates and/or lots of boxes. reduce bullet count in crate? - - // add ammo to the soldier's inventory! - OBJECTTYPE kit; - CreateItem(ammoBoxes[10][0], (INT8)(90+Random(10)), &kit); - if (FitsInSmallPocket(&kit)) - { - for(INT8 i = SMALLPOCKSTART; i < SMALLPOCKFINAL; i++ ) - { - if( pSoldier->inv[ i ].exists() == false && !(pSoldier->inv[ i ].fFlags & OBJECT_NO_OVERWRITE) ) - { - pSoldier->inv[ i ] = kit; - break; - } - } - } - else - { - for(INT8 i = BIGPOCKSTART; i < BIGPOCKFINAL; i++ ) - { //no space free in small pockets, so put it into a large pocket. - if( pSoldier->inv[ i ].exists() == false && !(pSoldier->inv[ i ].fFlags & OBJECT_NO_OVERWRITE) ) - { - pSoldier->inv[ i ] = kit; - break; - } - } - } - - - // force inventory to be dropped! - for (int i = 0; i < pSoldier->inv.size(); ++i) - { - OBJECTTYPE* item = &pSoldier->inv[i]; - if (item->exists() && Item[item->usItem].defaultundroppable == FALSE) - { - item->fFlags &= ~OBJECT_UNDROPPABLE; - } - } - } } // Flugente: instead of just crashing the game without any explanation to the user, ignore this issue if it still exists. @@ -1200,6 +1132,12 @@ BOOLEAN PrepareEnemyForSectorBattle() pGroup = pGroup->next; } + // rftr todo: check if feature is enabled + if (groupIdToSoldierMap.size() > 0) + { + UpdateTransportGroupInventory(groupIdToSoldierMap); + } + ValidateEnemiesHaveWeapons(); UnPauseGame(); @@ -2487,6 +2425,11 @@ void AddEnemiesToBattle( GROUP *pGroup, UINT8 ubStrategicInsertionCode, UINT8 ub UpdateMercInSector( pSoldier, gWorldSectorX, gWorldSectorY, 0 ); } + // rftr todo: check reinforcements for transport group presence? + if (pGroup->pEnemyGroup->ubIntention == TRANSPORT) + { + } + // HEADROCK HAM 3.2: enemy reinforcements arrive with 0 APs. if (gGameExternalOptions.ubReinforcementsFirstTurnFreeze == 1 || gGameExternalOptions.ubReinforcementsFirstTurnFreeze == 2) { @@ -3691,3 +3634,119 @@ void CorrectTurncoatCount( INT16 sSectorX, INT16 sSectorY ) pGroup = pGroup->next; } } + +void UpdateTransportGroupInventory(std::map> &groupIdToSoldierMap) +{ + const int firstSlot = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID; + const int lastSlot = gTacticalStatus.Team[ ENEMY_TEAM ].bLastID; + + // rftr todo: do this on init/load somewhere + // do some prep + std::vector gasCans; + std::vector firstAidKits; + std::vector medKits; + std::vector toolKits; + std::map> ammoBoxes; // map coolness to ammo vector + std::map> ammoCrates; // map coolness to ammo vector + BOOLEAN needToBuildItemCache = TRUE; + + for (int slot = firstSlot; (slot <= lastSlot); ++slot) + { + SOLDIERTYPE* pSoldier = &Menptr[slot]; + + std::map>::iterator groupIter = groupIdToSoldierMap.find(pSoldier->ubGroupID); + if (groupIter != groupIdToSoldierMap.end()) + { + // found a matching transport groupid + std::map::iterator soldierClassIter = groupIter->second.find(pSoldier->ubSoldierClass); + if (soldierClassIter != groupIter->second.end()) + { + // found a matching soldierclass + if (soldierClassIter->second > 0) + { + // one-time item cache build + if (needToBuildItemCache == TRUE) + { + // rftr todo: see if we can replace this with random items. + // requirement: probably a new flag in Items.xml, or something + // add new groups in RandomItem.xml + // the new items will reference the new group in randomitem, eg 23 in Items.xml matches uiIndex 23 in RandomItem.xml + // fallback if no random items found? for mods and stuff (thinking sdo) + needToBuildItemCache = FALSE; + for (UINT16 i = 0; i < MAXITEMS; ++i) + { + if (Item[i].gascan) gasCans.push_back(i); + else if (Item[i].firstaidkit) firstAidKits.push_back(i); + else if (Item[i].medicalkit) medKits.push_back(i); + else if (Item[i].toolkit) toolKits.push_back(i); + else if (Item[i].usItemClass & IC_AMMO) + { + if (Magazine[Item[i].ubClassIndex].ubMagType == AMMO_BOX + || Magazine[Item[i].ubClassIndex].ubMagType == AMMO_CRATE) + { + if ((gGameOptions.fGunNut || !Item[i].biggunlist) + && (gGameOptions.ubGameStyle == STYLE_SCIFI || !Item[i].scifi)) + { + if (Magazine[Item[i].ubClassIndex].ubMagType == AMMO_BOX) + ammoBoxes[Item[i].ubCoolness].push_back(i); + else + ammoCrates[Item[i].ubCoolness].push_back(i); + } + } + } + } + } + + // there are still un-updated soldiers! begin the update! + soldierClassIter->second--; + + // rftr todo: move this into its own function + // rftr todo: don't forget to call this for reinforcing troops! + // adjust soldier inventory for transport groups + + // ideas: + // soldiers have backpacks + kits + ammo box (BONUS: make sure the backpack goes in the backpack slot for lobot compatibility. that might be a fix outside of this feature tho) + // jeeps have ammo crates and/or lots of boxes. reduce bullet count in crate? + + // add ammo to the soldier's inventory! + OBJECTTYPE kit; + CreateItem(ammoBoxes[10][0], (INT8)(90+Random(10)), &kit); + if (FitsInSmallPocket(&kit)) + { + for(INT8 i = SMALLPOCKSTART; i < SMALLPOCKFINAL; i++ ) + { + if( pSoldier->inv[ i ].exists() == false && !(pSoldier->inv[ i ].fFlags & OBJECT_NO_OVERWRITE) ) + { + pSoldier->inv[ i ] = kit; + break; + } + } + } + else + { + for(INT8 i = BIGPOCKSTART; i < BIGPOCKFINAL; i++ ) + { //no space free in small pockets, so put it into a large pocket. + if( pSoldier->inv[ i ].exists() == false && !(pSoldier->inv[ i ].fFlags & OBJECT_NO_OVERWRITE) ) + { + pSoldier->inv[ i ] = kit; + break; + } + } + } + + + // force inventory to be dropped! + for (int i = 0; i < pSoldier->inv.size(); ++i) + { + OBJECTTYPE* item = &pSoldier->inv[i]; + if (item->exists() && Item[item->usItem].defaultundroppable == FALSE) + { + item->fFlags &= ~OBJECT_UNDROPPABLE; + } + } + } + } + } + } +} + From c745efea0a5031671a3a0a932425f9188c3c7895 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Sun, 11 Dec 2022 01:58:27 -0800 Subject: [PATCH 06/81] TEST - add backpack to group soldier's inventory --- Strategic/Queen Command.cpp | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/Strategic/Queen Command.cpp b/Strategic/Queen Command.cpp index 09dcc0aa7..daa7278a2 100644 --- a/Strategic/Queen Command.cpp +++ b/Strategic/Queen Command.cpp @@ -3646,6 +3646,7 @@ void UpdateTransportGroupInventory(std::map> &groupI std::vector firstAidKits; std::vector medKits; std::vector toolKits; + std::vector backpacks; std::map> ammoBoxes; // map coolness to ammo vector std::map> ammoCrates; // map coolness to ammo vector BOOLEAN needToBuildItemCache = TRUE; @@ -3679,6 +3680,14 @@ void UpdateTransportGroupInventory(std::map> &groupI else if (Item[i].firstaidkit) firstAidKits.push_back(i); else if (Item[i].medicalkit) medKits.push_back(i); else if (Item[i].toolkit) toolKits.push_back(i); + else if (Item[i].usItemClass & IC_LBEGEAR) + { + if (LoadBearingEquipment[Item[i].ubClassIndex].lbeClass == BACKPACK) + { + // todo get actual backpacks, not covert ones, tactical slings, golf clubs, etc... + backpacks.push_back(i); + } + } else if (Item[i].usItemClass & IC_AMMO) { if (Magazine[Item[i].ubClassIndex].ubMagType == AMMO_BOX @@ -3708,16 +3717,23 @@ void UpdateTransportGroupInventory(std::map> &groupI // soldiers have backpacks + kits + ammo box (BONUS: make sure the backpack goes in the backpack slot for lobot compatibility. that might be a fix outside of this feature tho) // jeeps have ammo crates and/or lots of boxes. reduce bullet count in crate? + // add backpack to soldier's inventory! + OBJECTTYPE itemToAdd; + if (backpacks.size() > 0) + { + CreateItem(backpacks[0], 75 + Random(25), &itemToAdd); + pSoldier->inv[BPACKPOCKPOS] = itemToAdd; + } + // add ammo to the soldier's inventory! - OBJECTTYPE kit; - CreateItem(ammoBoxes[10][0], (INT8)(90+Random(10)), &kit); - if (FitsInSmallPocket(&kit)) + CreateItem(ammoBoxes[10][0], (INT8)(90+Random(10)), &itemToAdd); + if (FitsInSmallPocket(&itemToAdd)) { for(INT8 i = SMALLPOCKSTART; i < SMALLPOCKFINAL; i++ ) { if( pSoldier->inv[ i ].exists() == false && !(pSoldier->inv[ i ].fFlags & OBJECT_NO_OVERWRITE) ) { - pSoldier->inv[ i ] = kit; + pSoldier->inv[ i ] = itemToAdd; break; } } @@ -3728,7 +3744,7 @@ void UpdateTransportGroupInventory(std::map> &groupI { //no space free in small pockets, so put it into a large pocket. if( pSoldier->inv[ i ].exists() == false && !(pSoldier->inv[ i ].fFlags & OBJECT_NO_OVERWRITE) ) { - pSoldier->inv[ i ] = kit; + pSoldier->inv[ i ] = itemToAdd; break; } } From 9d285666cad46e47530c8f4b960c7f98ca3fd75f Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Mon, 12 Dec 2022 02:54:26 -0800 Subject: [PATCH 07/81] Handle groups that are moving into player-owned sectors Build item cache before iterating through soldiers Handle groups with and without jeeps --- Strategic/Queen Command.cpp | 301 ++++++++++++++++++++++++------------ 1 file changed, 206 insertions(+), 95 deletions(-) diff --git a/Strategic/Queen Command.cpp b/Strategic/Queen Command.cpp index daa7278a2..8f4cd0000 100644 --- a/Strategic/Queen Command.cpp +++ b/Strategic/Queen Command.cpp @@ -86,6 +86,10 @@ extern void EndCreatureQuest(); extern GARRISON_GROUP *gGarrisonGroup; extern INT32 giGarrisonArraySize; +// rftr todo: do I need to make this global to handle reinforcements? +std::map> gTransportGroupIdToSoldierMap; // groupId -> soldierclass, count +void UpdateTransportGroupInventory(std::map> &groupIdToSoldierMap); + #ifdef JA2TESTVERSION extern BOOLEAN gfOverrideSector; #endif @@ -103,8 +107,6 @@ void HandleBloodCatDeaths( SECTORINFO *pSector ); extern void Ensure_RepairedGarrisonGroup( GARRISON_GROUP **ppGarrison, INT32 *pGarraySize ); -void UpdateTransportGroupInventory(std::map> &groupIdToSoldierMap); - void ValidateEnemiesHaveWeapons() { #ifdef JA2BETAVERSION @@ -619,6 +621,9 @@ BOOLEAN PrepareEnemyForSectorBattle() gfPendingNonPlayerTeam[ENEMY_TEAM] = FALSE; + // rftr: clear cached transport groups + gTransportGroupIdToSoldierMap.clear(); + if( gbWorldSectorZ > 0 ) return PrepareEnemyForUndergroundBattle(); @@ -675,10 +680,26 @@ BOOLEAN PrepareEnemyForSectorBattle() HandleArrivalOfReinforcements( pGroup ); } + if (pGroup->usGroupTeam == ENEMY_TEAM && pGroup->pEnemyGroup->ubIntention == TRANSPORT && pGroup->ubSectorX == gWorldSectorX && pGroup->ubSectorY == gWorldSectorY && !gbWorldSectorZ) + { + gTransportGroupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_ADMINISTRATOR] += pGroup->pEnemyGroup->ubNumAdmins; + gTransportGroupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_ARMY] += pGroup->pEnemyGroup->ubNumTroops; + gTransportGroupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_ELITE] += pGroup->pEnemyGroup->ubNumElites; + gTransportGroupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_ROBOT] += pGroup->pEnemyGroup->ubNumRobots; + gTransportGroupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_JEEP] += pGroup->pEnemyGroup->ubNumJeeps; + gTransportGroupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_TANK] += pGroup->pEnemyGroup->ubNumTanks; + } + pGroup = pGroup->next; } } + // rftr todo: check if feature is enabled + if (gTransportGroupIdToSoldierMap.size() > 0) + { + UpdateTransportGroupInventory(gTransportGroupIdToSoldierMap); + } + ValidateEnemiesHaveWeapons(); UnPauseGame(); return ( ( BOOLEAN) ( gpBattleGroup->ubGroupSize > 0 ) ); @@ -854,7 +875,6 @@ BOOLEAN PrepareEnemyForSectorBattle() //processed. // rftr todo: need to do this for reinforcements?? - std::map> groupIdToSoldierMap; // groupId -> soldierclass, count for( pGroup = gpGroupList; pGroup; pGroup = pGroup->next) { if ( pGroup->usGroupTeam == ENEMY_TEAM && !pGroup->fVehicle && @@ -876,7 +896,7 @@ BOOLEAN PrepareEnemyForSectorBattle() ubTotalAdmins += ubNumAdmins; if (isTransportGroup) - groupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_ADMINISTRATOR] += ubNumAdmins; + gTransportGroupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_ADMINISTRATOR] += ubNumAdmins; } if( sNumSlots > 0 ) { //Add regular army forces. @@ -893,7 +913,7 @@ BOOLEAN PrepareEnemyForSectorBattle() ubTotalTroops += ubNumTroops; if (isTransportGroup) - groupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_ARMY] += ubNumTroops; + gTransportGroupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_ARMY] += ubNumTroops; } if( sNumSlots > 0 ) { //Add elite troops @@ -910,7 +930,7 @@ BOOLEAN PrepareEnemyForSectorBattle() ubTotalElites += ubNumElites; if (isTransportGroup) - groupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_ELITE] += ubNumElites; + gTransportGroupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_ELITE] += ubNumElites; } if( sNumSlots > 0 ) { //Add robots @@ -927,7 +947,7 @@ BOOLEAN PrepareEnemyForSectorBattle() ubTotalRobots += ubNumRobots; if (isTransportGroup) - groupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_ROBOT] += ubNumRobots; + gTransportGroupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_ROBOT] += ubNumRobots; } if( sNumSlots > 0 ) { //Add tanks @@ -944,7 +964,7 @@ BOOLEAN PrepareEnemyForSectorBattle() ubTotalTanks += ubNumTanks; if (isTransportGroup) - groupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_TANK] += ubNumTanks; + gTransportGroupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_TANK] += ubNumTanks; } if ( sNumSlots > 0 ) { @@ -962,7 +982,7 @@ BOOLEAN PrepareEnemyForSectorBattle() ubTotalJeeps += ubNumJeeps; if (isTransportGroup) - groupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_JEEP] += ubNumJeeps; + gTransportGroupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_JEEP] += ubNumJeeps; } //NOTE: //no provisions for profile troop leader or retreat groups yet. @@ -1133,9 +1153,9 @@ BOOLEAN PrepareEnemyForSectorBattle() } // rftr todo: check if feature is enabled - if (groupIdToSoldierMap.size() > 0) + if (gTransportGroupIdToSoldierMap.size() > 0) { - UpdateTransportGroupInventory(groupIdToSoldierMap); + UpdateTransportGroupInventory(gTransportGroupIdToSoldierMap); } ValidateEnemiesHaveWeapons(); @@ -2426,6 +2446,7 @@ void AddEnemiesToBattle( GROUP *pGroup, UINT8 ubStrategicInsertionCode, UINT8 ub } // rftr todo: check reinforcements for transport group presence? + // rftr todo: better: transport groups cannot/do not reinforce if (pGroup->pEnemyGroup->ubIntention == TRANSPORT) { } @@ -3649,115 +3670,205 @@ void UpdateTransportGroupInventory(std::map> &groupI std::vector backpacks; std::map> ammoBoxes; // map coolness to ammo vector std::map> ammoCrates; // map coolness to ammo vector - BOOLEAN needToBuildItemCache = TRUE; + + // one-time item cache build + { + // rftr todo: see if we can replace this with random items. + // requirement: probably a new flag in Items.xml, or something + // add new groups in RandomItem.xml + // the new items will reference the new group in randomitem, eg 23 in Items.xml matches uiIndex 23 in RandomItem.xml + // fallback if no random items found? for mods and stuff (thinking sdo) + for (UINT16 i = 0; i < MAXITEMS; ++i) + { + if (Item[i].gascan) gasCans.push_back(i); + else if (Item[i].firstaidkit) firstAidKits.push_back(i); + else if (Item[i].medicalkit) medKits.push_back(i); + else if (Item[i].toolkit) toolKits.push_back(i); + else if (Item[i].usItemClass & IC_LBEGEAR) + { + if (LoadBearingEquipment[Item[i].ubClassIndex].lbeClass == BACKPACK) + { + // todo get actual backpacks, not covert ones, tactical slings, golf clubs, etc... + backpacks.push_back(i); + } + } + else if (Item[i].usItemClass & IC_AMMO) + { + if (Magazine[Item[i].ubClassIndex].ubMagType == AMMO_BOX + || Magazine[Item[i].ubClassIndex].ubMagType == AMMO_CRATE) + { + if ((gGameOptions.fGunNut || !Item[i].biggunlist) + && (gGameOptions.ubGameStyle == STYLE_SCIFI || !Item[i].scifi)) + { + if (Magazine[Item[i].ubClassIndex].ubMagType == AMMO_BOX) + ammoBoxes[Item[i].ubCoolness].push_back(i); + else + ammoCrates[Item[i].ubCoolness].push_back(i); + } + } + } + } + } + + auto addItemToInventory = [](SOLDIERTYPE* pSoldier, OBJECTTYPE& itemToAdd) + { + itemToAdd.fFlags &= ~OBJECT_UNDROPPABLE; + + if (FitsInSmallPocket(&itemToAdd)) + { + for(INT8 i = SMALLPOCKSTART; i < SMALLPOCKFINAL; i++ ) + { + if( pSoldier->inv[ i ].exists() == false && !(pSoldier->inv[ i ].fFlags & OBJECT_NO_OVERWRITE) ) + { + pSoldier->inv[ i ] = itemToAdd; + break; + } + } + } + else + { + for(INT8 i = BIGPOCKSTART; i < BIGPOCKFINAL; i++ ) + { //no space free in small pockets, so put it into a large pocket. + if( pSoldier->inv[ i ].exists() == false && !(pSoldier->inv[ i ].fFlags & OBJECT_NO_OVERWRITE) ) + { + pSoldier->inv[ i ] = itemToAdd; + break; + } + } + } + }; + + // groups with jeeps are special - the jeeps carry the loot instead of the soldiers + //std::set groupsWithJeeps; + //for (const auto pair : groupIdToSoldierMap) + //{ + // std::map soldierMap = pair.second; + // if (soldierMap[SOLDIER_CLASS_JEEP] > 0) + // { + // groupsWithJeeps.insert(pair.first); + // } + //} for (int slot = firstSlot; (slot <= lastSlot); ++slot) { SOLDIERTYPE* pSoldier = &Menptr[slot]; - std::map>::iterator groupIter = groupIdToSoldierMap.find(pSoldier->ubGroupID); + // this group has a jeep in it! + //if (groupsWithJeeps.find(pSoldier->ubGroupID) != groupsWithJeeps.end()) + //{ + // // only jeeps carry things + // // but give a little extra, since the jeep exploding can outright destroy things + // if (pSoldier->ubSoldierClass == SOLDIER_CLASS_JEEP) + // { + // OBJECTTYPE itemToAdd; + // for (int i = 0; i < 3; ++i) + // { + // CreateItem(ammoBoxes[5][0], 100, &itemToAdd); + // addItemToInventory(pSoldier, itemToAdd); + // } + + // for (int i = 0; i < 3; ++i) + // { + // CreateItem(medKits[Random(medKits.size())], 100, &itemToAdd); + // addItemToInventory(pSoldier, itemToAdd); + // } + // groupIdToSoldierMap[pSoldier->ubGroupID][SOLDIER_CLASS_JEEP]--; + // } + // else // not a jeep + // { + // // force inventory to be dropped! + // for (int i = 0; i < pSoldier->inv.size(); ++i) + // { + // OBJECTTYPE* item = &pSoldier->inv[i]; + // if (item->exists() && Item[item->usItem].defaultundroppable == FALSE) + // { + // item->fFlags &= ~OBJECT_UNDROPPABLE; + // } + // } + // } + + // continue; + //} + + const std::map>::iterator groupIter = groupIdToSoldierMap.find(pSoldier->ubGroupID); if (groupIter != groupIdToSoldierMap.end()) { // found a matching transport groupid - std::map::iterator soldierClassIter = groupIter->second.find(pSoldier->ubSoldierClass); + std::map::iterator soldierClassIter = groupIter->second.find(SOLDIER_CLASS_JEEP); if (soldierClassIter != groupIter->second.end()) { - // found a matching soldierclass - if (soldierClassIter->second > 0) + // this group has a jeep in it! + // only jeeps carry things + // but give a little extra, since the jeep exploding can outright destroy things + if (pSoldier->ubSoldierClass == SOLDIER_CLASS_JEEP) { - // one-time item cache build - if (needToBuildItemCache == TRUE) + OBJECTTYPE itemToAdd; + for (int i = 0; i < 3; ++i) { - // rftr todo: see if we can replace this with random items. - // requirement: probably a new flag in Items.xml, or something - // add new groups in RandomItem.xml - // the new items will reference the new group in randomitem, eg 23 in Items.xml matches uiIndex 23 in RandomItem.xml - // fallback if no random items found? for mods and stuff (thinking sdo) - needToBuildItemCache = FALSE; - for (UINT16 i = 0; i < MAXITEMS; ++i) - { - if (Item[i].gascan) gasCans.push_back(i); - else if (Item[i].firstaidkit) firstAidKits.push_back(i); - else if (Item[i].medicalkit) medKits.push_back(i); - else if (Item[i].toolkit) toolKits.push_back(i); - else if (Item[i].usItemClass & IC_LBEGEAR) - { - if (LoadBearingEquipment[Item[i].ubClassIndex].lbeClass == BACKPACK) - { - // todo get actual backpacks, not covert ones, tactical slings, golf clubs, etc... - backpacks.push_back(i); - } - } - else if (Item[i].usItemClass & IC_AMMO) - { - if (Magazine[Item[i].ubClassIndex].ubMagType == AMMO_BOX - || Magazine[Item[i].ubClassIndex].ubMagType == AMMO_CRATE) - { - if ((gGameOptions.fGunNut || !Item[i].biggunlist) - && (gGameOptions.ubGameStyle == STYLE_SCIFI || !Item[i].scifi)) - { - if (Magazine[Item[i].ubClassIndex].ubMagType == AMMO_BOX) - ammoBoxes[Item[i].ubCoolness].push_back(i); - else - ammoCrates[Item[i].ubCoolness].push_back(i); - } - } - } - } + CreateItem(ammoBoxes[5][0], 100, &itemToAdd); + addItemToInventory(pSoldier, itemToAdd); } - // there are still un-updated soldiers! begin the update! - soldierClassIter->second--; - - // rftr todo: move this into its own function - // rftr todo: don't forget to call this for reinforcing troops! - // adjust soldier inventory for transport groups - - // ideas: - // soldiers have backpacks + kits + ammo box (BONUS: make sure the backpack goes in the backpack slot for lobot compatibility. that might be a fix outside of this feature tho) - // jeeps have ammo crates and/or lots of boxes. reduce bullet count in crate? - - // add backpack to soldier's inventory! - OBJECTTYPE itemToAdd; - if (backpacks.size() > 0) + for (int i = 0; i < 3; ++i) { - CreateItem(backpacks[0], 75 + Random(25), &itemToAdd); - pSoldier->inv[BPACKPOCKPOS] = itemToAdd; + CreateItem(medKits[Random(medKits.size())], 100, &itemToAdd); + addItemToInventory(pSoldier, itemToAdd); } - - // add ammo to the soldier's inventory! - CreateItem(ammoBoxes[10][0], (INT8)(90+Random(10)), &itemToAdd); - if (FitsInSmallPocket(&itemToAdd)) + groupIdToSoldierMap[pSoldier->ubGroupID][SOLDIER_CLASS_JEEP]--; + } + else // not a jeep + { + // force inventory to be dropped! + for (int i = 0; i < pSoldier->inv.size(); ++i) { - for(INT8 i = SMALLPOCKSTART; i < SMALLPOCKFINAL; i++ ) + OBJECTTYPE* item = &pSoldier->inv[i]; + if (item->exists() && Item[item->usItem].defaultundroppable == FALSE) { - if( pSoldier->inv[ i ].exists() == false && !(pSoldier->inv[ i ].fFlags & OBJECT_NO_OVERWRITE) ) - { - pSoldier->inv[ i ] = itemToAdd; - break; - } + item->fFlags &= ~OBJECT_UNDROPPABLE; } } - else + } + } + else + { + // no jeep in group, add things normally + soldierClassIter = groupIter->second.find(pSoldier->ubSoldierClass); + if (soldierClassIter != groupIter->second.end()) + { + // found a matching soldierclass + if (soldierClassIter->second > 0) { - for(INT8 i = BIGPOCKSTART; i < BIGPOCKFINAL; i++ ) - { //no space free in small pockets, so put it into a large pocket. - if( pSoldier->inv[ i ].exists() == false && !(pSoldier->inv[ i ].fFlags & OBJECT_NO_OVERWRITE) ) - { - pSoldier->inv[ i ] = itemToAdd; - break; - } + // there are still un-updated soldiers! begin the update! + soldierClassIter->second--; + + // rftr todo: move this into its own function + // rftr todo: don't forget to call this for reinforcing troops! + // adjust soldier inventory for transport groups + + // ideas: + // soldiers have backpacks + kits + ammo box (BONUS: make sure the backpack goes in the backpack slot for lobot compatibility. that might be a fix outside of this feature tho) + // jeeps have ammo crates and/or lots of boxes. reduce bullet count in crate? + + // add backpack to soldier's inventory! + OBJECTTYPE itemToAdd; + if (backpacks.size() > 0) + { + CreateItem(backpacks[0], 75 + Random(25), &itemToAdd); + pSoldier->inv[BPACKPOCKPOS] = itemToAdd; } - } + // add ammo to the soldier's inventory! + CreateItem(ammoBoxes[10][0], (INT8)(90+Random(10)), &itemToAdd); + addItemToInventory(pSoldier, itemToAdd); - // force inventory to be dropped! - for (int i = 0; i < pSoldier->inv.size(); ++i) - { - OBJECTTYPE* item = &pSoldier->inv[i]; - if (item->exists() && Item[item->usItem].defaultundroppable == FALSE) + // force inventory to be dropped! + for (int i = 0; i < pSoldier->inv.size(); ++i) { - item->fFlags &= ~OBJECT_UNDROPPABLE; + OBJECTTYPE* item = &pSoldier->inv[i]; + if (item->exists() && Item[item->usItem].defaultundroppable == FALSE) + { + item->fFlags &= ~OBJECT_UNDROPPABLE; + } } } } From d1ecb7ecfe25cc30bf3da006e82baa972489ac4c Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Mon, 12 Dec 2022 02:55:00 -0800 Subject: [PATCH 08/81] Delete commented code --- Strategic/Queen Command.cpp | 48 ------------------------------------- 1 file changed, 48 deletions(-) diff --git a/Strategic/Queen Command.cpp b/Strategic/Queen Command.cpp index 8f4cd0000..1b1ac372b 100644 --- a/Strategic/Queen Command.cpp +++ b/Strategic/Queen Command.cpp @@ -3738,58 +3738,10 @@ void UpdateTransportGroupInventory(std::map> &groupI } }; - // groups with jeeps are special - the jeeps carry the loot instead of the soldiers - //std::set groupsWithJeeps; - //for (const auto pair : groupIdToSoldierMap) - //{ - // std::map soldierMap = pair.second; - // if (soldierMap[SOLDIER_CLASS_JEEP] > 0) - // { - // groupsWithJeeps.insert(pair.first); - // } - //} - for (int slot = firstSlot; (slot <= lastSlot); ++slot) { SOLDIERTYPE* pSoldier = &Menptr[slot]; - // this group has a jeep in it! - //if (groupsWithJeeps.find(pSoldier->ubGroupID) != groupsWithJeeps.end()) - //{ - // // only jeeps carry things - // // but give a little extra, since the jeep exploding can outright destroy things - // if (pSoldier->ubSoldierClass == SOLDIER_CLASS_JEEP) - // { - // OBJECTTYPE itemToAdd; - // for (int i = 0; i < 3; ++i) - // { - // CreateItem(ammoBoxes[5][0], 100, &itemToAdd); - // addItemToInventory(pSoldier, itemToAdd); - // } - - // for (int i = 0; i < 3; ++i) - // { - // CreateItem(medKits[Random(medKits.size())], 100, &itemToAdd); - // addItemToInventory(pSoldier, itemToAdd); - // } - // groupIdToSoldierMap[pSoldier->ubGroupID][SOLDIER_CLASS_JEEP]--; - // } - // else // not a jeep - // { - // // force inventory to be dropped! - // for (int i = 0; i < pSoldier->inv.size(); ++i) - // { - // OBJECTTYPE* item = &pSoldier->inv[i]; - // if (item->exists() && Item[item->usItem].defaultundroppable == FALSE) - // { - // item->fFlags &= ~OBJECT_UNDROPPABLE; - // } - // } - // } - - // continue; - //} - const std::map>::iterator groupIter = groupIdToSoldierMap.find(pSoldier->ubGroupID); if (groupIter != groupIdToSoldierMap.end()) { From 64dea23a5418f3f5440351d8eccb8c50755014ec Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Tue, 13 Dec 2022 00:59:21 -0800 Subject: [PATCH 09/81] Prevent transport groups from reinforcing Rename function to GetNonPlayerGroupInSectorForReinforcement() to clarify its purpose --- Strategic/Queen Command.cpp | 4 ++-- Strategic/Reinforcement.cpp | 6 +++--- Strategic/Reinforcement.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Strategic/Queen Command.cpp b/Strategic/Queen Command.cpp index 1b1ac372b..5d4ff25cb 100644 --- a/Strategic/Queen Command.cpp +++ b/Strategic/Queen Command.cpp @@ -651,9 +651,9 @@ BOOLEAN PrepareEnemyForSectorBattle() for( unsigned ubIndex = 0; ubIndex < ubDirNumber; ++ubIndex ) { - while ( NumMobileEnemiesInSector( SECTORX( pusMoveDir[ubIndex][0] ), SECTORY( pusMoveDir[ubIndex][0] ) ) && GetNonPlayerGroupInSector( SECTORX( pusMoveDir[ubIndex][0] ), SECTORY( pusMoveDir[ubIndex][0] ), ENEMY_TEAM ) ) + while ( NumMobileEnemiesInSector( SECTORX( pusMoveDir[ubIndex][0] ), SECTORY( pusMoveDir[ubIndex][0] ) ) && GetNonPlayerGroupInSectorForReinforcement( SECTORX( pusMoveDir[ubIndex][0] ), SECTORY( pusMoveDir[ubIndex][0] ), ENEMY_TEAM ) ) { - pGroup = GetNonPlayerGroupInSector( SECTORX( pusMoveDir[ubIndex][0] ), SECTORY( pusMoveDir[ubIndex][0] ), ENEMY_TEAM ); + pGroup = GetNonPlayerGroupInSectorForReinforcement( SECTORX( pusMoveDir[ubIndex][0] ), SECTORY( pusMoveDir[ubIndex][0] ), ENEMY_TEAM ); pGroup->ubPrevX = pGroup->ubSectorX; pGroup->ubPrevY = pGroup->ubSectorY; diff --git a/Strategic/Reinforcement.cpp b/Strategic/Reinforcement.cpp index 3840769f8..283e364e8 100644 --- a/Strategic/Reinforcement.cpp +++ b/Strategic/Reinforcement.cpp @@ -250,13 +250,13 @@ BOOLEAN ARMoveBestMilitiaManFromAdjacentSector(INT16 sMapX, INT16 sMapY) return TRUE; } -GROUP* GetNonPlayerGroupInSector( INT16 sMapX, INT16 sMapY, UINT8 usTeam ) +GROUP* GetNonPlayerGroupInSectorForReinforcement( INT16 sMapX, INT16 sMapY, UINT8 usTeam ) { GROUP *curr; curr = gpGroupList; while( curr ) { - if ( curr->ubSectorX == sMapX && curr->ubSectorY == sMapY && curr->usGroupTeam == usTeam && curr->ubGroupID ) + if ( curr->ubSectorX == sMapX && curr->ubSectorY == sMapY && curr->usGroupTeam == usTeam && curr->ubGroupID && (curr->usGroupTeam != ENEMY_TEAM || curr->pEnemyGroup->ubIntention != TRANSPORT) ) return curr; curr = curr->next; } @@ -284,7 +284,7 @@ UINT8 DoReinforcementAsPendingNonPlayer( INT16 sMapX, INT16 sMapY, UINT8 usTeam for( ubIndex = 0; ubIndex < ubDirNumber; ++ubIndex ) { - while ( (pGroup = GetNonPlayerGroupInSector( SECTORX( pusMoveDir[ubIndex][0] ), SECTORY( pusMoveDir[ubIndex][0] ), usTeam )) != NULL ) + while ( (pGroup = GetNonPlayerGroupInSectorForReinforcement( SECTORX( pusMoveDir[ubIndex][0] ), SECTORY( pusMoveDir[ubIndex][0] ), usTeam )) != NULL ) { pGroup->ubPrevX = pGroup->ubSectorX; pGroup->ubPrevY = pGroup->ubSectorY; diff --git a/Strategic/Reinforcement.h b/Strategic/Reinforcement.h index 543ff0415..e6017b51d 100644 --- a/Strategic/Reinforcement.h +++ b/Strategic/Reinforcement.h @@ -12,6 +12,6 @@ UINT8 NumEnemiesInFiveSectors( INT16 sMapX, INT16 sMapY ); //For Tactical UINT8 DoReinforcementAsPendingNonPlayer( INT16 sMapX, INT16 sMapY, UINT8 usTeam ); void AddPossiblePendingMilitiaToBattle(); -GROUP* GetNonPlayerGroupInSector( INT16 sMapX, INT16 sMapY, UINT8 usTeam ); +GROUP* GetNonPlayerGroupInSectorForReinforcement( INT16 sMapX, INT16 sMapY, UINT8 usTeam ); #endif \ No newline at end of file From d6f0700e4c25e7fae9d1a2544b5677b4205eb27a Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Tue, 13 Dec 2022 01:23:16 -0800 Subject: [PATCH 10/81] Only reduce non-box/crate ammo drops on non-player soldier death --- Tactical/Rotting Corpses.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Tactical/Rotting Corpses.cpp b/Tactical/Rotting Corpses.cpp index 26f476ec8..3f4d9cdec 100644 --- a/Tactical/Rotting Corpses.cpp +++ b/Tactical/Rotting Corpses.cpp @@ -2523,7 +2523,9 @@ void ReduceAmmoDroppedByNonPlayerSoldiers( SOLDIERTYPE *pSoldier, INT32 iInvSlot OBJECTTYPE *pObj = &( pSoldier->inv[ iInvSlot ] ); // if it's ammo - if ( Item[ pObj->usItem ].usItemClass == IC_AMMO ) + if ( Item[ pObj->usItem ].usItemClass == IC_AMMO + && Magazine[Item[pObj->usItem].ubClassIndex].ubMagType != AMMO_BOX + && Magazine[Item[pObj->usItem].ubClassIndex].ubMagType != AMMO_CRATE) { //don't drop all the clips, just a random # of them between 1 and how many there are pObj->ubNumberOfObjects = ( UINT8 ) ( 1 + Random( pObj->ubNumberOfObjects ) ); From 59e071751e6461a8dc864a0e6a31e277cfc3cad8 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Tue, 13 Dec 2022 22:42:52 -0800 Subject: [PATCH 11/81] Delay group return order --- Strategic/Game Event Hook.cpp | 6 ++++++ Strategic/Game Event Hook.h | 2 ++ Strategic/Game Events.cpp | 1 + Strategic/Strategic AI.cpp | 22 +++++++++++++++++++++- Tactical/interface Dialogue.h | 1 + 5 files changed, 31 insertions(+), 1 deletion(-) diff --git a/Strategic/Game Event Hook.cpp b/Strategic/Game Event Hook.cpp index 261fbd80d..5bc04143f 100644 --- a/Strategic/Game Event Hook.cpp +++ b/Strategic/Game Event Hook.cpp @@ -52,6 +52,7 @@ #include "LuaInitNPCs.h" // added by Flugente #include "MiniEvents.h" #include "Rebel Command.h" + #include "interface Dialogue.h" #endif #include "connect.h" @@ -685,6 +686,11 @@ BOOLEAN ExecuteStrategicEvent( STRATEGICEVENT *pEvent ) case EVENT_REBELCOMMAND: RebelCommand::HandleStrategicEvent(pEvent->uiParam); break; + + case EVENT_RETURN_TRANSPORT_GROUP: + // for this action, we only care about the groupid, which is in the event param + ExecuteStrategicAIAction(NPC_ACTION_RETURN_TRANSPORT_GROUP, 0, 0, pEvent->uiParam); + break; } gfPreventDeletionOfAnyEvent = fOrigPreventFlag; return TRUE; diff --git a/Strategic/Game Event Hook.h b/Strategic/Game Event Hook.h index 29e08bb59..d35444dd8 100644 --- a/Strategic/Game Event Hook.h +++ b/Strategic/Game Event Hook.h @@ -154,6 +154,8 @@ enum EVENT_REBELCOMMAND, + EVENT_RETURN_TRANSPORT_GROUP, + NUMBER_OF_EVENT_TYPES_PLUS_ONE, NUMBER_OF_EVENT_TYPES = NUMBER_OF_EVENT_TYPES_PLUS_ONE - 1 }; diff --git a/Strategic/Game Events.cpp b/Strategic/Game Events.cpp index ffcc77b82..3d7145a91 100644 --- a/Strategic/Game Events.cpp +++ b/Strategic/Game Events.cpp @@ -141,6 +141,7 @@ CHAR16 gEventName[NUMBER_OF_EVENT_TYPES_PLUS_ONE][40]={ L"ArmyFinishTraining", L"MiniEvent", L"ARC_Event", + L"ReturnTransportGroup", }; #endif diff --git a/Strategic/Strategic AI.cpp b/Strategic/Strategic AI.cpp index 5d0b22052..b6c3eb9d9 100644 --- a/Strategic/Strategic AI.cpp +++ b/Strategic/Strategic AI.cpp @@ -38,6 +38,7 @@ #include "interface dialogue.h" #include "ASD.h" // added by Flugente #include "Rebel Command.h" + #include "Game Event Hook.h" #endif #include "GameInitOptionsScreen.h" @@ -2432,10 +2433,13 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Strategic5"); if (pGroup->ubSectorX != gModSettings.ubSAISpawnSectorX && pGroup->ubSectorY != gModSettings.ubSAISpawnSectorY) { pGroup->ubSectorIDOfLastReassignment = (UINT8)SECTOR( pGroup->ubSectorX, pGroup->ubSectorY ); - MoveSAIGroupToSector( &pGroup, SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), EVASIVE, TRANSPORT ); + + // queue up return home order + AddStrategicEvent(EVENT_RETURN_TRANSPORT_GROUP, GetWorldTotalMin() + 60 * 6, pGroup->ubGroupID); } else { + // successfully returned home. give the strategic ai some rewards! SendGroupToPool(&pGroup); } @@ -5441,6 +5445,22 @@ void ExecuteStrategicAIAction( UINT16 usActionCode, INT16 sSectorX, INT16 sSecto MoveSAIGroupToSector( &pGroup, ubSectorID, EVASIVE, TRANSPORT ); break; + case NPC_ACTION_RETURN_TRANSPORT_GROUP: + pGroup = gpGroupList; + while (pGroup) + { + if (pGroup->ubGroupID == option1) + { + MoveSAIGroupToSector( &pGroup, SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), EVASIVE, TRANSPORT ); + break; + } + pGroup = pGroup->next; + } + + if (pGroup == nullptr) + ScreenMsg( FONT_YELLOW, MSG_INTERFACE, L"RETURN_TRANSPORT_GROUP failed to find groupid %d", option1); + break; + default: ScreenMsg( FONT_RED, MSG_DEBUG, L"QueenAI failed to handle action code %d.", usActionCode ); break; diff --git a/Tactical/interface Dialogue.h b/Tactical/interface Dialogue.h index 4b3d1b759..9ca784082 100644 --- a/Tactical/interface Dialogue.h +++ b/Tactical/interface Dialogue.h @@ -390,6 +390,7 @@ enum // rftr: transport groups NPC_ACTION_DEPLOY_TRANSPORT_GROUP, + NPC_ACTION_RETURN_TRANSPORT_GROUP, NPC_ACTION_RECRUIT_PROFILE_TO_EPC = 700, NPC_ACTION_UNRECRUIT_EPC = 701, From 5ff62f9d3d255c497470426cded830bcd2baeae3 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Sun, 18 Dec 2022 01:51:18 -0800 Subject: [PATCH 12/81] Add Strategic AI bonuses on group arrival at destination and return --- Strategic/Strategic AI.cpp | 80 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 3 deletions(-) diff --git a/Strategic/Strategic AI.cpp b/Strategic/Strategic AI.cpp index b6c3eb9d9..5835bee4c 100644 --- a/Strategic/Strategic AI.cpp +++ b/Strategic/Strategic AI.cpp @@ -39,6 +39,7 @@ #include "ASD.h" // added by Flugente #include "Rebel Command.h" #include "Game Event Hook.h" + #include "Strategic Town Loyalty.h" #endif #include "GameInitOptionsScreen.h" @@ -2428,21 +2429,93 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Strategic5"); else if (pGroup->pEnemyGroup->ubIntention == TRANSPORT) { // rftr todo: something depending if we're in spawn or at target destination + const UINT8 difficulty = gGameOptions.ubDifficultyLevel; // just arrived, let's go home if (pGroup->ubSectorX != gModSettings.ubSAISpawnSectorX && pGroup->ubSectorY != gModSettings.ubSAISpawnSectorY) { pGroup->ubSectorIDOfLastReassignment = (UINT8)SECTOR( pGroup->ubSectorX, pGroup->ubSectorY ); + // global loyalty loss + INT32 loyaltyLoss = 0; + switch (difficulty) + { + case DIF_LEVEL_EASY: loyaltyLoss = 0; break; + case DIF_LEVEL_MEDIUM: loyaltyLoss = -100; break; + case DIF_LEVEL_HARD: loyaltyLoss = -250; break; + case DIF_LEVEL_INSANE: loyaltyLoss = -500; break; + } + // rftr todo: this is the "proper" way to do it - letting lua handle it. requires adding an enum value in Strategic Town Loyalty.h (GlobalLoyaltyEventTypes) + //HandleGlobalLoyaltyEvent(-1, pGroup->ubSectorX, pGroup->ubSectorY, pGroup->ubSectorZ); + //... which calls this: + AffectAllTownsLoyaltyByDistanceFrom(loyaltyLoss, pGroup->ubSectorX, pGroup->ubSectorY, pGroup->ubSectorZ); + + // on reach target ideas: + // disease: reduction in target town? + // volunteer pool reduction? can we do that? + // queue up return home order AddStrategicEvent(EVENT_RETURN_TRANSPORT_GROUP, GetWorldTotalMin() + 60 * 6, pGroup->ubGroupID); } else { + // asd income injection and bonus update + if (gGameExternalOptions.fASDActive) + { + INT32 moneyAmt = 0; + INT32 fuelAmt = 0; + + switch (difficulty) + { + case DIF_LEVEL_EASY: + moneyAmt = 0; + fuelAmt = 0; + break; + + case DIF_LEVEL_MEDIUM: + moneyAmt = gGameExternalOptions.gASDResource_Cost[ASD_JEEP] * 0.5f; + fuelAmt = gGameExternalOptions.gASDResource_Fuel_Jeep * 0.5f; + break; + + case DIF_LEVEL_HARD: + moneyAmt = gGameExternalOptions.gASDResource_Cost[ASD_JEEP]; + fuelAmt = gGameExternalOptions.gASDResource_Fuel_Jeep; + break; + + case DIF_LEVEL_INSANE: + moneyAmt = gGameExternalOptions.gASDResource_Cost[ASD_JEEP] + gGameExternalOptions.gASDResource_Cost[ASD_TANK]; + fuelAmt = gGameExternalOptions.gASDResource_Fuel_Jeep + gGameExternalOptions.gASDResource_Fuel_Tank; + break; + } + + AddStrategicAIResources(ASD_MONEY, moneyAmt); + AddStrategicAIResources(ASD_FUEL, fuelAmt); + UpdateASD(); + } + + // reinforcement pool increase + if (!gfUnlimitedTroops) + { + INT32 poolAmt = 0; + switch (difficulty) + { + case DIF_LEVEL_EASY: poolAmt = 0; break; + case DIF_LEVEL_MEDIUM: poolAmt = 10; break; + case DIF_LEVEL_HARD: poolAmt = 15; break; + case DIF_LEVEL_INSANE: poolAmt = 40; break; + } + + giReinforcementPool += poolAmt; + } + // successfully returned home. give the strategic ai some rewards! SendGroupToPool(&pGroup); - } + // immediately do a queen evaluation + DeleteAllStrategicEventsOfType(EVENT_EVALUATE_QUEEN_SITUATION); + EvaluateQueenSituation(); + } + return TRUE; // do we just call ReassignAIGroup or SendGroupToPool to dissolve and remove the group? } else @@ -3485,6 +3558,8 @@ void EvaluateQueenSituation() dEnemyGeneralsSpeedupFactor *= RebelCommand::GetStrategicDecisionSpeedModifier(); uiOffset += dEnemyGeneralsSpeedupFactor * (zDiffSetting[gGameOptions.ubDifficultyLevel].iBaseDelayInMinutesBetweenEvaluations + Random( zDiffSetting[gGameOptions.ubDifficultyLevel].iEvaluationDelayVariance )); + + ScreenMsg( FONT_RED, MSG_INTERFACE, L"Evaluating queen situation..."); // Check/update reinforcements pool if old behavior is enabled if ( !gfUnlimitedTroops && zDiffSetting[gGameOptions.ubDifficultyLevel].iQueenPoolIncrementDaysPerDifficultyLevel == 0 ) @@ -5418,10 +5493,9 @@ void ExecuteStrategicAIAction( UINT16 usActionCode, INT16 sSectorX, INT16 sSecto // limitations: max number of transport groups at any given time // track recent transport group interceptions // varying transport group quality/compositions -//void ExecuteStrategicAIAction( UINT16 usActionCode, INT16 sSectorX, INT16 sSectorY, -// INT32 option1, INT32 option2 ) // copied from NPC_ACTION_SEND_SOLDIERS_TO_BATTLE_LOCATION, which happens after the first non-welcome wagon battle // rftr todo: replace this with townid + // rftr todo: only pick towns that 1) have mines, and 2) are uncontested ubSectorID = (UINT8)STRATEGIC_INDEX_TO_SECTOR_INFO( sWorldSectorLocationOfFirstBattle ); pSector = &SectorInfo[ ubSectorID ]; From 5b762e49f27e644d3620d83cc8789f7088f9bb20 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Fri, 23 Dec 2022 00:07:11 -0800 Subject: [PATCH 13/81] Move logic to new files (Strategic Transport Groups) Move SendGroupToPool to header --- Strategic/Queen Command.cpp | 180 +---------- Strategic/Strategic AI.cpp | 134 +------- Strategic/Strategic AI.h | 1 + Strategic/Strategic Transport Groups.cpp | 371 +++++++++++++++++++++++ Strategic/Strategic Transport Groups.h | 16 + Strategic/Strategic_VS2005.vcproj | 8 + Strategic/Strategic_VS2008.vcproj | 8 + Strategic/Strategic_VS2010.vcxproj | 2 + Strategic/Strategic_VS2013.vcxproj | 2 + Strategic/Strategic_VS2017.vcxproj | 2 + Strategic/Strategic_VS2019.vcxproj | 2 + 11 files changed, 420 insertions(+), 306 deletions(-) create mode 100644 Strategic/Strategic Transport Groups.cpp create mode 100644 Strategic/Strategic Transport Groups.h diff --git a/Strategic/Queen Command.cpp b/Strategic/Queen Command.cpp index 5d4ff25cb..58a96182b 100644 --- a/Strategic/Queen Command.cpp +++ b/Strategic/Queen Command.cpp @@ -46,6 +46,7 @@ #include "Morale.h" #include "CampaignStats.h" // added by Flugente #include "ASD.h" // added by Flugente + #include "Strategic Transport Groups.h" #endif #ifdef JA2BETAVERSION @@ -86,10 +87,6 @@ extern void EndCreatureQuest(); extern GARRISON_GROUP *gGarrisonGroup; extern INT32 giGarrisonArraySize; -// rftr todo: do I need to make this global to handle reinforcements? -std::map> gTransportGroupIdToSoldierMap; // groupId -> soldierclass, count -void UpdateTransportGroupInventory(std::map> &groupIdToSoldierMap); - #ifdef JA2TESTVERSION extern BOOLEAN gfOverrideSector; #endif @@ -680,6 +677,7 @@ BOOLEAN PrepareEnemyForSectorBattle() HandleArrivalOfReinforcements( pGroup ); } + // for transport groups, track how many enemies of each type we're adding so we can update drops for them if (pGroup->usGroupTeam == ENEMY_TEAM && pGroup->pEnemyGroup->ubIntention == TRANSPORT && pGroup->ubSectorX == gWorldSectorX && pGroup->ubSectorY == gWorldSectorY && !gbWorldSectorZ) { gTransportGroupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_ADMINISTRATOR] += pGroup->pEnemyGroup->ubNumAdmins; @@ -874,7 +872,6 @@ BOOLEAN PrepareEnemyForSectorBattle() //For enemy groups, we fill up the slots until we have none left or all of the groups have been //processed. - // rftr todo: need to do this for reinforcements?? for( pGroup = gpGroupList; pGroup; pGroup = pGroup->next) { if ( pGroup->usGroupTeam == ENEMY_TEAM && !pGroup->fVehicle && @@ -2449,6 +2446,7 @@ void AddEnemiesToBattle( GROUP *pGroup, UINT8 ubStrategicInsertionCode, UINT8 ub // rftr todo: better: transport groups cannot/do not reinforce if (pGroup->pEnemyGroup->ubIntention == TRANSPORT) { + ScreenMsg(FONT_RED, MSG_INTERFACE, L"Transport group attempting to reinforce? This shouldn't happen!"); } // HEADROCK HAM 3.2: enemy reinforcements arrive with 0 APs. @@ -3656,176 +3654,4 @@ void CorrectTurncoatCount( INT16 sSectorX, INT16 sSectorY ) } } -void UpdateTransportGroupInventory(std::map> &groupIdToSoldierMap) -{ - const int firstSlot = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID; - const int lastSlot = gTacticalStatus.Team[ ENEMY_TEAM ].bLastID; - - // rftr todo: do this on init/load somewhere - // do some prep - std::vector gasCans; - std::vector firstAidKits; - std::vector medKits; - std::vector toolKits; - std::vector backpacks; - std::map> ammoBoxes; // map coolness to ammo vector - std::map> ammoCrates; // map coolness to ammo vector - - // one-time item cache build - { - // rftr todo: see if we can replace this with random items. - // requirement: probably a new flag in Items.xml, or something - // add new groups in RandomItem.xml - // the new items will reference the new group in randomitem, eg 23 in Items.xml matches uiIndex 23 in RandomItem.xml - // fallback if no random items found? for mods and stuff (thinking sdo) - for (UINT16 i = 0; i < MAXITEMS; ++i) - { - if (Item[i].gascan) gasCans.push_back(i); - else if (Item[i].firstaidkit) firstAidKits.push_back(i); - else if (Item[i].medicalkit) medKits.push_back(i); - else if (Item[i].toolkit) toolKits.push_back(i); - else if (Item[i].usItemClass & IC_LBEGEAR) - { - if (LoadBearingEquipment[Item[i].ubClassIndex].lbeClass == BACKPACK) - { - // todo get actual backpacks, not covert ones, tactical slings, golf clubs, etc... - backpacks.push_back(i); - } - } - else if (Item[i].usItemClass & IC_AMMO) - { - if (Magazine[Item[i].ubClassIndex].ubMagType == AMMO_BOX - || Magazine[Item[i].ubClassIndex].ubMagType == AMMO_CRATE) - { - if ((gGameOptions.fGunNut || !Item[i].biggunlist) - && (gGameOptions.ubGameStyle == STYLE_SCIFI || !Item[i].scifi)) - { - if (Magazine[Item[i].ubClassIndex].ubMagType == AMMO_BOX) - ammoBoxes[Item[i].ubCoolness].push_back(i); - else - ammoCrates[Item[i].ubCoolness].push_back(i); - } - } - } - } - } - - auto addItemToInventory = [](SOLDIERTYPE* pSoldier, OBJECTTYPE& itemToAdd) - { - itemToAdd.fFlags &= ~OBJECT_UNDROPPABLE; - - if (FitsInSmallPocket(&itemToAdd)) - { - for(INT8 i = SMALLPOCKSTART; i < SMALLPOCKFINAL; i++ ) - { - if( pSoldier->inv[ i ].exists() == false && !(pSoldier->inv[ i ].fFlags & OBJECT_NO_OVERWRITE) ) - { - pSoldier->inv[ i ] = itemToAdd; - break; - } - } - } - else - { - for(INT8 i = BIGPOCKSTART; i < BIGPOCKFINAL; i++ ) - { //no space free in small pockets, so put it into a large pocket. - if( pSoldier->inv[ i ].exists() == false && !(pSoldier->inv[ i ].fFlags & OBJECT_NO_OVERWRITE) ) - { - pSoldier->inv[ i ] = itemToAdd; - break; - } - } - } - }; - - for (int slot = firstSlot; (slot <= lastSlot); ++slot) - { - SOLDIERTYPE* pSoldier = &Menptr[slot]; - - const std::map>::iterator groupIter = groupIdToSoldierMap.find(pSoldier->ubGroupID); - if (groupIter != groupIdToSoldierMap.end()) - { - // found a matching transport groupid - std::map::iterator soldierClassIter = groupIter->second.find(SOLDIER_CLASS_JEEP); - if (soldierClassIter != groupIter->second.end()) - { - // this group has a jeep in it! - // only jeeps carry things - // but give a little extra, since the jeep exploding can outright destroy things - if (pSoldier->ubSoldierClass == SOLDIER_CLASS_JEEP) - { - OBJECTTYPE itemToAdd; - for (int i = 0; i < 3; ++i) - { - CreateItem(ammoBoxes[5][0], 100, &itemToAdd); - addItemToInventory(pSoldier, itemToAdd); - } - - for (int i = 0; i < 3; ++i) - { - CreateItem(medKits[Random(medKits.size())], 100, &itemToAdd); - addItemToInventory(pSoldier, itemToAdd); - } - groupIdToSoldierMap[pSoldier->ubGroupID][SOLDIER_CLASS_JEEP]--; - } - else // not a jeep - { - // force inventory to be dropped! - for (int i = 0; i < pSoldier->inv.size(); ++i) - { - OBJECTTYPE* item = &pSoldier->inv[i]; - if (item->exists() && Item[item->usItem].defaultundroppable == FALSE) - { - item->fFlags &= ~OBJECT_UNDROPPABLE; - } - } - } - } - else - { - // no jeep in group, add things normally - soldierClassIter = groupIter->second.find(pSoldier->ubSoldierClass); - if (soldierClassIter != groupIter->second.end()) - { - // found a matching soldierclass - if (soldierClassIter->second > 0) - { - // there are still un-updated soldiers! begin the update! - soldierClassIter->second--; - - // rftr todo: move this into its own function - // rftr todo: don't forget to call this for reinforcing troops! - // adjust soldier inventory for transport groups - - // ideas: - // soldiers have backpacks + kits + ammo box (BONUS: make sure the backpack goes in the backpack slot for lobot compatibility. that might be a fix outside of this feature tho) - // jeeps have ammo crates and/or lots of boxes. reduce bullet count in crate? - - // add backpack to soldier's inventory! - OBJECTTYPE itemToAdd; - if (backpacks.size() > 0) - { - CreateItem(backpacks[0], 75 + Random(25), &itemToAdd); - pSoldier->inv[BPACKPOCKPOS] = itemToAdd; - } - - // add ammo to the soldier's inventory! - CreateItem(ammoBoxes[10][0], (INT8)(90+Random(10)), &itemToAdd); - addItemToInventory(pSoldier, itemToAdd); - - // force inventory to be dropped! - for (int i = 0; i < pSoldier->inv.size(); ++i) - { - OBJECTTYPE* item = &pSoldier->inv[i]; - if (item->exists() && Item[item->usItem].defaultundroppable == FALSE) - { - item->fFlags &= ~OBJECT_UNDROPPABLE; - } - } - } - } - } - } - } -} diff --git a/Strategic/Strategic AI.cpp b/Strategic/Strategic AI.cpp index 5835bee4c..521ba2056 100644 --- a/Strategic/Strategic AI.cpp +++ b/Strategic/Strategic AI.cpp @@ -40,6 +40,7 @@ #include "Rebel Command.h" #include "Game Event Hook.h" #include "Strategic Town Loyalty.h" + #include "Strategic Transport Groups.h" #endif #include "GameInitOptionsScreen.h" @@ -496,7 +497,6 @@ extern INT16 sWorldSectorLocationOfFirstBattle; void ReassignAIGroup( GROUP **pGroup ); void TransferGroupToPool( GROUP **pGroup ); -void SendGroupToPool( GROUP **pGroup ); //Simply orders all garrisons to take troops from the patrol groups and send the closest troops from them. Any garrison, //whom there request isn't fulfilled (due to lack of troops), will recieve their reinforcements from the queen (P3). @@ -2428,93 +2428,7 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Strategic5"); } else if (pGroup->pEnemyGroup->ubIntention == TRANSPORT) { - // rftr todo: something depending if we're in spawn or at target destination - const UINT8 difficulty = gGameOptions.ubDifficultyLevel; - - // just arrived, let's go home - if (pGroup->ubSectorX != gModSettings.ubSAISpawnSectorX && pGroup->ubSectorY != gModSettings.ubSAISpawnSectorY) - { - pGroup->ubSectorIDOfLastReassignment = (UINT8)SECTOR( pGroup->ubSectorX, pGroup->ubSectorY ); - - // global loyalty loss - INT32 loyaltyLoss = 0; - switch (difficulty) - { - case DIF_LEVEL_EASY: loyaltyLoss = 0; break; - case DIF_LEVEL_MEDIUM: loyaltyLoss = -100; break; - case DIF_LEVEL_HARD: loyaltyLoss = -250; break; - case DIF_LEVEL_INSANE: loyaltyLoss = -500; break; - } - // rftr todo: this is the "proper" way to do it - letting lua handle it. requires adding an enum value in Strategic Town Loyalty.h (GlobalLoyaltyEventTypes) - //HandleGlobalLoyaltyEvent(-1, pGroup->ubSectorX, pGroup->ubSectorY, pGroup->ubSectorZ); - //... which calls this: - AffectAllTownsLoyaltyByDistanceFrom(loyaltyLoss, pGroup->ubSectorX, pGroup->ubSectorY, pGroup->ubSectorZ); - - // on reach target ideas: - // disease: reduction in target town? - // volunteer pool reduction? can we do that? - - // queue up return home order - AddStrategicEvent(EVENT_RETURN_TRANSPORT_GROUP, GetWorldTotalMin() + 60 * 6, pGroup->ubGroupID); - } - else - { - // asd income injection and bonus update - if (gGameExternalOptions.fASDActive) - { - INT32 moneyAmt = 0; - INT32 fuelAmt = 0; - - switch (difficulty) - { - case DIF_LEVEL_EASY: - moneyAmt = 0; - fuelAmt = 0; - break; - - case DIF_LEVEL_MEDIUM: - moneyAmt = gGameExternalOptions.gASDResource_Cost[ASD_JEEP] * 0.5f; - fuelAmt = gGameExternalOptions.gASDResource_Fuel_Jeep * 0.5f; - break; - - case DIF_LEVEL_HARD: - moneyAmt = gGameExternalOptions.gASDResource_Cost[ASD_JEEP]; - fuelAmt = gGameExternalOptions.gASDResource_Fuel_Jeep; - break; - - case DIF_LEVEL_INSANE: - moneyAmt = gGameExternalOptions.gASDResource_Cost[ASD_JEEP] + gGameExternalOptions.gASDResource_Cost[ASD_TANK]; - fuelAmt = gGameExternalOptions.gASDResource_Fuel_Jeep + gGameExternalOptions.gASDResource_Fuel_Tank; - break; - } - - AddStrategicAIResources(ASD_MONEY, moneyAmt); - AddStrategicAIResources(ASD_FUEL, fuelAmt); - UpdateASD(); - } - - // reinforcement pool increase - if (!gfUnlimitedTroops) - { - INT32 poolAmt = 0; - switch (difficulty) - { - case DIF_LEVEL_EASY: poolAmt = 0; break; - case DIF_LEVEL_MEDIUM: poolAmt = 10; break; - case DIF_LEVEL_HARD: poolAmt = 15; break; - case DIF_LEVEL_INSANE: poolAmt = 40; break; - } - - giReinforcementPool += poolAmt; - } - - // successfully returned home. give the strategic ai some rewards! - SendGroupToPool(&pGroup); - - // immediately do a queen evaluation - DeleteAllStrategicEventsOfType(EVENT_EVALUATE_QUEEN_SITUATION); - EvaluateQueenSituation(); - } + ProcessTransportGroupReachedDestination(pGroup); return TRUE; // do we just call ReassignAIGroup or SendGroupToPool to dissolve and remove the group? } @@ -3559,6 +3473,7 @@ void EvaluateQueenSituation() uiOffset += dEnemyGeneralsSpeedupFactor * (zDiffSetting[gGameOptions.ubDifficultyLevel].iBaseDelayInMinutesBetweenEvaluations + Random( zDiffSetting[gGameOptions.ubDifficultyLevel].iEvaluationDelayVariance )); + // rftr todo: send transport group here? ScreenMsg( FONT_RED, MSG_INTERFACE, L"Evaluating queen situation..."); // Check/update reinforcements pool if old behavior is enabled @@ -5489,50 +5404,11 @@ void ExecuteStrategicAIAction( UINT16 usActionCode, INT16 sSectorX, INT16 sSecto break; case NPC_ACTION_DEPLOY_TRANSPORT_GROUP: - // rftr todo: create a new group in the capital (same as attack/patrol groups) and send it to a friendly town with a mine! - // limitations: max number of transport groups at any given time - // track recent transport group interceptions - // varying transport group quality/compositions - // copied from NPC_ACTION_SEND_SOLDIERS_TO_BATTLE_LOCATION, which happens after the first non-welcome wagon battle - // rftr todo: replace this with townid - // rftr todo: only pick towns that 1) have mines, and 2) are uncontested - ubSectorID = (UINT8)STRATEGIC_INDEX_TO_SECTOR_INFO( sWorldSectorLocationOfFirstBattle ); - pSector = &SectorInfo[ ubSectorID ]; - - // rftr: adjust group size and composition based on recent interceptions, game progress, etc - ubNumSoldiers = 17; - - //InitializeGroup(GROUP_TYPE_TRANSPORT, ubNumSoldiers, grouptroops[0], groupelites[0], grouprobots[0], groupjeeps[0], grouptanks[0], Random(10) < difficultyMod); - //totalusedsoldiers += grouptroops[0] + groupelites[0] + grouprobots[0] + grouptanks[0] + groupjeeps[0]; - - //pGroup = CreateNewEnemyGroupDepartingFromSector( SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), 0, grouptroops[0], groupelites[0], grouprobots[0], grouptanks[0], groupjeeps[0] ); - pGroup = CreateNewEnemyGroupDepartingFromSector( SEC_D5, 10, 5, 1, 0, 0, 1 ); - - //Madd: unlimited reinforcements? - if ( !gfUnlimitedTroops ) - { - giReinforcementPool -= ubNumSoldiers; - - giReinforcementPool = max( giReinforcementPool, 0 ); - } - - MoveSAIGroupToSector( &pGroup, ubSectorID, EVASIVE, TRANSPORT ); + DeployTransportGroup(sWorldSectorLocationOfFirstBattle); break; case NPC_ACTION_RETURN_TRANSPORT_GROUP: - pGroup = gpGroupList; - while (pGroup) - { - if (pGroup->ubGroupID == option1) - { - MoveSAIGroupToSector( &pGroup, SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), EVASIVE, TRANSPORT ); - break; - } - pGroup = pGroup->next; - } - - if (pGroup == nullptr) - ScreenMsg( FONT_YELLOW, MSG_INTERFACE, L"RETURN_TRANSPORT_GROUP failed to find groupid %d", option1); + ReturnTransportGroup(option1); break; default: diff --git a/Strategic/Strategic AI.h b/Strategic/Strategic AI.h index 14fd3581f..5c7986af3 100644 --- a/Strategic/Strategic AI.h +++ b/Strategic/Strategic AI.h @@ -38,6 +38,7 @@ BOOLEAN StrategicAILookForAdjacentGroups( GROUP *pGroup ); void RemoveGroupFromStrategicAILists( UINT8 ubGroupID ); void RecalculateSectorWeight( UINT8 ubSectorID ); void RecalculateGroupWeight( GROUP *pGroup ); +void SendGroupToPool( GROUP **pGroup ); BOOLEAN OkayForEnemyToMoveThroughSector( UINT8 ubSectorID ); BOOLEAN EnemyPermittedToAttackSector( GROUP **pGroup, UINT8 ubSectorID ); diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp new file mode 100644 index 000000000..ee9b12d84 --- /dev/null +++ b/Strategic/Strategic Transport Groups.cpp @@ -0,0 +1,371 @@ +/* +Strategic Transport Groups +by rftr + +Strategic transport groups are a type of enemy strategic group in addition to ATTACK and PATROL groups. The primary purpose +of transport groups is to function as a loot pinata for the player. However, they will generally be behind enemy lines, so +the player will have to seek them out. + +Behaviourally, transport groups will spawn at the AI's HQ and then travel to a friendly town. Once the group reaches its +destination, it will wait for a few hours before returning home, where it despawns. The AI will receive small bonuses +upon the group successfully reaching both its destination and HQ. + +A transport group always flags its members to drop everything they have regardless of the player's DROP_ALL setting. In +addition, transport groups will also be carrying supplies that the player may find useful. + +Transport group compositions will vary based on the player's progress, how many interceptions have been completed recently, +and the difficulty of the game. + +*/ +#include "Strategic Transport Groups.h" + +#include "ASD.h" +#include "Game Clock.h" +#include "Game Event Hook.h" +#include "message.h" +#include "Overhead.h" +#include "Overhead Types.h" +#include "random.h" +#include "Strategic AI.h" +#include "strategicmap.h" +#include "Strategic Movement.h" +#include "Strategic Town Loyalty.h" + +std::map> gTransportGroupIdToSoldierMap; + +BOOLEAN DeployTransportGroup(INT16 sWorldSectorLocationOfFirstBattle) +{ + INT8 transportGroupCount = 0; + GROUP* pGroup = gpGroupList; + while (pGroup) + { + if (pGroup->usGroupTeam == ENEMY_TEAM && pGroup->pEnemyGroup->ubIntention == TRANSPORT) + { + transportGroupCount++; + } + pGroup = pGroup->next; + } + + // if there are too many active transport groups, don't deploy any more + // rftr todo: based on difficulty? + if (transportGroupCount >= 5) return FALSE; + // rftr todo: create a new group in the capital (same as attack/patrol groups) and send it to a friendly town with a mine! + // limitations: max number of transport groups at any given time + // track recent transport group interceptions + // varying transport group quality/compositions + // copied from NPC_ACTION_SEND_SOLDIERS_TO_BATTLE_LOCATION, which happens after the first non-welcome wagon battle + // rftr todo: replace this with townid + // rftr todo: only pick towns that 1) have mines, and 2) are uncontested + const UINT8 ubSectorID = (UINT8)STRATEGIC_INDEX_TO_SECTOR_INFO( sWorldSectorLocationOfFirstBattle ); + const SECTORINFO* pSector = &SectorInfo[ ubSectorID ]; + + // rftr: adjust group size and composition based on recent interceptions, game progress, etc + const INT32 ubNumSoldiers = 17; + + //InitializeGroup(GROUP_TYPE_TRANSPORT, ubNumSoldiers, grouptroops[0], groupelites[0], grouprobots[0], groupjeeps[0], grouptanks[0], Random(10) < difficultyMod); + //totalusedsoldiers += grouptroops[0] + groupelites[0] + grouprobots[0] + grouptanks[0] + groupjeeps[0]; + + //pGroup = CreateNewEnemyGroupDepartingFromSector( SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), 0, grouptroops[0], groupelites[0], grouprobots[0], grouptanks[0], groupjeeps[0] ); + pGroup = CreateNewEnemyGroupDepartingFromSector( SEC_D5, 10, 5, 1, 0, 0, 1 ); + + //Madd: unlimited reinforcements? + if ( !gfUnlimitedTroops ) + { + giReinforcementPool -= ubNumSoldiers; + + giReinforcementPool = max( giReinforcementPool, 0 ); + } + + MoveSAIGroupToSector( &pGroup, ubSectorID, EVASIVE, TRANSPORT ); + + return TRUE; +} + +BOOLEAN ReturnTransportGroup(INT32 option1) +{ + GROUP* pGroup = gpGroupList; + while (pGroup) + { + if (pGroup->ubGroupID == option1) + { + MoveSAIGroupToSector( &pGroup, SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), EVASIVE, TRANSPORT ); + break; + } + pGroup = pGroup->next; + } + + if (pGroup == nullptr) + { + ScreenMsg( FONT_YELLOW, MSG_INTERFACE, L"RETURN_TRANSPORT_GROUP failed to find groupid %d", option1); + return FALSE; + } + + return TRUE; +} + +void ProcessTransportGroupReachedDestination(GROUP* pGroup) +{ + // rftr todo: something depending if we're in spawn or at target destination + const UINT8 difficulty = gGameOptions.ubDifficultyLevel; + + // just arrived, let's go home + if (pGroup->ubSectorX != gModSettings.ubSAISpawnSectorX && pGroup->ubSectorY != gModSettings.ubSAISpawnSectorY) + { + pGroup->ubSectorIDOfLastReassignment = (UINT8)SECTOR( pGroup->ubSectorX, pGroup->ubSectorY ); + + // global loyalty loss + INT32 loyaltyLoss = 0; + switch (difficulty) + { + case DIF_LEVEL_EASY: loyaltyLoss = 0; break; + case DIF_LEVEL_MEDIUM: loyaltyLoss = -100; break; + case DIF_LEVEL_HARD: loyaltyLoss = -200; break; + case DIF_LEVEL_INSANE: loyaltyLoss = -500; break; + } + // rftr todo: this is the "proper" way to do it - letting lua handle it. requires adding an enum value in Strategic Town Loyalty.h (GlobalLoyaltyEventTypes) + //HandleGlobalLoyaltyEvent(-1, pGroup->ubSectorX, pGroup->ubSectorY, pGroup->ubSectorZ); + //... which calls this: + AffectAllTownsLoyaltyByDistanceFrom(loyaltyLoss, pGroup->ubSectorX, pGroup->ubSectorY, pGroup->ubSectorZ); + + // on reach target ideas: + // disease: reduction in target town? + // volunteer pool reduction? can we do that? + + // queue up return home order + AddStrategicEvent(EVENT_RETURN_TRANSPORT_GROUP, GetWorldTotalMin() + 60 * 6, pGroup->ubGroupID); + } + else + { + // asd income injection and bonus update + if (gGameExternalOptions.fASDActive) + { + INT32 moneyAmt = 0; + INT32 fuelAmt = 0; + + switch (difficulty) + { + case DIF_LEVEL_EASY: + moneyAmt = 0; + fuelAmt = 0; + break; + + case DIF_LEVEL_MEDIUM: + moneyAmt = gGameExternalOptions.gASDResource_Cost[ASD_JEEP] * 0.5f; + fuelAmt = gGameExternalOptions.gASDResource_Fuel_Jeep * 0.5f; + break; + + case DIF_LEVEL_HARD: + moneyAmt = gGameExternalOptions.gASDResource_Cost[ASD_JEEP]; + fuelAmt = gGameExternalOptions.gASDResource_Fuel_Jeep; + break; + + case DIF_LEVEL_INSANE: + moneyAmt = gGameExternalOptions.gASDResource_Cost[ASD_JEEP] + gGameExternalOptions.gASDResource_Cost[ASD_TANK]; + fuelAmt = gGameExternalOptions.gASDResource_Fuel_Jeep + gGameExternalOptions.gASDResource_Fuel_Tank; + break; + } + + AddStrategicAIResources(ASD_MONEY, moneyAmt); + AddStrategicAIResources(ASD_FUEL, fuelAmt); + UpdateASD(); + } + + // reinforcement pool increase + if (!gfUnlimitedTroops) + { + INT32 poolAmt = 0; + switch (difficulty) + { + case DIF_LEVEL_EASY: poolAmt = 0; break; + case DIF_LEVEL_MEDIUM: poolAmt = 10; break; + case DIF_LEVEL_HARD: poolAmt = 15; break; + case DIF_LEVEL_INSANE: poolAmt = 40; break; + } + + giReinforcementPool += poolAmt; + } + + // successfully returned home. give the strategic ai some rewards! + SendGroupToPool(&pGroup); + + // immediately do a queen evaluation + DeleteAllStrategicEventsOfType(EVENT_EVALUATE_QUEEN_SITUATION); + EvaluateQueenSituation(); + } +} + +void UpdateTransportGroupInventory(std::map> &groupIdToSoldierMap) +{ + const int firstSlot = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID; + const int lastSlot = gTacticalStatus.Team[ ENEMY_TEAM ].bLastID; + + // rftr todo: detect whether this group is going to/from HQ, + // and update loot accordingly + + // rftr todo: do this on init/load somewhere + // do some prep + std::vector gasCans; + std::vector firstAidKits; + std::vector medKits; + std::vector toolKits; + std::vector backpacks; + std::map> ammoBoxes; // map coolness to ammo vector + std::map> ammoCrates; // map coolness to ammo vector + + // one-time item cache build + { + // rftr todo: see if we can replace this with random items. + // requirement: probably a new flag in Items.xml, or something + // add new groups in RandomItem.xml + // the new items will reference the new group in randomitem, eg 23 in Items.xml matches uiIndex 23 in RandomItem.xml + // fallback if no random items found? for mods and stuff (thinking sdo) + for (UINT16 i = 0; i < MAXITEMS; ++i) + { + if (Item[i].gascan) gasCans.push_back(i); + else if (Item[i].firstaidkit) firstAidKits.push_back(i); + else if (Item[i].medicalkit) medKits.push_back(i); + else if (Item[i].toolkit) toolKits.push_back(i); + else if (Item[i].usItemClass & IC_LBEGEAR) + { + if (LoadBearingEquipment[Item[i].ubClassIndex].lbeClass == BACKPACK) + { + // todo get actual backpacks, not covert ones, tactical slings, golf clubs, etc... + backpacks.push_back(i); + } + } + else if (Item[i].usItemClass & IC_AMMO) + { + if (Magazine[Item[i].ubClassIndex].ubMagType == AMMO_BOX + || Magazine[Item[i].ubClassIndex].ubMagType == AMMO_CRATE) + { + if ((gGameOptions.fGunNut || !Item[i].biggunlist) + && (gGameOptions.ubGameStyle == STYLE_SCIFI || !Item[i].scifi)) + { + if (Magazine[Item[i].ubClassIndex].ubMagType == AMMO_BOX) + ammoBoxes[Item[i].ubCoolness].push_back(i); + else + ammoCrates[Item[i].ubCoolness].push_back(i); + } + } + } + } + } + + auto addItemToInventory = [](SOLDIERTYPE* pSoldier, OBJECTTYPE& itemToAdd) + { + itemToAdd.fFlags &= ~OBJECT_UNDROPPABLE; + + if (FitsInSmallPocket(&itemToAdd)) + { + for(INT8 i = SMALLPOCKSTART; i < SMALLPOCKFINAL; i++ ) + { + if( pSoldier->inv[ i ].exists() == false && !(pSoldier->inv[ i ].fFlags & OBJECT_NO_OVERWRITE) ) + { + pSoldier->inv[ i ] = itemToAdd; + break; + } + } + } + else + { + for(INT8 i = BIGPOCKSTART; i < BIGPOCKFINAL; i++ ) + { //no space free in small pockets, so put it into a large pocket. + if( pSoldier->inv[ i ].exists() == false && !(pSoldier->inv[ i ].fFlags & OBJECT_NO_OVERWRITE) ) + { + pSoldier->inv[ i ] = itemToAdd; + break; + } + } + } + }; + + for (int slot = firstSlot; (slot <= lastSlot); ++slot) + { + SOLDIERTYPE* pSoldier = &Menptr[slot]; + + const std::map>::iterator groupIter = groupIdToSoldierMap.find(pSoldier->ubGroupID); + if (groupIter != groupIdToSoldierMap.end()) + { + // found a matching transport groupid + std::map::iterator soldierClassIter = groupIter->second.find(SOLDIER_CLASS_JEEP); + if (soldierClassIter != groupIter->second.end()) + { + // this group has a jeep in it! + // only jeeps carry things + // but give a little extra, since the jeep exploding can outright destroy things + if (pSoldier->ubSoldierClass == SOLDIER_CLASS_JEEP) + { + OBJECTTYPE itemToAdd; + for (int i = 0; i < 3; ++i) + { + CreateItem(ammoBoxes[5][0], 100, &itemToAdd); + addItemToInventory(pSoldier, itemToAdd); + } + + for (int i = 0; i < 3; ++i) + { + CreateItem(medKits[Random(medKits.size())], 100, &itemToAdd); + addItemToInventory(pSoldier, itemToAdd); + } + groupIdToSoldierMap[pSoldier->ubGroupID][SOLDIER_CLASS_JEEP]--; + } + else // not a jeep + { + // force inventory to be dropped! + for (int i = 0; i < pSoldier->inv.size(); ++i) + { + OBJECTTYPE* item = &pSoldier->inv[i]; + if (item->exists() && Item[item->usItem].defaultundroppable == FALSE) + { + item->fFlags &= ~OBJECT_UNDROPPABLE; + } + } + } + } + else + { + // no jeep in group, add things normally + soldierClassIter = groupIter->second.find(pSoldier->ubSoldierClass); + if (soldierClassIter != groupIter->second.end()) + { + // found a matching soldierclass + if (soldierClassIter->second > 0) + { + // there are still un-updated soldiers! begin the update! + soldierClassIter->second--; + + // rftr todo: move this into its own function + // rftr todo: don't forget to call this for reinforcing troops! + // adjust soldier inventory for transport groups + + // ideas: + // soldiers have backpacks + kits + ammo box (BONUS: make sure the backpack goes in the backpack slot for lobot compatibility. that might be a fix outside of this feature tho) + // jeeps have ammo crates and/or lots of boxes. reduce bullet count in crate? + + // add backpack to soldier's inventory! + OBJECTTYPE itemToAdd; + if (backpacks.size() > 0) + { + CreateItem(backpacks[0], 75 + Random(25), &itemToAdd); + pSoldier->inv[BPACKPOCKPOS] = itemToAdd; + } + + // add ammo to the soldier's inventory! + CreateItem(ammoBoxes[10][0], (INT8)(90+Random(10)), &itemToAdd); + addItemToInventory(pSoldier, itemToAdd); + + // force inventory to be dropped! + for (int i = 0; i < pSoldier->inv.size(); ++i) + { + OBJECTTYPE* item = &pSoldier->inv[i]; + if (item->exists() && Item[item->usItem].defaultundroppable == FALSE) + { + item->fFlags &= ~OBJECT_UNDROPPABLE; + } + } + } + } + } + } + } +} diff --git a/Strategic/Strategic Transport Groups.h b/Strategic/Strategic Transport Groups.h new file mode 100644 index 000000000..aa05e98be --- /dev/null +++ b/Strategic/Strategic Transport Groups.h @@ -0,0 +1,16 @@ +#ifndef _STRATEGIC_TRANSPORT_GROUPS_H +#define _STRATEGIC_TRANSPORT_GROUPS_H + +#include +#include "Types.h" + +struct GROUP; + +BOOLEAN DeployTransportGroup(INT16); +BOOLEAN ReturnTransportGroup(INT32); +void ProcessTransportGroupReachedDestination(GROUP* pGroup); +void UpdateTransportGroupInventory(std::map> &groupIdToSoldierMap); + +extern std::map> gTransportGroupIdToSoldierMap; // groupId -> soldierclass, count + +#endif diff --git a/Strategic/Strategic_VS2005.vcproj b/Strategic/Strategic_VS2005.vcproj index 348378c5f..61783a591 100644 --- a/Strategic/Strategic_VS2005.vcproj +++ b/Strategic/Strategic_VS2005.vcproj @@ -530,6 +530,10 @@ RelativePath=".\strategic town reputation.h" > + + @@ -748,6 +752,10 @@ RelativePath=".\strategic town reputation.cpp" > + + diff --git a/Strategic/Strategic_VS2008.vcproj b/Strategic/Strategic_VS2008.vcproj index 5854184c9..2441dd827 100644 --- a/Strategic/Strategic_VS2008.vcproj +++ b/Strategic/Strategic_VS2008.vcproj @@ -526,6 +526,10 @@ RelativePath="Strategic Town Loyalty.h" > + + @@ -746,6 +750,10 @@ RelativePath="strategic town reputation.cpp" > + + diff --git a/Strategic/Strategic_VS2010.vcxproj b/Strategic/Strategic_VS2010.vcxproj index 87c89ffe3..6c99934b4 100644 --- a/Strategic/Strategic_VS2010.vcxproj +++ b/Strategic/Strategic_VS2010.vcxproj @@ -71,6 +71,7 @@ + @@ -126,6 +127,7 @@ + diff --git a/Strategic/Strategic_VS2013.vcxproj b/Strategic/Strategic_VS2013.vcxproj index 5f7c10387..4528402c6 100644 --- a/Strategic/Strategic_VS2013.vcxproj +++ b/Strategic/Strategic_VS2013.vcxproj @@ -71,6 +71,7 @@ + @@ -126,6 +127,7 @@ + diff --git a/Strategic/Strategic_VS2017.vcxproj b/Strategic/Strategic_VS2017.vcxproj index 0995eb006..066507be2 100644 --- a/Strategic/Strategic_VS2017.vcxproj +++ b/Strategic/Strategic_VS2017.vcxproj @@ -71,6 +71,7 @@ + @@ -126,6 +127,7 @@ + diff --git a/Strategic/Strategic_VS2019.vcxproj b/Strategic/Strategic_VS2019.vcxproj index 4337e3f21..6c58c5df0 100644 --- a/Strategic/Strategic_VS2019.vcxproj +++ b/Strategic/Strategic_VS2019.vcxproj @@ -91,6 +91,7 @@ + @@ -146,6 +147,7 @@ + From 5791575d2048322d9a505fec7579e9ad0be4aaac Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Fri, 23 Dec 2022 12:04:10 -0800 Subject: [PATCH 14/81] Remove global transport group map --- Strategic/Queen Command.cpp | 36 ++++++++++-------------- Strategic/Strategic Transport Groups.cpp | 21 ++++++++++---- Strategic/Strategic Transport Groups.h | 5 ++-- 3 files changed, 34 insertions(+), 28 deletions(-) diff --git a/Strategic/Queen Command.cpp b/Strategic/Queen Command.cpp index 58a96182b..9c675c734 100644 --- a/Strategic/Queen Command.cpp +++ b/Strategic/Queen Command.cpp @@ -619,7 +619,7 @@ BOOLEAN PrepareEnemyForSectorBattle() gfPendingNonPlayerTeam[ENEMY_TEAM] = FALSE; // rftr: clear cached transport groups - gTransportGroupIdToSoldierMap.clear(); + ClearTransportGroupMap(); if( gbWorldSectorZ > 0 ) return PrepareEnemyForUndergroundBattle(); @@ -680,12 +680,12 @@ BOOLEAN PrepareEnemyForSectorBattle() // for transport groups, track how many enemies of each type we're adding so we can update drops for them if (pGroup->usGroupTeam == ENEMY_TEAM && pGroup->pEnemyGroup->ubIntention == TRANSPORT && pGroup->ubSectorX == gWorldSectorX && pGroup->ubSectorY == gWorldSectorY && !gbWorldSectorZ) { - gTransportGroupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_ADMINISTRATOR] += pGroup->pEnemyGroup->ubNumAdmins; - gTransportGroupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_ARMY] += pGroup->pEnemyGroup->ubNumTroops; - gTransportGroupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_ELITE] += pGroup->pEnemyGroup->ubNumElites; - gTransportGroupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_ROBOT] += pGroup->pEnemyGroup->ubNumRobots; - gTransportGroupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_JEEP] += pGroup->pEnemyGroup->ubNumJeeps; - gTransportGroupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_TANK] += pGroup->pEnemyGroup->ubNumTanks; + AddToTransportGroupMap(pGroup->ubGroupID, SOLDIER_CLASS_ADMINISTRATOR, pGroup->pEnemyGroup->ubNumAdmins); + AddToTransportGroupMap(pGroup->ubGroupID, SOLDIER_CLASS_ARMY, pGroup->pEnemyGroup->ubNumTroops); + AddToTransportGroupMap(pGroup->ubGroupID, SOLDIER_CLASS_ELITE, pGroup->pEnemyGroup->ubNumElites); + AddToTransportGroupMap(pGroup->ubGroupID, SOLDIER_CLASS_ROBOT, pGroup->pEnemyGroup->ubNumRobots); + AddToTransportGroupMap(pGroup->ubGroupID, SOLDIER_CLASS_JEEP, pGroup->pEnemyGroup->ubNumJeeps); + AddToTransportGroupMap(pGroup->ubGroupID, SOLDIER_CLASS_TANK, pGroup->pEnemyGroup->ubNumTanks); } pGroup = pGroup->next; @@ -693,10 +693,7 @@ BOOLEAN PrepareEnemyForSectorBattle() } // rftr todo: check if feature is enabled - if (gTransportGroupIdToSoldierMap.size() > 0) - { - UpdateTransportGroupInventory(gTransportGroupIdToSoldierMap); - } + UpdateTransportGroupInventory(); ValidateEnemiesHaveWeapons(); UnPauseGame(); @@ -893,7 +890,7 @@ BOOLEAN PrepareEnemyForSectorBattle() ubTotalAdmins += ubNumAdmins; if (isTransportGroup) - gTransportGroupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_ADMINISTRATOR] += ubNumAdmins; + AddToTransportGroupMap(pGroup->ubGroupID, SOLDIER_CLASS_ADMINISTRATOR, ubNumAdmins); } if( sNumSlots > 0 ) { //Add regular army forces. @@ -910,7 +907,7 @@ BOOLEAN PrepareEnemyForSectorBattle() ubTotalTroops += ubNumTroops; if (isTransportGroup) - gTransportGroupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_ARMY] += ubNumTroops; + AddToTransportGroupMap(pGroup->ubGroupID, SOLDIER_CLASS_ARMY, ubNumTroops); } if( sNumSlots > 0 ) { //Add elite troops @@ -927,7 +924,7 @@ BOOLEAN PrepareEnemyForSectorBattle() ubTotalElites += ubNumElites; if (isTransportGroup) - gTransportGroupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_ELITE] += ubNumElites; + AddToTransportGroupMap(pGroup->ubGroupID, SOLDIER_CLASS_ELITE, ubNumElites); } if( sNumSlots > 0 ) { //Add robots @@ -944,7 +941,7 @@ BOOLEAN PrepareEnemyForSectorBattle() ubTotalRobots += ubNumRobots; if (isTransportGroup) - gTransportGroupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_ROBOT] += ubNumRobots; + AddToTransportGroupMap(pGroup->ubGroupID, SOLDIER_CLASS_ROBOT, ubNumRobots); } if( sNumSlots > 0 ) { //Add tanks @@ -961,7 +958,7 @@ BOOLEAN PrepareEnemyForSectorBattle() ubTotalTanks += ubNumTanks; if (isTransportGroup) - gTransportGroupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_TANK] += ubNumTanks; + AddToTransportGroupMap(pGroup->ubGroupID, SOLDIER_CLASS_TANK, ubNumTanks); } if ( sNumSlots > 0 ) { @@ -979,7 +976,7 @@ BOOLEAN PrepareEnemyForSectorBattle() ubTotalJeeps += ubNumJeeps; if (isTransportGroup) - gTransportGroupIdToSoldierMap[pGroup->ubGroupID][SOLDIER_CLASS_JEEP] += ubNumJeeps; + AddToTransportGroupMap(pGroup->ubGroupID, SOLDIER_CLASS_JEEP, ubNumJeeps); } //NOTE: //no provisions for profile troop leader or retreat groups yet. @@ -1150,10 +1147,7 @@ BOOLEAN PrepareEnemyForSectorBattle() } // rftr todo: check if feature is enabled - if (gTransportGroupIdToSoldierMap.size() > 0) - { - UpdateTransportGroupInventory(gTransportGroupIdToSoldierMap); - } + UpdateTransportGroupInventory(); ValidateEnemiesHaveWeapons(); UnPauseGame(); diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index ee9b12d84..5a93c45a6 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -31,7 +31,7 @@ and the difficulty of the game. #include "Strategic Movement.h" #include "Strategic Town Loyalty.h" -std::map> gTransportGroupIdToSoldierMap; +std::map> transportGroupIdToSoldierMap; BOOLEAN DeployTransportGroup(INT16 sWorldSectorLocationOfFirstBattle) { @@ -194,7 +194,7 @@ void ProcessTransportGroupReachedDestination(GROUP* pGroup) } } -void UpdateTransportGroupInventory(std::map> &groupIdToSoldierMap) +void UpdateTransportGroupInventory() { const int firstSlot = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID; const int lastSlot = gTacticalStatus.Team[ ENEMY_TEAM ].bLastID; @@ -283,8 +283,8 @@ void UpdateTransportGroupInventory(std::map> &groupI { SOLDIERTYPE* pSoldier = &Menptr[slot]; - const std::map>::iterator groupIter = groupIdToSoldierMap.find(pSoldier->ubGroupID); - if (groupIter != groupIdToSoldierMap.end()) + const std::map>::iterator groupIter = transportGroupIdToSoldierMap.find(pSoldier->ubGroupID); + if (groupIter != transportGroupIdToSoldierMap.end()) { // found a matching transport groupid std::map::iterator soldierClassIter = groupIter->second.find(SOLDIER_CLASS_JEEP); @@ -307,7 +307,7 @@ void UpdateTransportGroupInventory(std::map> &groupI CreateItem(medKits[Random(medKits.size())], 100, &itemToAdd); addItemToInventory(pSoldier, itemToAdd); } - groupIdToSoldierMap[pSoldier->ubGroupID][SOLDIER_CLASS_JEEP]--; + transportGroupIdToSoldierMap[pSoldier->ubGroupID][SOLDIER_CLASS_JEEP]--; } else // not a jeep { @@ -369,3 +369,14 @@ void UpdateTransportGroupInventory(std::map> &groupI } } } + +void AddToTransportGroupMap(UINT8 groupId, int soldierClass, UINT8 amount) +{ + transportGroupIdToSoldierMap[groupId][soldierClass] += amount; +} + +void ClearTransportGroupMap() +{ + transportGroupIdToSoldierMap.clear(); +} + diff --git a/Strategic/Strategic Transport Groups.h b/Strategic/Strategic Transport Groups.h index aa05e98be..11049139c 100644 --- a/Strategic/Strategic Transport Groups.h +++ b/Strategic/Strategic Transport Groups.h @@ -9,8 +9,9 @@ struct GROUP; BOOLEAN DeployTransportGroup(INT16); BOOLEAN ReturnTransportGroup(INT32); void ProcessTransportGroupReachedDestination(GROUP* pGroup); -void UpdateTransportGroupInventory(std::map> &groupIdToSoldierMap); +void UpdateTransportGroupInventory(); -extern std::map> gTransportGroupIdToSoldierMap; // groupId -> soldierclass, count +void AddToTransportGroupMap(UINT8 groupId, int soldierClass, UINT8 amount); +void ClearTransportGroupMap(); #endif From 92a514ad737d623b20e0bc0d8890e01a4a0a97ef Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Fri, 23 Dec 2022 12:24:38 -0800 Subject: [PATCH 15/81] Groups with jeeps: admins/troops/elites drop everything --- Strategic/Strategic Transport Groups.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index 5a93c45a6..2937e8459 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -309,7 +309,9 @@ void UpdateTransportGroupInventory() } transportGroupIdToSoldierMap[pSoldier->ubGroupID][SOLDIER_CLASS_JEEP]--; } - else // not a jeep + else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR + || pSoldier->ubSoldierClass == SOLDIER_CLASS_ARMY + || pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE) { // force inventory to be dropped! for (int i = 0; i < pSoldier->inv.size(); ++i) From 0410b0a097164c34158ac322b32394e4e678a07d Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Fri, 23 Dec 2022 18:48:07 -0800 Subject: [PATCH 16/81] Deploy groups during queen evals Limit inventory modifications to soldiers and jeeps Group targets a random friendly uncontested mine --- Strategic/Strategic AI.cpp | 4 +- Strategic/Strategic Transport Groups.cpp | 54 ++++++++++++++++++++++-- Strategic/Strategic Transport Groups.h | 2 +- 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/Strategic/Strategic AI.cpp b/Strategic/Strategic AI.cpp index 521ba2056..27c976b60 100644 --- a/Strategic/Strategic AI.cpp +++ b/Strategic/Strategic AI.cpp @@ -3505,6 +3505,8 @@ void EvaluateQueenSituation() // Gradually promote any remaining admins into troops UpgradeAdminsToTroops(); + ExecuteStrategicAIAction( NPC_ACTION_DEPLOY_TRANSPORT_GROUP, 0, 0 ); + if( ( giRequestPoints <= 0 ) || ( ( giReinforcementPoints <= 0 ) && ( giReinforcementPool <= 0 ) ) ) { //we either have no reinforcements or request for reinforcements. return; @@ -5404,7 +5406,7 @@ void ExecuteStrategicAIAction( UINT16 usActionCode, INT16 sSectorX, INT16 sSecto break; case NPC_ACTION_DEPLOY_TRANSPORT_GROUP: - DeployTransportGroup(sWorldSectorLocationOfFirstBattle); + DeployTransportGroup(); break; case NPC_ACTION_RETURN_TRANSPORT_GROUP: diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index 2937e8459..efbf3d447 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -26,15 +26,46 @@ and the difficulty of the game. #include "Overhead.h" #include "Overhead Types.h" #include "random.h" +#include "strategic.h" #include "Strategic AI.h" #include "strategicmap.h" +#include "Strategic Mines.h" #include "Strategic Movement.h" #include "Strategic Town Loyalty.h" + +extern BOOLEAN gfTownUsesLoyalty[MAX_TOWNS]; + std::map> transportGroupIdToSoldierMap; -BOOLEAN DeployTransportGroup(INT16 sWorldSectorLocationOfFirstBattle) +BOOLEAN DeployTransportGroup() { + // rftr todo: do nothing if feature disabled + + // is there a mine here? + // rftr todo: valid destination towns depend on difficulty + std::vector mineSectorIds; + for (INT8 i = 0; i < NUM_TOWNS; ++i) + { + // skip towns that have no loyalty + if (!gfTownUsesLoyalty[i]) continue; + // filter by TOWN ownership + if (IsTownUnderCompleteControlByEnemy(i) == FALSE) continue; + // skip towns with a shut down mine + const INT8 mineIndex = GetMineIndexForTown(i); + if (mineIndex == -1) continue; + if (IsMineShutDown(mineIndex) == TRUE) continue; + // filter by MINE ownership + const INT16 mineSector = GetMineSectorForTown(i); + if (StrategicMap[mineSector].fEnemyControlled == FALSE) continue; + + mineSectorIds.push_back(mineSector); + } + ScreenMsg(FONT_RED, MSG_INTERFACE, L"DeployTransportGroup valid town destinations: %d", mineSectorIds.size()); + + // rftr todo: special case when only one town left? + if (mineSectorIds.size() < 1) return FALSE; + INT8 transportGroupCount = 0; GROUP* pGroup = gpGroupList; while (pGroup) @@ -45,10 +76,12 @@ BOOLEAN DeployTransportGroup(INT16 sWorldSectorLocationOfFirstBattle) } pGroup = pGroup->next; } + ScreenMsg(FONT_RED, MSG_INTERFACE, L"DeployTransportGroup found existing transport groups: %d", transportGroupCount); // if there are too many active transport groups, don't deploy any more // rftr todo: based on difficulty? if (transportGroupCount >= 5) return FALSE; + // rftr todo: create a new group in the capital (same as attack/patrol groups) and send it to a friendly town with a mine! // limitations: max number of transport groups at any given time // track recent transport group interceptions @@ -56,7 +89,7 @@ BOOLEAN DeployTransportGroup(INT16 sWorldSectorLocationOfFirstBattle) // copied from NPC_ACTION_SEND_SOLDIERS_TO_BATTLE_LOCATION, which happens after the first non-welcome wagon battle // rftr todo: replace this with townid // rftr todo: only pick towns that 1) have mines, and 2) are uncontested - const UINT8 ubSectorID = (UINT8)STRATEGIC_INDEX_TO_SECTOR_INFO( sWorldSectorLocationOfFirstBattle ); + const UINT8 ubSectorID = (UINT8)mineSectorIds[Random(mineSectorIds.size())]; const SECTORINFO* pSector = &SectorInfo[ ubSectorID ]; // rftr: adjust group size and composition based on recent interceptions, game progress, etc @@ -196,6 +229,8 @@ void ProcessTransportGroupReachedDestination(GROUP* pGroup) void UpdateTransportGroupInventory() { + // rftr todo: do nothing if feature disabled + const int firstSlot = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID; const int lastSlot = gTacticalStatus.Team[ ENEMY_TEAM ].bLastID; @@ -374,7 +409,20 @@ void UpdateTransportGroupInventory() void AddToTransportGroupMap(UINT8 groupId, int soldierClass, UINT8 amount) { - transportGroupIdToSoldierMap[groupId][soldierClass] += amount; + // only update admins/troops/elites/jeeps + + switch (soldierClass) + { + case SOLDIER_CLASS_ADMINISTRATOR: + case SOLDIER_CLASS_ARMY: + case SOLDIER_CLASS_ELITE: + case SOLDIER_CLASS_JEEP: + transportGroupIdToSoldierMap[groupId][soldierClass] += amount; + break; + default: + // do nothing! + break; + } } void ClearTransportGroupMap() diff --git a/Strategic/Strategic Transport Groups.h b/Strategic/Strategic Transport Groups.h index 11049139c..dbd650262 100644 --- a/Strategic/Strategic Transport Groups.h +++ b/Strategic/Strategic Transport Groups.h @@ -6,7 +6,7 @@ struct GROUP; -BOOLEAN DeployTransportGroup(INT16); +BOOLEAN DeployTransportGroup(); BOOLEAN ReturnTransportGroup(INT32); void ProcessTransportGroupReachedDestination(GROUP* pGroup); void UpdateTransportGroupInventory(); From 586093cd9e99a514c7c7ac39945fcb9c22b4421a Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Sat, 24 Dec 2022 23:30:49 -0800 Subject: [PATCH 17/81] Skip transport groups when upgrading admins to troops --- Strategic/Strategic AI.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Strategic/Strategic AI.cpp b/Strategic/Strategic AI.cpp index 27c976b60..a5c78c0e3 100644 --- a/Strategic/Strategic AI.cpp +++ b/Strategic/Strategic AI.cpp @@ -6430,8 +6430,14 @@ void UpgradeAdminsToTroops() // if there are any admins currently in this group if ( pGroup->pEnemyGroup->ubNumAdmins > 0 ) { + // skip transport groups + if (pGroup->pEnemyGroup->ubIntention == TRANSPORT) + { + pGroup = pGroup->next; + continue; + } // if it's a patrol group - if ( pGroup->pEnemyGroup->ubIntention == PATROL ) + else if ( pGroup->pEnemyGroup->ubIntention == PATROL ) { sPatrolIndex = FindPatrolGroupIndexForGroupID( pGroup->ubGroupID ); Assert( sPatrolIndex != -1 ); From 52eab0c78bd2948e18b43ee4ca3d27ef79fb5ec8 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Sat, 24 Dec 2022 23:45:55 -0800 Subject: [PATCH 18/81] Check reinforcement pool before deploying group --- Strategic/Strategic Transport Groups.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index efbf3d447..5f80cb90a 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -41,6 +41,8 @@ std::map> transportGroupIdToSoldierMap; BOOLEAN DeployTransportGroup() { // rftr todo: do nothing if feature disabled + if (giReinforcementPool <= 0) + return FALSE; // is there a mine here? // rftr todo: valid destination towns depend on difficulty From c26b66dcd022cfb793b8563dd9804899c06f0980 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Sun, 25 Dec 2022 00:06:55 -0800 Subject: [PATCH 19/81] Deprioritise group deployment --- Strategic/Strategic AI.cpp | 129 ++++++++++++++++++------------------- 1 file changed, 63 insertions(+), 66 deletions(-) diff --git a/Strategic/Strategic AI.cpp b/Strategic/Strategic AI.cpp index a5c78c0e3..37a0ee6a1 100644 --- a/Strategic/Strategic AI.cpp +++ b/Strategic/Strategic AI.cpp @@ -3505,91 +3505,88 @@ void EvaluateQueenSituation() // Gradually promote any remaining admins into troops UpgradeAdminsToTroops(); - ExecuteStrategicAIAction( NPC_ACTION_DEPLOY_TRANSPORT_GROUP, 0, 0 ); - - if( ( giRequestPoints <= 0 ) || ( ( giReinforcementPoints <= 0 ) && ( giReinforcementPool <= 0 ) ) ) - { //we either have no reinforcements or request for reinforcements. - return; - } - - // anv: only consider garrisons and patrols that can be reinforced - // otherwise unreinforcable groups will stall the rest, effectively breaking entire system + // we either have reinforcements or a request for reinforcements + if (giRequestPoints > 0 && (giReinforcementPoints > 0 || giReinforcementPool > 0)) + { + // anv: only consider garrisons and patrols that can be reinforced + // otherwise unreinforcable groups will stall the rest, effectively breaking entire system - Ensure_RepairedGarrisonGroup( &gGarrisonGroup, &giGarrisonArraySize ); /* added NULL fix, 2007-03-03, Sgt. Kolja */ + Ensure_RepairedGarrisonGroup( &gGarrisonGroup, &giGarrisonArraySize ); /* added NULL fix, 2007-03-03, Sgt. Kolja */ - for( i = 0; i < giGarrisonArraySize; i++ ) - { - RecalculateGarrisonWeight( i ); - iWeight = gGarrisonGroup[ i ].bWeight; - if( iWeight > 0 ) + for( i = 0; i < giGarrisonArraySize; i++ ) { - if( !gGarrisonGroup[ i ].ubPendingGroupID && - EnemyPermittedToAttackSector( NULL, gGarrisonGroup[ i ].ubSectorID ) && - GarrisonRequestingMinimumReinforcements( i ) ) + RecalculateGarrisonWeight( i ); + iWeight = gGarrisonGroup[ i ].bWeight; + if( iWeight > 0 ) { - if( ReinforcementsApproved( i, &usDefencePoints ) ) + if( !gGarrisonGroup[ i ].ubPendingGroupID && + EnemyPermittedToAttackSector( NULL, gGarrisonGroup[ i ].ubSectorID ) && + GarrisonRequestingMinimumReinforcements( i ) ) { - iApplicableGarrisonIds[iApplicableGarrisons] = i; - iApplicableGarrisons++; - iApplicableRequestPoints += gGarrisonGroup[ i ].bWeight; + if( ReinforcementsApproved( i, &usDefencePoints ) ) + { + iApplicableGarrisonIds[iApplicableGarrisons] = i; + iApplicableGarrisons++; + iApplicableRequestPoints += gGarrisonGroup[ i ].bWeight; + } } } } - } - for( i = 0; i < giPatrolArraySize; i++ ) - { - RecalculatePatrolWeight( i ); - iWeight = gPatrolGroup[ i ].bWeight; - if( iWeight > 0 ) + for( i = 0; i < giPatrolArraySize; i++ ) { - if( !gPatrolGroup[ i ].ubPendingGroupID && PatrolRequestingMinimumReinforcements( i ) ) + RecalculatePatrolWeight( i ); + iWeight = gPatrolGroup[ i ].bWeight; + if( iWeight > 0 ) { - iApplicablePatrolIds[iApplicablePatrols] = i; - iApplicablePatrols++; - iApplicableRequestPoints += gPatrolGroup[ i ].bWeight; + if( !gPatrolGroup[ i ].ubPendingGroupID && PatrolRequestingMinimumReinforcements( i ) ) + { + iApplicablePatrolIds[iApplicablePatrols] = i; + iApplicablePatrols++; + iApplicableRequestPoints += gPatrolGroup[ i ].bWeight; + } } } - } - if( !iApplicableRequestPoints ) - { - return; - } + if( iApplicableRequestPoints ) + { + //now randomly choose who gets the reinforcements. + // giRequestPoints is the combined sum of all the individual weights of all garrisons and patrols requesting reinforcements + //iRandom = Random( giRequestPoints ); + iRandom = Random( iApplicableRequestPoints ); - //now randomly choose who gets the reinforcements. - // giRequestPoints is the combined sum of all the individual weights of all garrisons and patrols requesting reinforcements - //iRandom = Random( giRequestPoints ); - iRandom = Random( iApplicableRequestPoints ); + iOrigRequestPoints = giRequestPoints; // debug only! - iOrigRequestPoints = giRequestPoints; // debug only! + //go through garrisons first + for( i = 0; i < iApplicableGarrisons; i++ ) + { + iSumOfAllWeights += iWeight; // debug only! + iWeight = gGarrisonGroup[ iApplicableGarrisonIds[i] ].bWeight; + if( iRandom < iWeight ) + { + //This is the group that gets the reinforcements! + if ( SendReinforcementsForGarrison( iApplicableGarrisonIds[i] , usDefencePoints, NULL ) ) + return; + } + iRandom -= iWeight; + } - //go through garrisons first - for( i = 0; i < iApplicableGarrisons; i++ ) - { - iSumOfAllWeights += iWeight; // debug only! - iWeight = gGarrisonGroup[ iApplicableGarrisonIds[i] ].bWeight; - if( iRandom < iWeight ) - { - //This is the group that gets the reinforcements! - if ( SendReinforcementsForGarrison( iApplicableGarrisonIds[i] , usDefencePoints, NULL ) ) - return; + //go through the patrol groups + for( i = 0; i < iApplicablePatrols; i++ ) + { + iSumOfAllWeights += iWeight; // debug only! + iWeight = gPatrolGroup[ iApplicablePatrolIds[i] ].bWeight; + if( iRandom < iWeight ) + { + //This is the group that gets the reinforcements! + if ( SendReinforcementsForPatrol( iApplicablePatrolIds[i], NULL ) ) + return; + } + iRandom -= iWeight; + } } - iRandom -= iWeight; } - //go through the patrol groups - for( i = 0; i < iApplicablePatrols; i++ ) - { - iSumOfAllWeights += iWeight; // debug only! - iWeight = gPatrolGroup[ iApplicablePatrolIds[i] ].bWeight; - if( iRandom < iWeight ) - { - //This is the group that gets the reinforcements! - if ( SendReinforcementsForPatrol( iApplicablePatrolIds[i], NULL ) ) - return; - } - iRandom -= iWeight; - } + ExecuteStrategicAIAction( NPC_ACTION_DEPLOY_TRANSPORT_GROUP, 0, 0 ); ValidateWeights( 27 ); } From c5cebc0bff34b76ed26046422907d4ea0a105b68 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Sun, 25 Dec 2022 00:25:36 -0800 Subject: [PATCH 20/81] Tweak AI group rewards --- Strategic/Strategic Transport Groups.cpp | 36 +++++++++++------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index 5f80cb90a..d4c6e85b9 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -140,7 +140,6 @@ BOOLEAN ReturnTransportGroup(INT32 option1) void ProcessTransportGroupReachedDestination(GROUP* pGroup) { - // rftr todo: something depending if we're in spawn or at target destination const UINT8 difficulty = gGameOptions.ubDifficultyLevel; // just arrived, let's go home @@ -153,18 +152,12 @@ void ProcessTransportGroupReachedDestination(GROUP* pGroup) switch (difficulty) { case DIF_LEVEL_EASY: loyaltyLoss = 0; break; - case DIF_LEVEL_MEDIUM: loyaltyLoss = -100; break; - case DIF_LEVEL_HARD: loyaltyLoss = -200; break; - case DIF_LEVEL_INSANE: loyaltyLoss = -500; break; + case DIF_LEVEL_MEDIUM: loyaltyLoss = 0; break; + case DIF_LEVEL_HARD: loyaltyLoss = -100; break; + case DIF_LEVEL_INSANE: loyaltyLoss = -250; break; } - // rftr todo: this is the "proper" way to do it - letting lua handle it. requires adding an enum value in Strategic Town Loyalty.h (GlobalLoyaltyEventTypes) - //HandleGlobalLoyaltyEvent(-1, pGroup->ubSectorX, pGroup->ubSectorY, pGroup->ubSectorZ); - //... which calls this: - AffectAllTownsLoyaltyByDistanceFrom(loyaltyLoss, pGroup->ubSectorX, pGroup->ubSectorY, pGroup->ubSectorZ); - // on reach target ideas: - // disease: reduction in target town? - // volunteer pool reduction? can we do that? + AffectAllTownsLoyaltyByDistanceFrom(loyaltyLoss, pGroup->ubSectorX, pGroup->ubSectorY, pGroup->ubSectorZ); // queue up return home order AddStrategicEvent(EVENT_RETURN_TRANSPORT_GROUP, GetWorldTotalMin() + 60 * 6, pGroup->ubGroupID); @@ -185,18 +178,18 @@ void ProcessTransportGroupReachedDestination(GROUP* pGroup) break; case DIF_LEVEL_MEDIUM: - moneyAmt = gGameExternalOptions.gASDResource_Cost[ASD_JEEP] * 0.5f; - fuelAmt = gGameExternalOptions.gASDResource_Fuel_Jeep * 0.5f; + moneyAmt = gGameExternalOptions.gASDResource_Cost[ASD_JEEP] * 0.25f; + fuelAmt = gGameExternalOptions.gASDResource_Fuel_Jeep * 0.25f; break; case DIF_LEVEL_HARD: - moneyAmt = gGameExternalOptions.gASDResource_Cost[ASD_JEEP]; - fuelAmt = gGameExternalOptions.gASDResource_Fuel_Jeep; + moneyAmt = gGameExternalOptions.gASDResource_Cost[ASD_JEEP] * 0.5f; + fuelAmt = gGameExternalOptions.gASDResource_Fuel_Jeep * 0.5f; break; case DIF_LEVEL_INSANE: - moneyAmt = gGameExternalOptions.gASDResource_Cost[ASD_JEEP] + gGameExternalOptions.gASDResource_Cost[ASD_TANK]; - fuelAmt = gGameExternalOptions.gASDResource_Fuel_Jeep + gGameExternalOptions.gASDResource_Fuel_Tank; + moneyAmt = gGameExternalOptions.gASDResource_Cost[ASD_TANK]; + fuelAmt = gGameExternalOptions.gASDResource_Fuel_Tank; break; } @@ -223,9 +216,12 @@ void ProcessTransportGroupReachedDestination(GROUP* pGroup) // successfully returned home. give the strategic ai some rewards! SendGroupToPool(&pGroup); - // immediately do a queen evaluation - DeleteAllStrategicEventsOfType(EVENT_EVALUATE_QUEEN_SITUATION); - EvaluateQueenSituation(); + if (difficulty != DIF_LEVEL_EASY) + { + // immediately do a queen evaluation + DeleteAllStrategicEventsOfType(EVENT_EVALUATE_QUEEN_SITUATION); + EvaluateQueenSituation(); + } } } From d49ea7346fcdccc811de84b9ae204f56297cafca Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Wed, 4 Jan 2023 00:49:41 -0800 Subject: [PATCH 21/81] Properly count adjusted soldiers Add transport group direction flag --- Strategic/Strategic Movement.h | 3 +++ Strategic/Strategic Transport Groups.cpp | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/Strategic/Strategic Movement.h b/Strategic/Strategic Movement.h index 5a117bf8c..03f0d3ff6 100644 --- a/Strategic/Strategic Movement.h +++ b/Strategic/Strategic Movement.h @@ -110,6 +110,9 @@ typedef struct ENEMYGROUP #define GROUPFLAG_KNOWN_DIRECTION 0x00000080 #define GROUPFLAG_KNOWN_NUMBER 0x00000100 +// rftr: strategic transport group direction flag +#define GROUPFLAG_TRANSPORT_ENROUTE 0x00000200 + typedef struct GROUP { BOOLEAN fDebugGroup; //for testing purposes -- handled differently in certain cases. diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index d4c6e85b9..606c938cc 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -113,6 +113,8 @@ BOOLEAN DeployTransportGroup() MoveSAIGroupToSector( &pGroup, ubSectorID, EVASIVE, TRANSPORT ); + pGroup->uiFlags |= GROUPFLAG_TRANSPORT_ENROUTE; + return TRUE; } @@ -124,6 +126,7 @@ BOOLEAN ReturnTransportGroup(INT32 option1) if (pGroup->ubGroupID == option1) { MoveSAIGroupToSector( &pGroup, SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), EVASIVE, TRANSPORT ); + pGroup->uiFlags &= ~GROUPFLAG_TRANSPORT_ENROUTE; break; } pGroup = pGroup->next; @@ -355,6 +358,7 @@ void UpdateTransportGroupInventory() item->fFlags &= ~OBJECT_UNDROPPABLE; } } + transportGroupIdToSoldierMap[pSoldier->ubGroupID][pSoldier->ubSoldierClass]--; } } else @@ -398,6 +402,7 @@ void UpdateTransportGroupInventory() item->fFlags &= ~OBJECT_UNDROPPABLE; } } + transportGroupIdToSoldierMap[pSoldier->ubGroupID][pSoldier->ubSoldierClass]--; } } } From 0e355db1506ce37d97433e723e8f499bf77ccad6 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Tue, 10 Jan 2023 00:47:18 -0800 Subject: [PATCH 22/81] Update group loot --- Strategic/Strategic Transport Groups.cpp | 54 +++++++++++++++++++++--- 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index 606c938cc..4a3732e31 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -245,8 +245,15 @@ void UpdateTransportGroupInventory() std::vector medKits; std::vector toolKits; std::vector backpacks; + std::vector grenades; std::map> ammoBoxes; // map coolness to ammo vector std::map> ammoCrates; // map coolness to ammo vector + + // rftr todo: instead of building ammo caches, perhaps we could examine ChooseWeaponForSoldierCreateStruct(). excerpt: + // usAmmoIndex = RandomMagazine( &pp->Inv[HANDPOS], ubChanceStandardAmmo, max(Item[usGunIndex].ubCoolness, HighestPlayerProgressPercentage() / 10 + 3 ), pp->ubSoldierClass); + // however, we'd still need to convert the magazine into an ammo box + // for conversion, see the following (ammo conversion in strategic inventory) + // void SortSectorInventoryAmmo(bool useBoxes) // one-time item cache build { @@ -261,6 +268,7 @@ void UpdateTransportGroupInventory() else if (Item[i].firstaidkit) firstAidKits.push_back(i); else if (Item[i].medicalkit) medKits.push_back(i); else if (Item[i].toolkit) toolKits.push_back(i); + else if (Item[i].usItemClass & IC_GRENADE) grenades.push_back(i); else if (Item[i].usItemClass & IC_LBEGEAR) { if (LoadBearingEquipment[Item[i].ubClassIndex].lbeClass == BACKPACK) @@ -322,6 +330,19 @@ void UpdateTransportGroupInventory() const std::map>::iterator groupIter = transportGroupIdToSoldierMap.find(pSoldier->ubGroupID); if (groupIter != transportGroupIdToSoldierMap.end()) { + // let's find out if this group is coming home or still outgoing to its target destination + GROUP* pGroup = gpGroupList; + BOOLEAN outgoing = FALSE; + while (pGroup) + { + if (pGroup->ubGroupID == groupIter->first) + { + outgoing = pGroup->uiFlags & GROUPFLAG_TRANSPORT_ENROUTE; + break; + } + pGroup = pGroup->next; + } + // found a matching transport groupid std::map::iterator soldierClassIter = groupIter->second.find(SOLDIER_CLASS_JEEP); if (soldierClassIter != groupIter->second.end()) @@ -332,24 +353,45 @@ void UpdateTransportGroupInventory() if (pSoldier->ubSoldierClass == SOLDIER_CLASS_JEEP) { OBJECTTYPE itemToAdd; - for (int i = 0; i < 3; ++i) + //if (outgoing) { - CreateItem(ammoBoxes[5][0], 100, &itemToAdd); + // en route to target destination - carrying ammo, supplies, etc + // medkits + CreateItems(medKits[Random(medKits.size())], 100, 5, &itemToAdd); + addItemToInventory(pSoldier, itemToAdd); + + // first aid kits + CreateItems(firstAidKits[Random(firstAidKits.size())], 100, 10, &itemToAdd); + addItemToInventory(pSoldier, itemToAdd); + + // toolkits + CreateItems(toolKits[Random(toolKits.size())], 100, 5, &itemToAdd); + addItemToInventory(pSoldier, itemToAdd); + + // 2 groups of grenades (possible to get the same) + CreateItems(grenades[Random(grenades.size())], 100, 20, &itemToAdd); addItemToInventory(pSoldier, itemToAdd); + CreateItems(grenades[Random(grenades.size())], 100, 20, &itemToAdd); + addItemToInventory(pSoldier, itemToAdd); + } + //else + { + // coming back home - carrying money/loot/??? } for (int i = 0; i < 3; ++i) { - CreateItem(medKits[Random(medKits.size())], 100, &itemToAdd); + CreateItem(ammoBoxes[5][0], 100, &itemToAdd); addItemToInventory(pSoldier, itemToAdd); } + transportGroupIdToSoldierMap[pSoldier->ubGroupID][SOLDIER_CLASS_JEEP]--; } else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR || pSoldier->ubSoldierClass == SOLDIER_CLASS_ARMY || pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE) { - // force inventory to be dropped! + // jeep is carrying everything, so just force inventory to be dropped! for (int i = 0; i < pSoldier->inv.size(); ++i) { OBJECTTYPE* item = &pSoldier->inv[i]; @@ -385,12 +427,12 @@ void UpdateTransportGroupInventory() OBJECTTYPE itemToAdd; if (backpacks.size() > 0) { - CreateItem(backpacks[0], 75 + Random(25), &itemToAdd); + CreateItem(backpacks[0], 100, &itemToAdd); pSoldier->inv[BPACKPOCKPOS] = itemToAdd; } // add ammo to the soldier's inventory! - CreateItem(ammoBoxes[10][0], (INT8)(90+Random(10)), &itemToAdd); + CreateItem(ammoBoxes[10][0], 100, &itemToAdd); addItemToInventory(pSoldier, itemToAdd); // force inventory to be dropped! From 85a03508c24fef00521b69addbc085d4c2b0de8c Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Mon, 16 Jan 2023 17:49:28 -0800 Subject: [PATCH 23/81] Add todo list (don't forget to remove!) --- Strategic/Strategic Transport Groups.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index 4a3732e31..858a1d5d4 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -16,16 +16,25 @@ addition, transport groups will also be carrying supplies that the player may fi Transport group compositions will vary based on the player's progress, how many interceptions have been completed recently, and the difficulty of the game. +TODO LIST: +- determine how/when/what groups are deployed +- implement ways for the player to find groups (based on difficulty?) +- use proper loyalty degradation (Strategic Loyalty lua) (maybe...) +- use enemygunchoices and enemyitemchoices to populate bonus loot, depending on jeep or no jeep +- track previous failed transports? transport group alertness level? partially degrades over time? + */ #include "Strategic Transport Groups.h" #include "ASD.h" #include "Game Clock.h" #include "Game Event Hook.h" +#include "Inventory Choosing.h" #include "message.h" #include "Overhead.h" #include "Overhead Types.h" #include "random.h" +#include "Soldier Control.h" #include "strategic.h" #include "Strategic AI.h" #include "strategicmap.h" @@ -33,7 +42,8 @@ and the difficulty of the game. #include "Strategic Movement.h" #include "Strategic Town Loyalty.h" - +extern ARMY_GUN_CHOICE_TYPE gExtendedArmyGunChoices[SOLDIER_GUN_CHOICE_SELECTIONS][ARMY_GUN_LEVELS]; +extern ARMY_GUN_CHOICE_TYPE gArmyItemChoices[SOLDIER_GUN_CHOICE_SELECTIONS][MAX_ITEM_TYPES]; extern BOOLEAN gfTownUsesLoyalty[MAX_TOWNS]; std::map> transportGroupIdToSoldierMap; @@ -262,6 +272,9 @@ void UpdateTransportGroupInventory() // add new groups in RandomItem.xml // the new items will reference the new group in randomitem, eg 23 in Items.xml matches uiIndex 23 in RandomItem.xml // fallback if no random items found? for mods and stuff (thinking sdo) + //gExtendedArmyGunChoices[SOLDIER_CLASS_ELITE][gunLevel]; + //gArmyItemChoices[SOLDIER_CLASS_ELITE][typeIndex]; + for (UINT16 i = 0; i < MAXITEMS; ++i) { if (Item[i].gascan) gasCans.push_back(i); From d0171f2e75f5ce31f30244cc33828ef4afa31126 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Mon, 16 Jan 2023 23:56:29 -0800 Subject: [PATCH 24/81] Add game setting options --- GameSettings.cpp | 3 +++ GameSettings.h | 3 +++ Strategic/Strategic Transport Groups.cpp | 16 +++++++++++++--- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/GameSettings.cpp b/GameSettings.cpp index 7981d3008..df3a4aa41 100644 --- a/GameSettings.cpp +++ b/GameSettings.cpp @@ -2159,6 +2159,9 @@ void LoadGameExternalOptions() gGameExternalOptions.fAlternativeHelicopterFuelSystem = iniReader.ReadBoolean("Strategic Gameplay Settings","ALTERNATIVE_HELICOPTER_FUEL_SYSTEM", TRUE); gGameExternalOptions.fHelicopterPassengersCanGetHit = iniReader.ReadBoolean("Strategic Gameplay Settings","HELICOPTER_PASSENGERS_CAN_GET_HIT", TRUE); + gGameExternalOptions.fStrategicTransportGroupsEnabled = iniReader.ReadBoolean("Strategic Gameplay Settings", "STRATEGIC_TRANSPORT_GROUPS_ENABLED", FALSE); + gGameExternalOptions.iMaxSimultaneousTransportGroups = iniReader.ReadInteger("Strategic Gameplay Settings", "MAX_SIMULTANEOUS_STRATEGIC_TRANSPORT_GROUPS", 5, 1, 10); + //################# Morale Settings ################## gGameExternalOptions.sMoraleModAppearance = iniReader.ReadInteger("Morale Settings","MORALE_MOD_APPEARANCE", 1, 0, 5); gGameExternalOptions.sMoraleModRefinement = iniReader.ReadInteger("Morale Settings","MORALE_MOD_REFINEMENT", 2, 0, 5); diff --git a/GameSettings.h b/GameSettings.h index 5f5db0adc..1a57eaaef 100644 --- a/GameSettings.h +++ b/GameSettings.h @@ -1602,6 +1602,9 @@ typedef struct BOOLEAN fAlternativeHelicopterFuelSystem; BOOLEAN fHelicopterPassengersCanGetHit; + BOOLEAN fStrategicTransportGroupsEnabled; + INT8 iMaxSimultaneousTransportGroups; + UINT16 usHelicopterHoverCostOnGreenTile; UINT16 usHelicopterHoverCostOnRedTile; diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index 858a1d5d4..a5f955311 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -29,6 +29,7 @@ TODO LIST: #include "ASD.h" #include "Game Clock.h" #include "Game Event Hook.h" +#include "GameSettings.h" #include "Inventory Choosing.h" #include "message.h" #include "Overhead.h" @@ -50,7 +51,9 @@ std::map> transportGroupIdToSoldierMap; BOOLEAN DeployTransportGroup() { - // rftr todo: do nothing if feature disabled + if (gGameExternalOptions.fStrategicTransportGroupsEnabled) + return FALSE; + if (giReinforcementPool <= 0) return FALSE; @@ -92,7 +95,7 @@ BOOLEAN DeployTransportGroup() // if there are too many active transport groups, don't deploy any more // rftr todo: based on difficulty? - if (transportGroupCount >= 5) return FALSE; + if (transportGroupCount >= gGameExternalOptions.iMaxSimultaneousTransportGroups) return FALSE; // rftr todo: create a new group in the capital (same as attack/patrol groups) and send it to a friendly town with a mine! // limitations: max number of transport groups at any given time @@ -240,7 +243,8 @@ void ProcessTransportGroupReachedDestination(GROUP* pGroup) void UpdateTransportGroupInventory() { - // rftr todo: do nothing if feature disabled + if (gGameExternalOptions.fStrategicTransportGroupsEnabled) + return; const int firstSlot = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID; const int lastSlot = gTacticalStatus.Team[ ENEMY_TEAM ].bLastID; @@ -467,6 +471,12 @@ void UpdateTransportGroupInventory() void AddToTransportGroupMap(UINT8 groupId, int soldierClass, UINT8 amount) { + if (gGameExternalOptions.fStrategicTransportGroupsEnabled) + { + ClearTransportGroupMap(); + return; + } + // only update admins/troops/elites/jeeps switch (soldierClass) From 956efe536aa7b70c8ef2e8371def01e6455afbd4 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Wed, 18 Jan 2023 22:08:07 -0800 Subject: [PATCH 25/81] Add readiness level to groups Use item map instead of vectors Update todos --- Strategic/Strategic Movement.h | 3 +- Strategic/Strategic Transport Groups.cpp | 63 ++++++++++++++++-------- 2 files changed, 45 insertions(+), 21 deletions(-) diff --git a/Strategic/Strategic Movement.h b/Strategic/Strategic Movement.h index 03f0d3ff6..4393ab4cb 100644 --- a/Strategic/Strategic Movement.h +++ b/Strategic/Strategic Movement.h @@ -85,7 +85,8 @@ typedef struct ENEMYGROUP UINT8 ubNumRobots; //number of enemy robots in the group UINT8 ubRobotsInBattle; //number of enemy robots currently in battle. - INT8 bPadding[11]; + UINT8 ubReadiness; // Group readiness when spawned. Determines group member inventory. Currently used by only by strategic transport groups. + INT8 bPadding[10]; }ENEMYGROUP; //NOTE: ALL FLAGS ARE CLEARED WHENEVER A GROUP ARRIVES IN A SECTOR, OR ITS WAYPOINTS ARE diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index a5f955311..b0a38622b 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -22,11 +22,18 @@ TODO LIST: - use proper loyalty degradation (Strategic Loyalty lua) (maybe...) - use enemygunchoices and enemyitemchoices to populate bonus loot, depending on jeep or no jeep - track previous failed transports? transport group alertness level? partially degrades over time? + - we can use strategic status (gStrategicStatus. there's tons of unused padding). that way we don't need to muck with savegames, + as the bytes are already there. + - what do we actually want to track? + - alertness level (affects group compositions) + - recent losses (strategic events?) (affects group compositions) + - groups should track their own "readiness level" (ie, strategic stats when they were spawned) (could use the padding in GROUP->ENEMYGROUP) */ #include "Strategic Transport Groups.h" #include "ASD.h" +#include "Campaign.h" #include "Game Clock.h" #include "Game Event Hook.h" #include "GameSettings.h" @@ -46,6 +53,7 @@ TODO LIST: extern ARMY_GUN_CHOICE_TYPE gExtendedArmyGunChoices[SOLDIER_GUN_CHOICE_SELECTIONS][ARMY_GUN_LEVELS]; extern ARMY_GUN_CHOICE_TYPE gArmyItemChoices[SOLDIER_GUN_CHOICE_SELECTIONS][MAX_ITEM_TYPES]; extern BOOLEAN gfTownUsesLoyalty[MAX_TOWNS]; +//extern STRATEGIC_STATUS gStrategicStatus; std::map> transportGroupIdToSoldierMap; @@ -115,6 +123,7 @@ BOOLEAN DeployTransportGroup() //pGroup = CreateNewEnemyGroupDepartingFromSector( SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), 0, grouptroops[0], groupelites[0], grouprobots[0], grouptanks[0], groupjeeps[0] ); pGroup = CreateNewEnemyGroupDepartingFromSector( SEC_D5, 10, 5, 1, 0, 0, 1 ); + pGroup->pEnemyGroup->ubReadiness = HighestPlayerProgressPercentage(); //Madd: unlimited reinforcements? if ( !gfUnlimitedTroops ) @@ -254,12 +263,23 @@ void UpdateTransportGroupInventory() // rftr todo: do this on init/load somewhere // do some prep - std::vector gasCans; - std::vector firstAidKits; - std::vector medKits; - std::vector toolKits; - std::vector backpacks; - std::vector grenades; + + enum ItemTypes + { + GAS_CANS, + FIRST_AID_KITS, + MED_KITS, + TOOL_KITS, + BACKPACKS, + RADIOS, + GRENADES, + AMMO_BOXES, + AMMO_CRATES, + GUNS, + }; + + std::map> itemMap; + std::map> ammoBoxes; // map coolness to ammo vector std::map> ammoCrates; // map coolness to ammo vector @@ -281,17 +301,18 @@ void UpdateTransportGroupInventory() for (UINT16 i = 0; i < MAXITEMS; ++i) { - if (Item[i].gascan) gasCans.push_back(i); - else if (Item[i].firstaidkit) firstAidKits.push_back(i); - else if (Item[i].medicalkit) medKits.push_back(i); - else if (Item[i].toolkit) toolKits.push_back(i); - else if (Item[i].usItemClass & IC_GRENADE) grenades.push_back(i); + if (Item[i].gascan) itemMap[GAS_CANS].push_back(i); + else if (Item[i].firstaidkit) itemMap[FIRST_AID_KITS].push_back(i); + else if (Item[i].medicalkit) itemMap[MED_KITS].push_back(i); + else if (Item[i].toolkit) itemMap[TOOL_KITS].push_back(i); + else if (HasItemFlag(i, RADIO_SET)) itemMap[RADIOS].push_back(i); + else if (Item[i].usItemClass & IC_GRENADE) itemMap[GRENADES].push_back(i); else if (Item[i].usItemClass & IC_LBEGEAR) { - if (LoadBearingEquipment[Item[i].ubClassIndex].lbeClass == BACKPACK) + if (LoadBearingEquipment[Item[i].ubClassIndex].lbeClass == BACKPACK && !HasItemFlag(i, RADIO_SET)) // make sure radios don't get added here { // todo get actual backpacks, not covert ones, tactical slings, golf clubs, etc... - backpacks.push_back(i); + itemMap[BACKPACKS].push_back(i); } } else if (Item[i].usItemClass & IC_AMMO) @@ -360,6 +381,8 @@ void UpdateTransportGroupInventory() pGroup = pGroup->next; } + const UINT8 groupReadiness = pGroup->pEnemyGroup->ubReadiness; + // found a matching transport groupid std::map::iterator soldierClassIter = groupIter->second.find(SOLDIER_CLASS_JEEP); if (soldierClassIter != groupIter->second.end()) @@ -374,21 +397,21 @@ void UpdateTransportGroupInventory() { // en route to target destination - carrying ammo, supplies, etc // medkits - CreateItems(medKits[Random(medKits.size())], 100, 5, &itemToAdd); + CreateItems(itemMap[MED_KITS][Random(itemMap[MED_KITS].size())], 100, 5, &itemToAdd); addItemToInventory(pSoldier, itemToAdd); // first aid kits - CreateItems(firstAidKits[Random(firstAidKits.size())], 100, 10, &itemToAdd); + CreateItems(itemMap[FIRST_AID_KITS][Random(itemMap[FIRST_AID_KITS].size())], 100, 10, &itemToAdd); addItemToInventory(pSoldier, itemToAdd); // toolkits - CreateItems(toolKits[Random(toolKits.size())], 100, 5, &itemToAdd); + CreateItems(itemMap[TOOL_KITS][Random(itemMap[TOOL_KITS].size())], 100, 5, &itemToAdd); addItemToInventory(pSoldier, itemToAdd); // 2 groups of grenades (possible to get the same) - CreateItems(grenades[Random(grenades.size())], 100, 20, &itemToAdd); + CreateItems(itemMap[GRENADES][Random(itemMap[GRENADES].size())], 100, 20, &itemToAdd); addItemToInventory(pSoldier, itemToAdd); - CreateItems(grenades[Random(grenades.size())], 100, 20, &itemToAdd); + CreateItems(itemMap[GRENADES][Random(itemMap[GRENADES].size())], 100, 20, &itemToAdd); addItemToInventory(pSoldier, itemToAdd); } //else @@ -442,9 +465,9 @@ void UpdateTransportGroupInventory() // add backpack to soldier's inventory! OBJECTTYPE itemToAdd; - if (backpacks.size() > 0) + if (itemMap[BACKPACKS].size() > 0) { - CreateItem(backpacks[0], 100, &itemToAdd); + CreateItem(itemMap[BACKPACKS][0], 100, &itemToAdd); pSoldier->inv[BPACKPOCKPOS] = itemToAdd; } From 3233f4d6723be6a21cd269de9b27230a8fd0ab49 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Tue, 24 Jan 2023 08:59:59 -0800 Subject: [PATCH 26/81] Update Strategic CMakeLists --- Strategic/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Strategic/CMakeLists.txt b/Strategic/CMakeLists.txt index 8e15ba341..295ff41a1 100644 --- a/Strategic/CMakeLists.txt +++ b/Strategic/CMakeLists.txt @@ -47,6 +47,7 @@ set(StrategicSrc "${CMAKE_CURRENT_SOURCE_DIR}/Strategic Status.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/Strategic Town Loyalty.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/strategic town reputation.cpp" +"${CMAKE_CURRENT_SOURCE_DIR}/Strategic Transport Groups.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/Strategic Turns.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/strategic.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/strategicmap.cpp" From 0d60748ffeaca65f7640c34732b9b97f795c9fb4 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Tue, 24 Jan 2023 21:51:24 -0800 Subject: [PATCH 27/81] Remove #pragma optimize --- Strategic/Queen Command.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Strategic/Queen Command.cpp b/Strategic/Queen Command.cpp index 1720ee4e8..7600f1b86 100644 --- a/Strategic/Queen Command.cpp +++ b/Strategic/Queen Command.cpp @@ -1,4 +1,3 @@ -#pragma optimize("",off) //Queen Command.c #include "Queen Command.h" From 39fa52c500966d05a8530ab488768aa9599a2284 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Tue, 24 Jan 2023 23:12:26 -0800 Subject: [PATCH 28/81] Add scout and radio detectors --- Strategic/Map Screen Interface Map.cpp | 23 +------ Strategic/Strategic Transport Groups.cpp | 86 +++++++++++++++++++++++- Strategic/Strategic Transport Groups.h | 3 +- 3 files changed, 88 insertions(+), 24 deletions(-) diff --git a/Strategic/Map Screen Interface Map.cpp b/Strategic/Map Screen Interface Map.cpp index de4415093..a2d29cbd0 100644 --- a/Strategic/Map Screen Interface Map.cpp +++ b/Strategic/Map Screen Interface Map.cpp @@ -46,6 +46,7 @@ #include "LuaInitNPCs.h" // added by Flugente #include "Game Event Hook.h" // added by Flugente #include "Rebel Command.h" + #include "Strategic Transport Groups.h" #include "Quests.h" #include "connect.h" @@ -841,6 +842,8 @@ void fillMapColoursForVisitedSectors(INT32(&colorMap)[ MAXIMUM_VALID_Y_COORDINAT } } + FillMapColoursForTransportGroups(colorMap); + if (RebelCommand::ShowEnemyMovementTargets()) { const auto targetColor = MAP_SHADE_LT_RED; @@ -876,26 +879,6 @@ void fillMapColoursForVisitedSectors(INT32(&colorMap)[ MAXIMUM_VALID_Y_COORDINAT pGroup = pGroup->next; } } - - // rftr todo: transport groups - { - const auto targetColor = MAP_SHADE_LT_BLUE; - GROUP* pGroup = gpGroupList; - - while (pGroup) - { - if (pGroup->usGroupTeam == ENEMY_TEAM) - { - const UINT8 intention = pGroup->pEnemyGroup->ubIntention; - if (intention == TRANSPORT ) - { - colorMap[pGroup->ubSectorY-1][pGroup->ubSectorX-1] = targetColor; - } - } - - pGroup = pGroup->next; - } - } } diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index b0a38622b..d669752ad 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -33,11 +33,13 @@ TODO LIST: #include "Strategic Transport Groups.h" #include "ASD.h" +#include "Assignments.h" #include "Campaign.h" #include "Game Clock.h" #include "Game Event Hook.h" #include "GameSettings.h" #include "Inventory Choosing.h" +#include "Map Screen Interface Map.h" #include "message.h" #include "Overhead.h" #include "Overhead Types.h" @@ -59,7 +61,7 @@ std::map> transportGroupIdToSoldierMap; BOOLEAN DeployTransportGroup() { - if (gGameExternalOptions.fStrategicTransportGroupsEnabled) + if (gGameExternalOptions.fStrategicTransportGroupsEnabled == FALSE) return FALSE; if (giReinforcementPool <= 0) @@ -163,6 +165,84 @@ BOOLEAN ReturnTransportGroup(INT32 option1) return TRUE; } +void FillMapColoursForTransportGroups(INT32(&colorMap)[MAXIMUM_VALID_Y_COORDINATE][MAXIMUM_VALID_X_COORDINATE]) +{ + if (gGameExternalOptions.fStrategicTransportGroupsEnabled == FALSE) + return; + + // radio operators identify at range X+ + // spies identify incoming transport groups + // RIS identifies ALL transport groups in monitored areas? in all areas? + + const auto debugColor = MAP_SHADE_LT_BLUE; + const auto targetColor = MAP_SHADE_LT_YELLOW; + const INT8 DETECTION_RANGE_SCOUT = 1; + const INT8 DETECTION_RANGE_RADIO = 3; + GROUP* pGroup = gpGroupList; + + // build map of detection sectors + ranges + std::map, INT8> detectionMap; + for( INT16 i = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; i <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; i++ ) + { + if( MercPtrs[ i ]->bActive && + MercPtrs[ i ]->stats.bLife >= OKLIFE && + MercPtrs[ i ]->bAssignment < ON_DUTY && + !MercPtrs[ i ]->flags.fMercAsleep) + { + if (HAS_SKILL_TRAIT(MercPtrs[i], SCOUTING_NT)) + { + detectionMap[std::pair(MercPtrs[i]->sSectorX, MercPtrs[i]->sSectorY)] = DETECTION_RANGE_SCOUT; + } + else if (HAS_SKILL_TRAIT(MercPtrs[i], RADIO_OPERATOR_NT)) + { + detectionMap[std::pair(MercPtrs[i]->sSectorX, MercPtrs[i]->sSectorY)] = DETECTION_RANGE_RADIO; + } + } + } + + while (pGroup) + { + if (pGroup->usGroupTeam == ENEMY_TEAM) + { + const UINT8 intention = pGroup->pEnemyGroup->ubIntention; + if (intention == TRANSPORT ) + { + // rftr todo: delete me! + colorMap[pGroup->ubSectorY-1][pGroup->ubSectorX-1] = debugColor; + + // check if current location is known + const UINT8 gx = pGroup->ubSectorX; + const UINT8 gy = pGroup->ubSectorY; + for (const auto key : detectionMap) + { + const std::pair sector = key.first; + const INT8 range = key.second; + + const INT8 dist = (gx - sector.first) + (gy - sector.second); + if (dist < range) + { + colorMap[pGroup->ubSectorY-1][pGroup->ubSectorX-1] = targetColor; + } + } + + // check if target location is known + WAYPOINT* wp = pGroup->pWaypoints; + + while (wp) + { + if (wp->next == nullptr) + break; + + wp = wp->next; + } + //HAS_SKILL_TRAIT(MercPtrs[i], COVERT_NT); + } + } + + pGroup = pGroup->next; + } +} + void ProcessTransportGroupReachedDestination(GROUP* pGroup) { const UINT8 difficulty = gGameOptions.ubDifficultyLevel; @@ -252,7 +332,7 @@ void ProcessTransportGroupReachedDestination(GROUP* pGroup) void UpdateTransportGroupInventory() { - if (gGameExternalOptions.fStrategicTransportGroupsEnabled) + if (gGameExternalOptions.fStrategicTransportGroupsEnabled == FALSE) return; const int firstSlot = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID; @@ -494,7 +574,7 @@ void UpdateTransportGroupInventory() void AddToTransportGroupMap(UINT8 groupId, int soldierClass, UINT8 amount) { - if (gGameExternalOptions.fStrategicTransportGroupsEnabled) + if (gGameExternalOptions.fStrategicTransportGroupsEnabled == FALSE) { ClearTransportGroupMap(); return; diff --git a/Strategic/Strategic Transport Groups.h b/Strategic/Strategic Transport Groups.h index dbd650262..fcd5976c5 100644 --- a/Strategic/Strategic Transport Groups.h +++ b/Strategic/Strategic Transport Groups.h @@ -1,13 +1,14 @@ #ifndef _STRATEGIC_TRANSPORT_GROUPS_H #define _STRATEGIC_TRANSPORT_GROUPS_H -#include +#include "Campaign Types.h" #include "Types.h" struct GROUP; BOOLEAN DeployTransportGroup(); BOOLEAN ReturnTransportGroup(INT32); +void FillMapColoursForTransportGroups(INT32(&colorMap)[MAXIMUM_VALID_Y_COORDINATE][MAXIMUM_VALID_X_COORDINATE]); void ProcessTransportGroupReachedDestination(GROUP* pGroup); void UpdateTransportGroupInventory(); From cdd7775d9fb0957e9e0eacf2872aee85cf1c960e Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Wed, 25 Jan 2023 12:53:23 -0800 Subject: [PATCH 29/81] Fix range check --- Strategic/Strategic Transport Groups.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index d669752ad..409fa9a93 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -170,7 +170,6 @@ void FillMapColoursForTransportGroups(INT32(&colorMap)[MAXIMUM_VALID_Y_COORDINAT if (gGameExternalOptions.fStrategicTransportGroupsEnabled == FALSE) return; - // radio operators identify at range X+ // spies identify incoming transport groups // RIS identifies ALL transport groups in monitored areas? in all areas? @@ -218,8 +217,8 @@ void FillMapColoursForTransportGroups(INT32(&colorMap)[MAXIMUM_VALID_Y_COORDINAT const std::pair sector = key.first; const INT8 range = key.second; - const INT8 dist = (gx - sector.first) + (gy - sector.second); - if (dist < range) + const INT8 dist = abs((gx - sector.first) + (gy - sector.second)); + if (dist <= range) { colorMap[pGroup->ubSectorY-1][pGroup->ubSectorX-1] = targetColor; } From bb29517cab3c80e0cbd093e105761af1608a961e Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Fri, 27 Jan 2023 00:53:38 -0800 Subject: [PATCH 30/81] Add covert ops destination monitoring --- Strategic/Strategic Transport Groups.cpp | 54 ++++++++++++++++++------ 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index 409fa9a93..d6b50ec61 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -177,10 +177,12 @@ void FillMapColoursForTransportGroups(INT32(&colorMap)[MAXIMUM_VALID_Y_COORDINAT const auto targetColor = MAP_SHADE_LT_YELLOW; const INT8 DETECTION_RANGE_SCOUT = 1; const INT8 DETECTION_RANGE_RADIO = 3; + const INT8 DETECTION_RANGE_COVERT = 0; GROUP* pGroup = gpGroupList; // build map of detection sectors + ranges - std::map, INT8> detectionMap; + std::map, INT8> detectionMap; + std::map monitoredTowns; for( INT16 i = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; i <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; i++ ) { if( MercPtrs[ i ]->bActive && @@ -188,13 +190,24 @@ void FillMapColoursForTransportGroups(INT32(&colorMap)[MAXIMUM_VALID_Y_COORDINAT MercPtrs[ i ]->bAssignment < ON_DUTY && !MercPtrs[ i ]->flags.fMercAsleep) { - if (HAS_SKILL_TRAIT(MercPtrs[i], SCOUTING_NT)) + if (gGameOptions.fNewTraitSystem) { - detectionMap[std::pair(MercPtrs[i]->sSectorX, MercPtrs[i]->sSectorY)] = DETECTION_RANGE_SCOUT; - } - else if (HAS_SKILL_TRAIT(MercPtrs[i], RADIO_OPERATOR_NT)) - { - detectionMap[std::pair(MercPtrs[i]->sSectorX, MercPtrs[i]->sSectorY)] = DETECTION_RANGE_RADIO; + if (HAS_SKILL_TRAIT(MercPtrs[i], SCOUTING_NT)) + { + detectionMap[std::pair(MercPtrs[i]->sSectorX, MercPtrs[i]->sSectorY)] = DETECTION_RANGE_SCOUT; + } + else if (HAS_SKILL_TRAIT(MercPtrs[i], RADIO_OPERATOR_NT)) + { + detectionMap[std::pair(MercPtrs[i]->sSectorX, MercPtrs[i]->sSectorY)] = DETECTION_RANGE_RADIO; + } + else if (HAS_SKILL_TRAIT(MercPtrs[i], COVERT_NT)) + { + if (MercPtrs[i]->bAssignment == GATHERINTEL) + { + detectionMap[std::pair(MercPtrs[i]->sSectorX, MercPtrs[i]->sSectorY)] = DETECTION_RANGE_COVERT; + monitoredTowns[GetTownIdForSector(MercPtrs[i]->sSectorX, MercPtrs[i]->sSectorY)] = FALSE; + } + } } } } @@ -210,11 +223,11 @@ void FillMapColoursForTransportGroups(INT32(&colorMap)[MAXIMUM_VALID_Y_COORDINAT colorMap[pGroup->ubSectorY-1][pGroup->ubSectorX-1] = debugColor; // check if current location is known - const UINT8 gx = pGroup->ubSectorX; - const UINT8 gy = pGroup->ubSectorY; + const INT16 gx = pGroup->ubSectorX; + const INT16 gy = pGroup->ubSectorY; for (const auto key : detectionMap) { - const std::pair sector = key.first; + const std::pair sector = key.first; const INT8 range = key.second; const INT8 dist = abs((gx - sector.first) + (gy - sector.second)); @@ -224,7 +237,7 @@ void FillMapColoursForTransportGroups(INT32(&colorMap)[MAXIMUM_VALID_Y_COORDINAT } } - // check if target location is known + // check if target location is monitored WAYPOINT* wp = pGroup->pWaypoints; while (wp) @@ -234,12 +247,29 @@ void FillMapColoursForTransportGroups(INT32(&colorMap)[MAXIMUM_VALID_Y_COORDINAT wp = wp->next; } - //HAS_SKILL_TRAIT(MercPtrs[i], COVERT_NT); + const UINT8 townId = GetTownIdForSector(wp->x, wp->y); + if (monitoredTowns.find(townId) != monitoredTowns.end()) + { + monitoredTowns[townId] = TRUE; + } } } pGroup = pGroup->next; } + + // color all monitored towns if there's a transport group en route + for (int x = MINIMUM_VALID_X_COORDINATE; x <= MAXIMUM_VALID_X_COORDINATE; ++x) + { + for (int y = MINIMUM_VALID_Y_COORDINATE; y <= MAXIMUM_VALID_Y_COORDINATE; ++y) + { + const UINT8 townId = GetTownIdForSector(x, y); + if (monitoredTowns.find(townId) != monitoredTowns.end() && monitoredTowns[townId]) + { + colorMap[x-1][y-1] = targetColor; + } + } + } } void ProcessTransportGroupReachedDestination(GROUP* pGroup) From 7514378d8334f59be7b5150119a7faa2df83bed1 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Tue, 7 Feb 2023 01:26:15 -0800 Subject: [PATCH 31/81] Add random gun loot for jeep groups --- Strategic/Strategic AI.cpp | 1 - Strategic/Strategic Transport Groups.cpp | 66 ++++++++++++++++++------ 2 files changed, 50 insertions(+), 17 deletions(-) diff --git a/Strategic/Strategic AI.cpp b/Strategic/Strategic AI.cpp index ccc2970ea..179efe3bf 100644 --- a/Strategic/Strategic AI.cpp +++ b/Strategic/Strategic AI.cpp @@ -2424,7 +2424,6 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Strategic5"); { ProcessTransportGroupReachedDestination(pGroup); return TRUE; - // do we just call ReassignAIGroup or SendGroupToPool to dissolve and remove the group? } else { //This is a floating group at his final destination... diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index d6b50ec61..113b9d5ef 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -366,12 +366,9 @@ void UpdateTransportGroupInventory() const int firstSlot = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID; const int lastSlot = gTacticalStatus.Team[ ENEMY_TEAM ].bLastID; - - // rftr todo: detect whether this group is going to/from HQ, - // and update loot accordingly - - // rftr todo: do this on init/load somewhere - // do some prep + const UINT8 progress = CurrentPlayerProgressPercentage(); + const UINT8 minGunCoolness = max(8, (progress + 5) / 10); + const UINT8 maxGunCoolness = min(10, 2 + (progress + 5) / 10); enum ItemTypes { @@ -389,6 +386,7 @@ void UpdateTransportGroupInventory() std::map> itemMap; + std::vector guns; std::map> ammoBoxes; // map coolness to ammo vector std::map> ammoCrates; // map coolness to ammo vector @@ -407,8 +405,8 @@ void UpdateTransportGroupInventory() // fallback if no random items found? for mods and stuff (thinking sdo) //gExtendedArmyGunChoices[SOLDIER_CLASS_ELITE][gunLevel]; //gArmyItemChoices[SOLDIER_CLASS_ELITE][typeIndex]; - - for (UINT16 i = 0; i < MAXITEMS; ++i) + + for (UINT16 i = 0; i < gMAXITEMS_READ; ++i) { if (Item[i].gascan) itemMap[GAS_CANS].push_back(i); else if (Item[i].firstaidkit) itemMap[FIRST_AID_KITS].push_back(i); @@ -439,6 +437,11 @@ void UpdateTransportGroupInventory() } } } + else if (Item[i].usItemClass & IC_GUN) + { + if (ItemIsLegal(i) && Item[i].ubCoolness >= minGunCoolness && Item[i].ubCoolness <= maxGunCoolness) + guns.push_back(i); + } } } @@ -506,7 +509,7 @@ void UpdateTransportGroupInventory() { // en route to target destination - carrying ammo, supplies, etc // medkits - CreateItems(itemMap[MED_KITS][Random(itemMap[MED_KITS].size())], 100, 5, &itemToAdd); + CreateItems(itemMap[MED_KITS][Random(itemMap[MED_KITS].size())], 100, 2, &itemToAdd); addItemToInventory(pSoldier, itemToAdd); // first aid kits @@ -514,16 +517,40 @@ void UpdateTransportGroupInventory() addItemToInventory(pSoldier, itemToAdd); // toolkits - CreateItems(itemMap[TOOL_KITS][Random(itemMap[TOOL_KITS].size())], 100, 5, &itemToAdd); + CreateItems(itemMap[TOOL_KITS][Random(itemMap[TOOL_KITS].size())], 100, 2, &itemToAdd); addItemToInventory(pSoldier, itemToAdd); // 2 groups of grenades (possible to get the same) - CreateItems(itemMap[GRENADES][Random(itemMap[GRENADES].size())], 100, 20, &itemToAdd); + CreateItems(itemMap[GRENADES][Random(itemMap[GRENADES].size())], 100, 10, &itemToAdd); addItemToInventory(pSoldier, itemToAdd); - CreateItems(itemMap[GRENADES][Random(itemMap[GRENADES].size())], 100, 20, &itemToAdd); + CreateItems(itemMap[GRENADES][Random(itemMap[GRENADES].size())], 100, 10, &itemToAdd); addItemToInventory(pSoldier, itemToAdd); + + // a couple sets of possibly better-than-expected weapons, as well as ammo for them + for (int loop = 0; loop < 2; ++loop) + { + UINT16 gunId = Random(guns.size()); + CreateItems(guns[gunId], 100, 2, &itemToAdd); + addItemToInventory(pSoldier, itemToAdd); + UINT16 ammoId = RandomMagazine(gunId, 0, maxGunCoolness, SOLDIER_CLASS_ELITE); + + for (INT32 itemId = 0; itemId < (INT32)gMAXITEMS_READ; ++itemId) + { + if( ItemIsLegal(itemId) + && Item[itemId].usItemClass == IC_AMMO + && Magazine[Item[itemId].ubClassIndex].ubMagType == AMMO_BOX + && Magazine[Item[itemId].ubClassIndex].ubCalibre == Magazine[Item[ammoId].ubClassIndex].ubCalibre) + { + // replace mag with box + ammoId = itemId; + break; + } + } + CreateItems(ammoId, 100, 2, &itemToAdd); + addItemToInventory(pSoldier, itemToAdd); + } } - //else + //else // returning home { // coming back home - carrying money/loot/??? } @@ -580,9 +607,16 @@ void UpdateTransportGroupInventory() pSoldier->inv[BPACKPOCKPOS] = itemToAdd; } - // add ammo to the soldier's inventory! - CreateItem(ammoBoxes[10][0], 100, &itemToAdd); - addItemToInventory(pSoldier, itemToAdd); + //if (outgoing) + { + // add ammo to the soldier's inventory! + CreateItem(ammoBoxes[10][0], 100, &itemToAdd); + addItemToInventory(pSoldier, itemToAdd); + } + //else // returning home + { + // coming back home - carrying money/loot/??? + } // force inventory to be dropped! for (int i = 0; i < pSoldier->inv.size(); ++i) From 0d62c786f706945f584cbcc064ba39cf695d881c Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Tue, 7 Feb 2023 01:33:15 -0800 Subject: [PATCH 32/81] Update addItemToInventory lambda --- Strategic/Strategic Transport Groups.cpp | 37 +++++++++--------------- 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index 113b9d5ef..dcd6e4de0 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -445,8 +445,11 @@ void UpdateTransportGroupInventory() } } - auto addItemToInventory = [](SOLDIERTYPE* pSoldier, OBJECTTYPE& itemToAdd) + auto addItemToInventory = [](SOLDIERTYPE* pSoldier, UINT16 itemId, UINT8 amount) { + OBJECTTYPE itemToAdd; + CreateItems(itemId, 100, amount, &itemToAdd); + itemToAdd.fFlags &= ~OBJECT_UNDROPPABLE; if (FitsInSmallPocket(&itemToAdd)) @@ -509,31 +512,25 @@ void UpdateTransportGroupInventory() { // en route to target destination - carrying ammo, supplies, etc // medkits - CreateItems(itemMap[MED_KITS][Random(itemMap[MED_KITS].size())], 100, 2, &itemToAdd); - addItemToInventory(pSoldier, itemToAdd); + addItemToInventory(pSoldier, itemMap[MED_KITS][Random(itemMap[MED_KITS].size())], 2); // first aid kits - CreateItems(itemMap[FIRST_AID_KITS][Random(itemMap[FIRST_AID_KITS].size())], 100, 10, &itemToAdd); - addItemToInventory(pSoldier, itemToAdd); + addItemToInventory(pSoldier, itemMap[FIRST_AID_KITS][Random(itemMap[FIRST_AID_KITS].size())], 10); // toolkits - CreateItems(itemMap[TOOL_KITS][Random(itemMap[TOOL_KITS].size())], 100, 2, &itemToAdd); - addItemToInventory(pSoldier, itemToAdd); + addItemToInventory(pSoldier, itemMap[TOOL_KITS][Random(itemMap[TOOL_KITS].size())], 2); // 2 groups of grenades (possible to get the same) - CreateItems(itemMap[GRENADES][Random(itemMap[GRENADES].size())], 100, 10, &itemToAdd); - addItemToInventory(pSoldier, itemToAdd); - CreateItems(itemMap[GRENADES][Random(itemMap[GRENADES].size())], 100, 10, &itemToAdd); - addItemToInventory(pSoldier, itemToAdd); + addItemToInventory(pSoldier, itemMap[GRENADES][Random(itemMap[GRENADES].size())], 10); + addItemToInventory(pSoldier, itemMap[GRENADES][Random(itemMap[GRENADES].size())], 10); // a couple sets of possibly better-than-expected weapons, as well as ammo for them for (int loop = 0; loop < 2; ++loop) { UINT16 gunId = Random(guns.size()); - CreateItems(guns[gunId], 100, 2, &itemToAdd); - addItemToInventory(pSoldier, itemToAdd); - UINT16 ammoId = RandomMagazine(gunId, 0, maxGunCoolness, SOLDIER_CLASS_ELITE); + addItemToInventory(pSoldier, guns[gunId], 2); + UINT16 ammoId = RandomMagazine(gunId, 0, maxGunCoolness, SOLDIER_CLASS_ELITE); for (INT32 itemId = 0; itemId < (INT32)gMAXITEMS_READ; ++itemId) { if( ItemIsLegal(itemId) @@ -546,8 +543,7 @@ void UpdateTransportGroupInventory() break; } } - CreateItems(ammoId, 100, 2, &itemToAdd); - addItemToInventory(pSoldier, itemToAdd); + addItemToInventory(pSoldier, ammoId, 2); } } //else // returning home @@ -555,12 +551,6 @@ void UpdateTransportGroupInventory() // coming back home - carrying money/loot/??? } - for (int i = 0; i < 3; ++i) - { - CreateItem(ammoBoxes[5][0], 100, &itemToAdd); - addItemToInventory(pSoldier, itemToAdd); - } - transportGroupIdToSoldierMap[pSoldier->ubGroupID][SOLDIER_CLASS_JEEP]--; } else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR @@ -610,8 +600,7 @@ void UpdateTransportGroupInventory() //if (outgoing) { // add ammo to the soldier's inventory! - CreateItem(ammoBoxes[10][0], 100, &itemToAdd); - addItemToInventory(pSoldier, itemToAdd); + addItemToInventory(pSoldier, ammoBoxes[10][0], 1); } //else // returning home { From ef9250ad2b0cabf10f416f09e4c57d6199c9b19d Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Thu, 9 Feb 2023 01:09:30 -0800 Subject: [PATCH 33/81] Add tag to Items.xml to determine valid loot --- Strategic/Strategic Transport Groups.cpp | 49 ++++++++++++++---------- Tactical/Item Types.h | 2 + Utils/XML_Items.cpp | 8 +++- 3 files changed, 38 insertions(+), 21 deletions(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index dcd6e4de0..cb22b7384 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -18,7 +18,6 @@ and the difficulty of the game. TODO LIST: - determine how/when/what groups are deployed -- implement ways for the player to find groups (based on difficulty?) - use proper loyalty degradation (Strategic Loyalty lua) (maybe...) - use enemygunchoices and enemyitemchoices to populate bonus loot, depending on jeep or no jeep - track previous failed transports? transport group alertness level? partially degrades over time? @@ -367,18 +366,21 @@ void UpdateTransportGroupInventory() const int firstSlot = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID; const int lastSlot = gTacticalStatus.Team[ ENEMY_TEAM ].bLastID; const UINT8 progress = CurrentPlayerProgressPercentage(); - const UINT8 minGunCoolness = max(8, (progress + 5) / 10); + const UINT8 minGunCoolness = min(8, (progress + 5) / 10); const UINT8 maxGunCoolness = min(10, 2 + (progress + 5) / 10); enum ItemTypes { GAS_CANS, - FIRST_AID_KITS, - MED_KITS, + MEDICAL_FIRSTAIDKITS, + MEDICAL_MEDKITS, + MEDICAL_OTHER, TOOL_KITS, BACKPACKS, RADIOS, - GRENADES, + GRENADE_THROWN, + GRENADE_LAUNCHED, + GRENADE_ROCKET, AMMO_BOXES, AMMO_CRATES, GUNS, @@ -398,27 +400,33 @@ void UpdateTransportGroupInventory() // one-time item cache build { - // rftr todo: see if we can replace this with random items. // requirement: probably a new flag in Items.xml, or something - // add new groups in RandomItem.xml - // the new items will reference the new group in randomitem, eg 23 in Items.xml matches uiIndex 23 in RandomItem.xml - // fallback if no random items found? for mods and stuff (thinking sdo) //gExtendedArmyGunChoices[SOLDIER_CLASS_ELITE][gunLevel]; //gArmyItemChoices[SOLDIER_CLASS_ELITE][typeIndex]; for (UINT16 i = 0; i < gMAXITEMS_READ; ++i) { - if (Item[i].gascan) itemMap[GAS_CANS].push_back(i); - else if (Item[i].firstaidkit) itemMap[FIRST_AID_KITS].push_back(i); - else if (Item[i].medicalkit) itemMap[MED_KITS].push_back(i); + if (Item[i].fTransportGroupValidLoot == FALSE) continue; + + if (Item[i].medical) + { + if (Item[i].firstaidkit) itemMap[MEDICAL_FIRSTAIDKITS].push_back(i); + else if (Item[i].medicalkit) itemMap[MEDICAL_MEDKITS].push_back(i); + else itemMap[MEDICAL_OTHER].push_back(i); + } + else if (Item[i].gascan) itemMap[GAS_CANS].push_back(i); else if (Item[i].toolkit) itemMap[TOOL_KITS].push_back(i); else if (HasItemFlag(i, RADIO_SET)) itemMap[RADIOS].push_back(i); - else if (Item[i].usItemClass & IC_GRENADE) itemMap[GRENADES].push_back(i); + else if (Item[i].usItemClass & IC_GRENADE) + { + if (Item[i].glgrenade == 0) itemMap[GRENADE_THROWN].push_back(i); + else if (Item[i].attachmentclass == AC_GRENADE) itemMap[GRENADE_LAUNCHED].push_back(i); // grenade launcher grenade + else if (Item[i].attachmentclass == AC_ROCKET) itemMap[GRENADE_ROCKET].push_back(i); // RPG rockets + } else if (Item[i].usItemClass & IC_LBEGEAR) { if (LoadBearingEquipment[Item[i].ubClassIndex].lbeClass == BACKPACK && !HasItemFlag(i, RADIO_SET)) // make sure radios don't get added here { - // todo get actual backpacks, not covert ones, tactical slings, golf clubs, etc... itemMap[BACKPACKS].push_back(i); } } @@ -512,22 +520,22 @@ void UpdateTransportGroupInventory() { // en route to target destination - carrying ammo, supplies, etc // medkits - addItemToInventory(pSoldier, itemMap[MED_KITS][Random(itemMap[MED_KITS].size())], 2); + addItemToInventory(pSoldier, itemMap[MEDICAL_MEDKITS][Random(itemMap[MEDICAL_MEDKITS].size())], 2); // first aid kits - addItemToInventory(pSoldier, itemMap[FIRST_AID_KITS][Random(itemMap[FIRST_AID_KITS].size())], 10); + addItemToInventory(pSoldier, itemMap[MEDICAL_FIRSTAIDKITS][Random(itemMap[MEDICAL_FIRSTAIDKITS].size())], 10); // toolkits addItemToInventory(pSoldier, itemMap[TOOL_KITS][Random(itemMap[TOOL_KITS].size())], 2); // 2 groups of grenades (possible to get the same) - addItemToInventory(pSoldier, itemMap[GRENADES][Random(itemMap[GRENADES].size())], 10); - addItemToInventory(pSoldier, itemMap[GRENADES][Random(itemMap[GRENADES].size())], 10); + addItemToInventory(pSoldier, itemMap[GRENADE_THROWN][Random(itemMap[GRENADE_THROWN].size())], 10); + addItemToInventory(pSoldier, itemMap[GRENADE_THROWN][Random(itemMap[GRENADE_THROWN].size())], 10); // a couple sets of possibly better-than-expected weapons, as well as ammo for them for (int loop = 0; loop < 2; ++loop) { - UINT16 gunId = Random(guns.size()); + const UINT16 gunId = guns[Random(guns.size())]; addItemToInventory(pSoldier, guns[gunId], 2); UINT16 ammoId = RandomMagazine(gunId, 0, maxGunCoolness, SOLDIER_CLASS_ELITE); @@ -536,7 +544,8 @@ void UpdateTransportGroupInventory() if( ItemIsLegal(itemId) && Item[itemId].usItemClass == IC_AMMO && Magazine[Item[itemId].ubClassIndex].ubMagType == AMMO_BOX - && Magazine[Item[itemId].ubClassIndex].ubCalibre == Magazine[Item[ammoId].ubClassIndex].ubCalibre) + && Magazine[Item[itemId].ubClassIndex].ubCalibre == Magazine[Item[ammoId].ubClassIndex].ubCalibre + && Magazine[Item[itemId].ubClassIndex].ubAmmoType == Magazine[Item[ammoId].ubClassIndex].ubAmmoType) { // replace mag with box ammoId = itemId; diff --git a/Tactical/Item Types.h b/Tactical/Item Types.h index 3e91212c0..c3b9005ac 100644 --- a/Tactical/Item Types.h +++ b/Tactical/Item Types.h @@ -1220,6 +1220,8 @@ typedef struct BOOLEAN fProvidesRobotLaserBonus; //shadooow: bitflag controlling what system needs to be in play for item to appear UINT8 usLimitedToSystem; + + BOOLEAN fTransportGroupValidLoot; } INVTYPE; diff --git a/Utils/XML_Items.cpp b/Utils/XML_Items.cpp index 7a576d561..c2deff93e 100644 --- a/Utils/XML_Items.cpp +++ b/Utils/XML_Items.cpp @@ -307,7 +307,8 @@ itemStartElementHandle(void *userData, const XML_Char *name, const XML_Char **at strcmp(name, "ProvidesRobotNightVision") == 0 || strcmp(name, "ProvidesRobotLaserBonus") == 0 || strcmp(name, "FoodSystemExclusive") == 0 || - strcmp(name, "DiseaseSystemExclusive") == 0 + strcmp(name, "DiseaseSystemExclusive") == 0 || + strcmp(name, "TransportGroupValidLoot") == 0 ) { pData->curElement = ELEMENT_PROPERTY; @@ -1525,6 +1526,11 @@ itemEndElementHandle(void *userData, const XML_Char *name) if (atol(pData->szCharData)) pData->curItem.usLimitedToSystem|= DISEASE_SYSTEM_FLAG; } + else if (strcmp(name, "TransportGroupValidLoot") == 0) + { + pData->curElement == ELEMENT; + pData->curItem.fTransportGroupValidLoot = (BOOLEAN)atol(pData->szCharData); + } --pData->maxReadDepth; } From f4d303ee5458e5a55790b57ae85330099e190500 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Fri, 10 Feb 2023 22:18:55 -0800 Subject: [PATCH 34/81] Properly set up weapons + ammo in jeeps Add grenade launcher/rocket launcher to item map --- Strategic/Strategic Transport Groups.cpp | 70 ++++++++++++++++-------- 1 file changed, 46 insertions(+), 24 deletions(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index cb22b7384..5b14bc29e 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -367,7 +367,7 @@ void UpdateTransportGroupInventory() const int lastSlot = gTacticalStatus.Team[ ENEMY_TEAM ].bLastID; const UINT8 progress = CurrentPlayerProgressPercentage(); const UINT8 minGunCoolness = min(8, (progress + 5) / 10); - const UINT8 maxGunCoolness = min(10, 2 + (progress + 5) / 10); + const UINT8 maxGunCoolness = min(10, 3 + (progress + 5) / 10); enum ItemTypes { @@ -384,11 +384,12 @@ void UpdateTransportGroupInventory() AMMO_BOXES, AMMO_CRATES, GUNS, + GRENADELAUNCHERS, + ROCKETLAUNCHERS, }; std::map> itemMap; - std::vector guns; std::map> ammoBoxes; // map coolness to ammo vector std::map> ammoCrates; // map coolness to ammo vector @@ -448,7 +449,17 @@ void UpdateTransportGroupInventory() else if (Item[i].usItemClass & IC_GUN) { if (ItemIsLegal(i) && Item[i].ubCoolness >= minGunCoolness && Item[i].ubCoolness <= maxGunCoolness) - guns.push_back(i); + itemMap[GUNS].push_back(i); + } + else if (Item[i].grenadelauncher) + { + if (ItemIsLegal(i) && Item[i].ubCoolness >= minGunCoolness && Item[i].ubCoolness <= maxGunCoolness) + itemMap[GRENADELAUNCHERS].push_back(i); + } + else if (Item[i].rocketlauncher) + { + if (ItemIsLegal(i) && Item[i].ubCoolness >= minGunCoolness && Item[i].ubCoolness <= maxGunCoolness) + itemMap[ROCKETLAUNCHERS].push_back(i); } } } @@ -520,39 +531,50 @@ void UpdateTransportGroupInventory() { // en route to target destination - carrying ammo, supplies, etc // medkits - addItemToInventory(pSoldier, itemMap[MEDICAL_MEDKITS][Random(itemMap[MEDICAL_MEDKITS].size())], 2); + if (itemMap[MEDICAL_MEDKITS].size() > 0) + addItemToInventory(pSoldier, itemMap[MEDICAL_MEDKITS][Random(itemMap[MEDICAL_MEDKITS].size())], 2); // first aid kits - addItemToInventory(pSoldier, itemMap[MEDICAL_FIRSTAIDKITS][Random(itemMap[MEDICAL_FIRSTAIDKITS].size())], 10); + if (itemMap[MEDICAL_FIRSTAIDKITS].size() > 0) + addItemToInventory(pSoldier, itemMap[MEDICAL_FIRSTAIDKITS][Random(itemMap[MEDICAL_FIRSTAIDKITS].size())], 10); // toolkits - addItemToInventory(pSoldier, itemMap[TOOL_KITS][Random(itemMap[TOOL_KITS].size())], 2); + if (itemMap[TOOL_KITS].size() > 0) + addItemToInventory(pSoldier, itemMap[TOOL_KITS][Random(itemMap[TOOL_KITS].size())], 2); // 2 groups of grenades (possible to get the same) - addItemToInventory(pSoldier, itemMap[GRENADE_THROWN][Random(itemMap[GRENADE_THROWN].size())], 10); - addItemToInventory(pSoldier, itemMap[GRENADE_THROWN][Random(itemMap[GRENADE_THROWN].size())], 10); - - // a couple sets of possibly better-than-expected weapons, as well as ammo for them - for (int loop = 0; loop < 2; ++loop) + if (itemMap[GRENADE_THROWN].size() > 0) { - const UINT16 gunId = guns[Random(guns.size())]; - addItemToInventory(pSoldier, guns[gunId], 2); + addItemToInventory(pSoldier, itemMap[GRENADE_THROWN][Random(itemMap[GRENADE_THROWN].size())], 10); + addItemToInventory(pSoldier, itemMap[GRENADE_THROWN][Random(itemMap[GRENADE_THROWN].size())], 10); + } - UINT16 ammoId = RandomMagazine(gunId, 0, maxGunCoolness, SOLDIER_CLASS_ELITE); - for (INT32 itemId = 0; itemId < (INT32)gMAXITEMS_READ; ++itemId) + // a few sets of weapons, as well as ammo for them + if (itemMap[GUNS].size() > 0) + { + for (int loop = 0; loop < 3; ++loop) { - if( ItemIsLegal(itemId) - && Item[itemId].usItemClass == IC_AMMO - && Magazine[Item[itemId].ubClassIndex].ubMagType == AMMO_BOX - && Magazine[Item[itemId].ubClassIndex].ubCalibre == Magazine[Item[ammoId].ubClassIndex].ubCalibre - && Magazine[Item[itemId].ubClassIndex].ubAmmoType == Magazine[Item[ammoId].ubClassIndex].ubAmmoType) + const UINT16 gunId = itemMap[GUNS][Random(itemMap[GUNS].size())]; + addItemToInventory(pSoldier, gunId, 1); + + UINT16 ammoId = RandomMagazine(gunId, 0, maxGunCoolness, SOLDIER_CLASS_ELITE); + BOOLEAN convertedToBox = FALSE; + for (INT32 itemId = 0; itemId < (INT32)gMAXITEMS_READ; ++itemId) { - // replace mag with box - ammoId = itemId; - break; + if( ItemIsLegal(itemId) + && Item[itemId].usItemClass == IC_AMMO + && Magazine[Item[itemId].ubClassIndex].ubMagType == AMMO_BOX + && Magazine[Item[itemId].ubClassIndex].ubCalibre == Magazine[Item[ammoId].ubClassIndex].ubCalibre + && Magazine[Item[itemId].ubClassIndex].ubAmmoType == Magazine[Item[ammoId].ubClassIndex].ubAmmoType) + { + // replace mag with box + convertedToBox = TRUE; + ammoId = itemId; + break; + } } + addItemToInventory(pSoldier, ammoId, convertedToBox ? 2 : 10); } - addItemToInventory(pSoldier, ammoId, 2); } } //else // returning home From 30d1f22b99089384e82d0633941cc4f3bbda76db Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Sun, 12 Feb 2023 23:12:02 -0800 Subject: [PATCH 35/81] Adjust item drop loop Add grenade and rocket launchers to drop list --- Strategic/Strategic Transport Groups.cpp | 131 +++++++++++++++-------- 1 file changed, 84 insertions(+), 47 deletions(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index 5b14bc29e..50d126632 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -379,13 +379,14 @@ void UpdateTransportGroupInventory() BACKPACKS, RADIOS, GRENADE_THROWN, - GRENADE_LAUNCHED, - GRENADE_ROCKET, - AMMO_BOXES, - AMMO_CRATES, GUNS, GRENADELAUNCHERS, ROCKETLAUNCHERS, + AMMO_BOXES, + AMMO_CRATES, + + TRANSPORT_LOOT_START = GAS_CANS, + TRANSPORT_LOOT_END = ROCKETLAUNCHERS, }; std::map> itemMap; @@ -401,13 +402,13 @@ void UpdateTransportGroupInventory() // one-time item cache build { - // requirement: probably a new flag in Items.xml, or something //gExtendedArmyGunChoices[SOLDIER_CLASS_ELITE][gunLevel]; //gArmyItemChoices[SOLDIER_CLASS_ELITE][typeIndex]; for (UINT16 i = 0; i < gMAXITEMS_READ; ++i) { if (Item[i].fTransportGroupValidLoot == FALSE) continue; + if (!ItemIsLegal(i)) continue; if (Item[i].medical) { @@ -420,9 +421,10 @@ void UpdateTransportGroupInventory() else if (HasItemFlag(i, RADIO_SET)) itemMap[RADIOS].push_back(i); else if (Item[i].usItemClass & IC_GRENADE) { - if (Item[i].glgrenade == 0) itemMap[GRENADE_THROWN].push_back(i); - else if (Item[i].attachmentclass == AC_GRENADE) itemMap[GRENADE_LAUNCHED].push_back(i); // grenade launcher grenade - else if (Item[i].attachmentclass == AC_ROCKET) itemMap[GRENADE_ROCKET].push_back(i); // RPG rockets + if (Item[i].glgrenade == 0 + && Item[i].attachmentclass != AC_GRENADE // not for a grenade launcher + && Item[i].attachmentclass != AC_ROCKET) // not for a rocket launcher + itemMap[GRENADE_THROWN].push_back(i); } else if (Item[i].usItemClass & IC_LBEGEAR) { @@ -448,17 +450,17 @@ void UpdateTransportGroupInventory() } else if (Item[i].usItemClass & IC_GUN) { - if (ItemIsLegal(i) && Item[i].ubCoolness >= minGunCoolness && Item[i].ubCoolness <= maxGunCoolness) + if (Item[i].ubCoolness >= minGunCoolness && Item[i].ubCoolness <= maxGunCoolness) itemMap[GUNS].push_back(i); } else if (Item[i].grenadelauncher) { - if (ItemIsLegal(i) && Item[i].ubCoolness >= minGunCoolness && Item[i].ubCoolness <= maxGunCoolness) + if (Item[i].ubCoolness >= minGunCoolness && Item[i].ubCoolness <= maxGunCoolness) itemMap[GRENADELAUNCHERS].push_back(i); } else if (Item[i].rocketlauncher) { - if (ItemIsLegal(i) && Item[i].ubCoolness >= minGunCoolness && Item[i].ubCoolness <= maxGunCoolness) + if (Item[i].ubCoolness >= minGunCoolness && Item[i].ubCoolness <= maxGunCoolness) itemMap[ROCKETLAUNCHERS].push_back(i); } } @@ -530,50 +532,85 @@ void UpdateTransportGroupInventory() //if (outgoing) { // en route to target destination - carrying ammo, supplies, etc - // medkits - if (itemMap[MEDICAL_MEDKITS].size() > 0) - addItemToInventory(pSoldier, itemMap[MEDICAL_MEDKITS][Random(itemMap[MEDICAL_MEDKITS].size())], 2); + for (int i = TRANSPORT_LOOT_START; i <= TRANSPORT_LOOT_END; ++i) + { + const ItemTypes itemType = static_cast(i); + if (itemMap[itemType].size() > 0) + { + const UINT16 id = itemMap[itemType][Random(itemMap[itemType].size())]; + switch (itemType) + { + case MEDICAL_MEDKITS: + case MEDICAL_OTHER: + case TOOL_KITS: + addItemToInventory(pSoldier, id, 2); + break; - // first aid kits - if (itemMap[MEDICAL_FIRSTAIDKITS].size() > 0) - addItemToInventory(pSoldier, itemMap[MEDICAL_FIRSTAIDKITS][Random(itemMap[MEDICAL_FIRSTAIDKITS].size())], 10); + case MEDICAL_FIRSTAIDKITS: + addItemToInventory(pSoldier, id, 10); + break; - // toolkits - if (itemMap[TOOL_KITS].size() > 0) - addItemToInventory(pSoldier, itemMap[TOOL_KITS][Random(itemMap[TOOL_KITS].size())], 2); + case GRENADE_THROWN: + addItemToInventory(pSoldier, id, 12); + break; - // 2 groups of grenades (possible to get the same) - if (itemMap[GRENADE_THROWN].size() > 0) - { - addItemToInventory(pSoldier, itemMap[GRENADE_THROWN][Random(itemMap[GRENADE_THROWN].size())], 10); - addItemToInventory(pSoldier, itemMap[GRENADE_THROWN][Random(itemMap[GRENADE_THROWN].size())], 10); - } + case GUNS: + { + for (int loop = 0; loop < 3; ++loop) + { + const UINT16 gunId = itemMap[itemType][Random(itemMap[itemType].size())]; + addItemToInventory(pSoldier, gunId, 1); + + UINT16 ammoId = RandomMagazine(gunId, 0, maxGunCoolness, SOLDIER_CLASS_ELITE); + if (ammoId == 0) continue; // no ammo matches, skip + + BOOLEAN convertedToBox = FALSE; + for (INT32 itemId = 0; itemId < (INT32)gMAXITEMS_READ; ++itemId) + { + if( ItemIsLegal(itemId) + && Item[itemId].usItemClass == IC_AMMO + && Magazine[Item[itemId].ubClassIndex].ubMagType == AMMO_BOX + && Magazine[Item[itemId].ubClassIndex].ubCalibre == Magazine[Item[ammoId].ubClassIndex].ubCalibre + && Magazine[Item[itemId].ubClassIndex].ubAmmoType == Magazine[Item[ammoId].ubClassIndex].ubAmmoType) + { + // replace mag with box + convertedToBox = TRUE; + ammoId = itemId; + break; + } + } + addItemToInventory(pSoldier, ammoId, convertedToBox ? 2 : 10); + } + } + break; - // a few sets of weapons, as well as ammo for them - if (itemMap[GUNS].size() > 0) - { - for (int loop = 0; loop < 3; ++loop) - { - const UINT16 gunId = itemMap[GUNS][Random(itemMap[GUNS].size())]; - addItemToInventory(pSoldier, gunId, 1); + case GRENADELAUNCHERS: + { + addItemToInventory(pSoldier, id, 1); - UINT16 ammoId = RandomMagazine(gunId, 0, maxGunCoolness, SOLDIER_CLASS_ELITE); - BOOLEAN convertedToBox = FALSE; - for (INT32 itemId = 0; itemId < (INT32)gMAXITEMS_READ; ++itemId) - { - if( ItemIsLegal(itemId) - && Item[itemId].usItemClass == IC_AMMO - && Magazine[Item[itemId].ubClassIndex].ubMagType == AMMO_BOX - && Magazine[Item[itemId].ubClassIndex].ubCalibre == Magazine[Item[ammoId].ubClassIndex].ubCalibre - && Magazine[Item[itemId].ubClassIndex].ubAmmoType == Magazine[Item[ammoId].ubClassIndex].ubAmmoType) + const UINT16 launchableId = PickARandomLaunchable(id); + if (launchableId == 0) continue; // no launchable matches, skip + + addItemToInventory(pSoldier, launchableId, 8); + } + break; + + case ROCKETLAUNCHERS: { - // replace mag with box - convertedToBox = TRUE; - ammoId = itemId; - break; + addItemToInventory(pSoldier, id, Item[id].singleshotrocketlauncher ? 3 : 1); + + const UINT16 launchableId = PickARandomLaunchable(id); + if (launchableId == 0) continue; // no launchable matches, skip + + addItemToInventory(pSoldier, launchableId, 3); } + break; + + default: + ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Warning: ignoring unhandled transport group loot type: %d", itemType); + // nothing! + break; } - addItemToInventory(pSoldier, ammoId, convertedToBox ? 2 : 10); } } } From 22d8fa633a00c4042f513fc36ee593fcc9172888 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Tue, 14 Feb 2023 23:29:11 -0800 Subject: [PATCH 36/81] Specify valid progress range in xml Track MISC items --- Strategic/Strategic Transport Groups.cpp | 22 +++++++++++----------- Tactical/Item Types.h | 4 +++- Utils/XML_Items.cpp | 12 +++++++++--- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index 50d126632..0e1e9b312 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -366,8 +366,6 @@ void UpdateTransportGroupInventory() const int firstSlot = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID; const int lastSlot = gTacticalStatus.Team[ ENEMY_TEAM ].bLastID; const UINT8 progress = CurrentPlayerProgressPercentage(); - const UINT8 minGunCoolness = min(8, (progress + 5) / 10); - const UINT8 maxGunCoolness = min(10, 3 + (progress + 5) / 10); enum ItemTypes { @@ -378,6 +376,7 @@ void UpdateTransportGroupInventory() TOOL_KITS, BACKPACKS, RADIOS, + MISC, GRENADE_THROWN, GUNS, GRENADELAUNCHERS, @@ -407,8 +406,8 @@ void UpdateTransportGroupInventory() for (UINT16 i = 0; i < gMAXITEMS_READ; ++i) { - if (Item[i].fTransportGroupValidLoot == FALSE) continue; - if (!ItemIsLegal(i)) continue; + if (!ItemIsLegal(i, TRUE)) continue; + if (Item[i].iTransportGroupMaxProgress == 0 || Item[i].iTransportGroupMinProgress > progress || progress > Item[i].iTransportGroupMaxProgress) continue; if (Item[i].medical) { @@ -433,6 +432,10 @@ void UpdateTransportGroupInventory() itemMap[BACKPACKS].push_back(i); } } + else if (Item[i].usItemClass & IC_MISC) + { + itemMap[MISC].push_back(i); + } else if (Item[i].usItemClass & IC_AMMO) { if (Magazine[Item[i].ubClassIndex].ubMagType == AMMO_BOX @@ -450,18 +453,15 @@ void UpdateTransportGroupInventory() } else if (Item[i].usItemClass & IC_GUN) { - if (Item[i].ubCoolness >= minGunCoolness && Item[i].ubCoolness <= maxGunCoolness) - itemMap[GUNS].push_back(i); + itemMap[GUNS].push_back(i); } else if (Item[i].grenadelauncher) { - if (Item[i].ubCoolness >= minGunCoolness && Item[i].ubCoolness <= maxGunCoolness) - itemMap[GRENADELAUNCHERS].push_back(i); + itemMap[GRENADELAUNCHERS].push_back(i); } else if (Item[i].rocketlauncher) { - if (Item[i].ubCoolness >= minGunCoolness && Item[i].ubCoolness <= maxGunCoolness) - itemMap[ROCKETLAUNCHERS].push_back(i); + itemMap[ROCKETLAUNCHERS].push_back(i); } } } @@ -561,7 +561,7 @@ void UpdateTransportGroupInventory() const UINT16 gunId = itemMap[itemType][Random(itemMap[itemType].size())]; addItemToInventory(pSoldier, gunId, 1); - UINT16 ammoId = RandomMagazine(gunId, 0, maxGunCoolness, SOLDIER_CLASS_ELITE); + UINT16 ammoId = RandomMagazine(gunId, 0, 100, SOLDIER_CLASS_ELITE); if (ammoId == 0) continue; // no ammo matches, skip BOOLEAN convertedToBox = FALSE; diff --git a/Tactical/Item Types.h b/Tactical/Item Types.h index c3b9005ac..67e761d42 100644 --- a/Tactical/Item Types.h +++ b/Tactical/Item Types.h @@ -1221,7 +1221,9 @@ typedef struct //shadooow: bitflag controlling what system needs to be in play for item to appear UINT8 usLimitedToSystem; - BOOLEAN fTransportGroupValidLoot; + // rftr: the progress bounds that allow a transport group to drop an item + INT8 iTransportGroupMinProgress; + INT8 iTransportGroupMaxProgress; } INVTYPE; diff --git a/Utils/XML_Items.cpp b/Utils/XML_Items.cpp index c2deff93e..0dc1938d3 100644 --- a/Utils/XML_Items.cpp +++ b/Utils/XML_Items.cpp @@ -308,7 +308,8 @@ itemStartElementHandle(void *userData, const XML_Char *name, const XML_Char **at strcmp(name, "ProvidesRobotLaserBonus") == 0 || strcmp(name, "FoodSystemExclusive") == 0 || strcmp(name, "DiseaseSystemExclusive") == 0 || - strcmp(name, "TransportGroupValidLoot") == 0 + strcmp(name, "TransportGroupMinProgress") == 0 || + strcmp(name, "TransportGroupMaxProgress") == 0 ) { pData->curElement = ELEMENT_PROPERTY; @@ -1526,10 +1527,15 @@ itemEndElementHandle(void *userData, const XML_Char *name) if (atol(pData->szCharData)) pData->curItem.usLimitedToSystem|= DISEASE_SYSTEM_FLAG; } - else if (strcmp(name, "TransportGroupValidLoot") == 0) + else if (strcmp(name, "TransportGroupMinProgress") == 0) { pData->curElement == ELEMENT; - pData->curItem.fTransportGroupValidLoot = (BOOLEAN)atol(pData->szCharData); + pData->curItem.iTransportGroupMinProgress = (INT8)atoi(pData->szCharData); + } + else if (strcmp(name, "TransportGroupMaxProgress") == 0) + { + pData->curElement == ELEMENT; + pData->curItem.iTransportGroupMaxProgress = (INT8)atoi(pData->szCharData); } --pData->maxReadDepth; From f9be46ac73dc0438e00008ba93c07c96d5ac328b Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Thu, 16 Feb 2023 00:17:56 -0800 Subject: [PATCH 37/81] Add history when successfully defeating a transport group --- Laptop/history.cpp | 1 + Laptop/history.h | 1 + Strategic/Auto Resolve.cpp | 3 ++- Strategic/PreBattle Interface.cpp | 36 ++++++++++++++++++++++++++----- Strategic/PreBattle Interface.h | 4 +++- 5 files changed, 38 insertions(+), 7 deletions(-) diff --git a/Laptop/history.cpp b/Laptop/history.cpp index 558029cac..6067098da 100644 --- a/Laptop/history.cpp +++ b/Laptop/history.cpp @@ -1259,6 +1259,7 @@ void ProcessHistoryTransactionString(STR16 pString, HistoryUnitPtr pHistory) case HISTORY_SLAY_MYSTERIOUSLY_LEFT: case HISTORY_WALDO: case HISTORY_HELICOPTER_REPAIR_STARTED: + case HISTORY_INTERCEPTED_TRANSPORT_GROUP: //swprintf( pString, pHistoryStrings[ pHistory->ubCode ], pHistory->ubSecondCode ); swprintf( pString, HistoryName[ pHistory->ubCode ].sHistory, pHistory->ubSecondCode ); break; diff --git a/Laptop/history.h b/Laptop/history.h index 6fecf8d2e..5a0a3d63d 100644 --- a/Laptop/history.h +++ b/Laptop/history.h @@ -113,6 +113,7 @@ enum{ HISTORY_MERC_KILLED_CHARACTER, HISTORY_WALDO, HISTORY_HELICOPTER_REPAIR_STARTED, + HISTORY_INTERCEPTED_TRANSPORT_GROUP, TEXT_NUM_HISTORY }; diff --git a/Strategic/Auto Resolve.cpp b/Strategic/Auto Resolve.cpp index c602e12c7..87a0cbc8e 100644 --- a/Strategic/Auto Resolve.cpp +++ b/Strategic/Auto Resolve.cpp @@ -633,6 +633,7 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Autoresolve1"); switch( GetEnemyEncounterCode() ) { case ENEMY_ENCOUNTER_CODE: + case TRANSPORT_INTERCEPT_CODE: gpAR->ubPlayerDefenceAdvantage = 21; //Skewed to the player's advantage for convenience purposes. break; case ENEMY_INVASION_CODE: @@ -1745,6 +1746,7 @@ void RenderAutoResolve() swprintf( str, gpStrategicString[STR_AR_ATTACK_HEADER] ); break; case ENEMY_ENCOUNTER_CODE: + case TRANSPORT_INTERCEPT_CODE: swprintf( str, gpStrategicString[STR_AR_ENCOUNTER_HEADER] ); break; case ENEMY_INVASION_CODE: @@ -6060,4 +6062,3 @@ BOOLEAN IndividualMilitiaInUse_AutoResolve( UINT32 aMilitiaId ) } return FALSE; -} \ No newline at end of file diff --git a/Strategic/PreBattle Interface.cpp b/Strategic/PreBattle Interface.cpp index 81909888a..d07fa4569 100644 --- a/Strategic/PreBattle Interface.cpp +++ b/Strategic/PreBattle Interface.cpp @@ -438,7 +438,7 @@ void InitPreBattleInterface( GROUP *pBattleGroup, BOOLEAN fPersistantPBI ) } else if ( pBattleGroup && pBattleGroup->usGroupTeam != OUR_TEAM && NumNonPlayerTeamMembersInSector( pBattleGroup->ubSectorX, pBattleGroup->ubSectorY, MILITIA_TEAM ) > 0 ) { - SetEnemyEncounterCode( ENEMY_ENCOUNTER_CODE ); + SetEnemyEncounterCode( pBattleGroup->usGroupTeam == ENEMY_TEAM && pBattleGroup->pEnemyGroup->ubIntention == TRANSPORT ? TRANSPORT_INTERCEPT_CODE : ENEMY_ENCOUNTER_CODE ); } else if( GetEnemyEncounterCode() == ENTERING_ENEMY_SECTOR_CODE || GetEnemyEncounterCode() == ENEMY_ENCOUNTER_CODE || @@ -452,7 +452,8 @@ void InitPreBattleInterface( GROUP *pBattleGroup, BOOLEAN fPersistantPBI ) GetEnemyEncounterCode() == CONCEALINSERTION_CODE || GetEnemyEncounterCode() == BLOODCAT_ATTACK_CODE || GetEnemyEncounterCode() == ZOMBIE_ATTACK_CODE || - GetEnemyEncounterCode() == BANDIT_ATTACK_CODE ) + GetEnemyEncounterCode() == BANDIT_ATTACK_CODE || + GetEnemyEncounterCode() == TRANSPORT_INTERCEPT_CODE ) { //use same code SetExplicitEnemyEncounterCode( GetEnemyEncounterCode() ); @@ -679,8 +680,24 @@ void InitPreBattleInterface( GROUP *pBattleGroup, BOOLEAN fPersistantPBI ) { SetEnemyEncounterCode( ENEMY_ENCOUNTER_CODE ); + GROUP* pGroup = gpGroupList; + BOOLEAN encounteredTransportGroup = FALSE; + while (pGroup) + { + if (pGroup->usGroupTeam == ENEMY_TEAM && pGroup->pEnemyGroup->ubIntention == TRANSPORT && pGroup->ubSectorX == gpBattleGroup->ubSectorX && pGroup->ubSectorY == gpBattleGroup->ubSectorY && pGroup->ubSectorZ == gpBattleGroup->ubSectorZ) + { + encounteredTransportGroup = TRUE; + break; + } + + pGroup = pGroup->next; + } + if (encounteredTransportGroup) + { + SetEnemyEncounterCode( TRANSPORT_INTERCEPT_CODE ); + } // Flugente: no ambushes on an airdrop - if ( !fAirDrop ) + else if ( !fAirDrop ) { //Don't consider ambushes until the player has reached 25% (normal) progress if( gfHighPotentialForAmbush ) @@ -798,7 +815,9 @@ void InitPreBattleInterface( GROUP *pBattleGroup, BOOLEAN fPersistantPBI ) } else { //Are enemies invading a town, or just encountered the player. - if( GetTownIdForSector( gubPBSectorX, gubPBSectorY ) ) + if (pBattleGroup && pBattleGroup->usGroupTeam == ENEMY_TEAM && pBattleGroup->pEnemyGroup->ubIntention == TRANSPORT) + SetEnemyEncounterCode( TRANSPORT_INTERCEPT_CODE ); + else if( GetTownIdForSector( gubPBSectorX, gubPBSectorY ) ) SetEnemyEncounterCode( ENEMY_INVASION_CODE ); //SAM sites not in towns will also be considered to be important else if( pSector->uiFlags & SF_SAM_SITE ) @@ -866,7 +885,7 @@ void InitPreBattleInterface( GROUP *pBattleGroup, BOOLEAN fPersistantPBI ) } HideButton( giMapContractButton ); - if( GetEnemyEncounterCode() == ENEMY_ENCOUNTER_CODE ) + if( GetEnemyEncounterCode() == ENEMY_ENCOUNTER_CODE || GetEnemyEncounterCode() == TRANSPORT_INTERCEPT_CODE ) { //we know how many enemies are here, so until we leave the sector, we will continue to display the value. //the flag will get cleared when time advances after the fEnemyInSector flag is clear. @@ -955,6 +974,7 @@ void InitPreBattleInterface( GROUP *pBattleGroup, BOOLEAN fPersistantPBI ) { case CREATURE_ATTACK_CODE: case ENEMY_ENCOUNTER_CODE: + case TRANSPORT_INTERCEPT_CODE: case ENEMY_INVASION_CODE: case ENEMY_INVASION_AIRDROP_CODE: case BLOODCAT_ATTACK_CODE: @@ -1213,6 +1233,7 @@ void RenderPBHeader( INT32 *piX, INT32 *piWidth) swprintf( str, gpStrategicString[ STR_PB_ENEMYINVASION_HEADER ] ); break; case ENEMY_ENCOUNTER_CODE: + case TRANSPORT_INTERCEPT_CODE: swprintf( str, gpStrategicString[ STR_PB_ENEMYENCOUNTER_HEADER ] ); break; case ENEMY_AMBUSH_CODE: @@ -2520,6 +2541,9 @@ void LogBattleResults( UINT8 ubVictoryCode) break; case CONCEALINSERTION_CODE: break; + case TRANSPORT_INTERCEPT_CODE: + AddHistoryToPlayersLog( HISTORY_INTERCEPTED_TRANSPORT_GROUP, 0, GetWorldTotalMin(), sSectorX, sSectorY ); + break; } // Flugente: campaign stats @@ -2534,6 +2558,7 @@ void LogBattleResults( UINT8 ubVictoryCode) AddHistoryToPlayersLog( HISTORY_LOSTTOWNSECTOR, 0, GetWorldTotalMin(), sSectorX, sSectorY ); break; case ENEMY_ENCOUNTER_CODE: + case TRANSPORT_INTERCEPT_CODE: AddHistoryToPlayersLog( HISTORY_LOSTBATTLE, 0, GetWorldTotalMin(), sSectorX, sSectorY ); break; case ENEMY_AMBUSH_CODE: @@ -2567,6 +2592,7 @@ void LogBattleResults( UINT8 ubVictoryCode) gCurrentIncident.usIncidentFlags |= INCIDENT_ATTACK_ENEMY; break; case ENEMY_ENCOUNTER_CODE: + case TRANSPORT_INTERCEPT_CODE: case ENTERING_ENEMY_SECTOR_CODE: case CREATURE_ATTACK_CODE: case ENTERING_BLOODCAT_LAIR_CODE: diff --git a/Strategic/PreBattle Interface.h b/Strategic/PreBattle Interface.h index d8bc045e3..78070486e 100644 --- a/Strategic/PreBattle Interface.h +++ b/Strategic/PreBattle Interface.h @@ -47,6 +47,8 @@ enum BLOODCAT_ATTACK_CODE, // Flugente: like CREATURE_ATTACK_CODE, but with cats ZOMBIE_ATTACK_CODE, // Flugente: like CREATURE_ATTACK_CODE, but with zombies BANDIT_ATTACK_CODE, // Flugente: like CREATURE_ATTACK_CODE, but with bandits + + TRANSPORT_INTERCEPT_CODE, // rftr: like ENEMY_ENCOUNTER_CODE }; extern BOOLEAN gfAutoAmbush; @@ -112,4 +114,4 @@ enum }; void LogBattleResults( UINT8 ubVictoryCode); -#endif \ No newline at end of file +#endif From 43e7e3dd1c35f94236c7a8bfeaa2e222ec66c0f7 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Thu, 16 Feb 2023 08:58:29 -0800 Subject: [PATCH 38/81] Fix --- Strategic/Auto Resolve.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Strategic/Auto Resolve.cpp b/Strategic/Auto Resolve.cpp index 87a0cbc8e..04fa2d561 100644 --- a/Strategic/Auto Resolve.cpp +++ b/Strategic/Auto Resolve.cpp @@ -6060,5 +6060,5 @@ BOOLEAN IndividualMilitiaInUse_AutoResolve( UINT32 aMilitiaId ) } } } - return FALSE; +} From 125050ce8388d19186d5f5fa564e42984d3b3889 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Thu, 16 Feb 2023 17:36:09 -0800 Subject: [PATCH 39/81] Add strategic event to track recent losses --- Strategic/Game Event Hook.h | 3 ++- Strategic/PreBattle Interface.cpp | 2 ++ Strategic/Strategic Transport Groups.cpp | 11 +++++++++++ Strategic/Strategic Transport Groups.h | 2 ++ 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Strategic/Game Event Hook.h b/Strategic/Game Event Hook.h index d35444dd8..fa9cacd98 100644 --- a/Strategic/Game Event Hook.h +++ b/Strategic/Game Event Hook.h @@ -155,6 +155,7 @@ enum EVENT_REBELCOMMAND, EVENT_RETURN_TRANSPORT_GROUP, + EVENT_TRANSPORT_GROUP_DEFEATED, NUMBER_OF_EVENT_TYPES_PLUS_ONE, NUMBER_OF_EVENT_TYPES = NUMBER_OF_EVENT_TYPES_PLUS_ONE - 1 @@ -219,4 +220,4 @@ void DeleteAllStrategicEvents(); // Flugente: return vector of all events of type ubCallbackID with time and param std::vector< std::pair > GetAllStrategicEventsOfType( UINT8 ubCallbackID ); -#endif \ No newline at end of file +#endif diff --git a/Strategic/PreBattle Interface.cpp b/Strategic/PreBattle Interface.cpp index d07fa4569..f05cf42ed 100644 --- a/Strategic/PreBattle Interface.cpp +++ b/Strategic/PreBattle Interface.cpp @@ -47,6 +47,7 @@ #include "CampaignStats.h" // added by Flugente #include "militiasquads.h" // added by Flugente #include "SkillCheck.h" // added by Flugente + #include "Strategic Transport Groups.h" #ifdef JA2UB #include "ub_config.h" @@ -2543,6 +2544,7 @@ void LogBattleResults( UINT8 ubVictoryCode) break; case TRANSPORT_INTERCEPT_CODE: AddHistoryToPlayersLog( HISTORY_INTERCEPTED_TRANSPORT_GROUP, 0, GetWorldTotalMin(), sSectorX, sSectorY ); + NotifyTransportGroupDefeated(); break; } diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index 0e1e9b312..486c68312 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -109,6 +109,7 @@ BOOLEAN DeployTransportGroup() // rftr todo: create a new group in the capital (same as attack/patrol groups) and send it to a friendly town with a mine! // limitations: max number of transport groups at any given time // track recent transport group interceptions + const INT8 recentLossCount = GetAllStrategicEventsOfType(EVENT_TRANSPORT_GROUP_DEFEATED).size(); // varying transport group quality/compositions // copied from NPC_ACTION_SEND_SOLDIERS_TO_BATTLE_LOCATION, which happens after the first non-welcome wagon battle // rftr todo: replace this with townid @@ -721,3 +722,13 @@ void ClearTransportGroupMap() transportGroupIdToSoldierMap.clear(); } +void NotifyTransportGroupDefeated() +{ + if (gGameExternalOptions.fStrategicTransportGroupsEnabled == FALSE) + return; + + const UINT32 hoursToRememberDefeat = 24 * 7; // 7 days + + AddStrategicEvent(EVENT_TRANSPORT_GROUP_DEFEATED, GetWorldTotalMin() + 60 * hoursToRememberDefeat, 0); +} + diff --git a/Strategic/Strategic Transport Groups.h b/Strategic/Strategic Transport Groups.h index fcd5976c5..3dbfdf8d3 100644 --- a/Strategic/Strategic Transport Groups.h +++ b/Strategic/Strategic Transport Groups.h @@ -15,4 +15,6 @@ void UpdateTransportGroupInventory(); void AddToTransportGroupMap(UINT8 groupId, int soldierClass, UINT8 amount); void ClearTransportGroupMap(); +void NotifyTransportGroupDefeated(); + #endif From e0204ecdb56472186a386018a70ac02ae5460c8b Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Thu, 16 Feb 2023 21:47:12 -0800 Subject: [PATCH 40/81] Remove readiness --- Strategic/Strategic Movement.h | 3 +-- Strategic/Strategic Transport Groups.cpp | 3 --- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/Strategic/Strategic Movement.h b/Strategic/Strategic Movement.h index 4393ab4cb..03f0d3ff6 100644 --- a/Strategic/Strategic Movement.h +++ b/Strategic/Strategic Movement.h @@ -85,8 +85,7 @@ typedef struct ENEMYGROUP UINT8 ubNumRobots; //number of enemy robots in the group UINT8 ubRobotsInBattle; //number of enemy robots currently in battle. - UINT8 ubReadiness; // Group readiness when spawned. Determines group member inventory. Currently used by only by strategic transport groups. - INT8 bPadding[10]; + INT8 bPadding[11]; }ENEMYGROUP; //NOTE: ALL FLAGS ARE CLEARED WHENEVER A GROUP ARRIVES IN A SECTOR, OR ITS WAYPOINTS ARE diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index 486c68312..a01b7b0be 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -125,7 +125,6 @@ BOOLEAN DeployTransportGroup() //pGroup = CreateNewEnemyGroupDepartingFromSector( SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), 0, grouptroops[0], groupelites[0], grouprobots[0], grouptanks[0], groupjeeps[0] ); pGroup = CreateNewEnemyGroupDepartingFromSector( SEC_D5, 10, 5, 1, 0, 0, 1 ); - pGroup->pEnemyGroup->ubReadiness = HighestPlayerProgressPercentage(); //Madd: unlimited reinforcements? if ( !gfUnlimitedTroops ) @@ -518,8 +517,6 @@ void UpdateTransportGroupInventory() pGroup = pGroup->next; } - const UINT8 groupReadiness = pGroup->pEnemyGroup->ubReadiness; - // found a matching transport groupid std::map::iterator soldierClassIter = groupIter->second.find(SOLDIER_CLASS_JEEP); if (soldierClassIter != groupIter->second.end()) From dc13640f66700475548c0264a8cc3515b6a6db67 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Sat, 18 Feb 2023 00:05:18 -0800 Subject: [PATCH 41/81] Refund ASD vehicles in TransferGroupToPool --- Strategic/Strategic AI.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Strategic/Strategic AI.cpp b/Strategic/Strategic AI.cpp index 179efe3bf..11160c850 100644 --- a/Strategic/Strategic AI.cpp +++ b/Strategic/Strategic AI.cpp @@ -6531,9 +6531,17 @@ INT16 FindGarrisonIndexForGroupIDPending( UINT8 ubGroupID ) void TransferGroupToPool( GROUP **pGroup ) { - //Madd: unlimited reinforcements? - if ( !gfUnlimitedTroops ) - giReinforcementPool += (*pGroup)->ubGroupSize; + if ((*pGroup)->usGroupTeam == ENEMY_TEAM) + { + //Madd: unlimited reinforcements? + if ( !gfUnlimitedTroops ) + giReinforcementPool += (*pGroup)->ubGroupSize; + + AddStrategicAIResources(ASD_ROBOT, (*pGroup)->pEnemyGroup->ubNumRobots); + AddStrategicAIResources(ASD_JEEP, (*pGroup)->pEnemyGroup->ubNumJeeps); + AddStrategicAIResources(ASD_TANK, (*pGroup)->pEnemyGroup->ubNumTanks); + } + RemovePGroup( *pGroup ); *pGroup = NULL; From 4e0f9061f9ce687e152cbb9bb595e191d77e18c8 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Sat, 18 Feb 2023 00:09:01 -0800 Subject: [PATCH 42/81] Add difficulty-specific behaviours Add last destination behaviour --- Strategic/Strategic Transport Groups.cpp | 86 +++++++++++++++++++----- 1 file changed, 68 insertions(+), 18 deletions(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index a01b7b0be..2a3815955 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -66,20 +66,24 @@ BOOLEAN DeployTransportGroup() if (giReinforcementPool <= 0) return FALSE; + const UINT8 difficulty = gGameOptions.ubDifficultyLevel; + // is there a mine here? - // rftr todo: valid destination towns depend on difficulty std::vector mineSectorIds; for (INT8 i = 0; i < NUM_TOWNS; ++i) { // skip towns that have no loyalty if (!gfTownUsesLoyalty[i]) continue; - // filter by TOWN ownership - if (IsTownUnderCompleteControlByEnemy(i) == FALSE) continue; + + // filter by TOWN ownership - expert/insane only + if ((difficulty == DIF_LEVEL_HARD || difficulty == DIF_LEVEL_INSANE) && IsTownUnderCompleteControlByEnemy(i) == FALSE) continue; + // skip towns with a shut down mine const INT8 mineIndex = GetMineIndexForTown(i); if (mineIndex == -1) continue; if (IsMineShutDown(mineIndex) == TRUE) continue; - // filter by MINE ownership + + // filter by MINE ownership - for novice/experienced, as hard/insane would have ignored this town above const INT16 mineSector = GetMineSectorForTown(i); if (StrategicMap[mineSector].fEnemyControlled == FALSE) continue; @@ -87,8 +91,8 @@ BOOLEAN DeployTransportGroup() } ScreenMsg(FONT_RED, MSG_INTERFACE, L"DeployTransportGroup valid town destinations: %d", mineSectorIds.size()); - // rftr todo: special case when only one town left? - if (mineSectorIds.size() < 1) return FALSE; + // no valid destinations + if (mineSectorIds.size() == 0) return FALSE; INT8 transportGroupCount = 0; GROUP* pGroup = gpGroupList; @@ -103,33 +107,79 @@ BOOLEAN DeployTransportGroup() ScreenMsg(FONT_RED, MSG_INTERFACE, L"DeployTransportGroup found existing transport groups: %d", transportGroupCount); // if there are too many active transport groups, don't deploy any more - // rftr todo: based on difficulty? - if (transportGroupCount >= gGameExternalOptions.iMaxSimultaneousTransportGroups) return FALSE; - + // maximum number of active groups is the number of valid destinations at queen decision time + if (transportGroupCount >= min(gGameExternalOptions.iMaxSimultaneousTransportGroups, mineSectorIds.size())) return FALSE; + // rftr todo: create a new group in the capital (same as attack/patrol groups) and send it to a friendly town with a mine! // limitations: max number of transport groups at any given time // track recent transport group interceptions const INT8 recentLossCount = GetAllStrategicEventsOfType(EVENT_TRANSPORT_GROUP_DEFEATED).size(); - // varying transport group quality/compositions + // copied from NPC_ACTION_SEND_SOLDIERS_TO_BATTLE_LOCATION, which happens after the first non-welcome wagon battle - // rftr todo: replace this with townid - // rftr todo: only pick towns that 1) have mines, and 2) are uncontested const UINT8 ubSectorID = (UINT8)mineSectorIds[Random(mineSectorIds.size())]; const SECTORINFO* pSector = &SectorInfo[ ubSectorID ]; // rftr: adjust group size and composition based on recent interceptions, game progress, etc - const INT32 ubNumSoldiers = 17; + UINT8 admins, troops, elites, robots, jeeps, tanks; + admins = troops = elites = robots = jeeps = tanks = 0; + + // special case for only one valid destination - expert/insane only + if ((difficulty == DIF_LEVEL_HARD || difficulty == DIF_LEVEL_INSANE) && mineSectorIds.size() == 1) + { + admins = 1; + elites = difficulty == DIF_LEVEL_INSANE ? 19 : 14; + + if (gGameExternalOptions.fASDActive) + { + if (gGameExternalOptions.fASDAssignsJeeps && ASDSoldierUpgradeToJeep()) + { + jeeps++; + elites--; + } + + if (gGameExternalOptions.fASDAssignsTanks) + { + const int numTanks = difficulty == DIF_LEVEL_INSANE ? 2 : 1; + for (int i = 0; i < numTanks; ++i) + { + if (ASDSoldierUpgradeToTank()) + { + tanks++; + elites--; + } + } + } - //InitializeGroup(GROUP_TYPE_TRANSPORT, ubNumSoldiers, grouptroops[0], groupelites[0], grouprobots[0], groupjeeps[0], grouptanks[0], Random(10) < difficultyMod); - //totalusedsoldiers += grouptroops[0] + groupelites[0] + grouprobots[0] + grouptanks[0] + groupjeeps[0]; + if (gGameExternalOptions.fASDAssignsRobots) + { + const int numRobots = Random(5); + for (int i = 0; i < numRobots; ++i) + { + if (ASDSoldierUpgradeToRobot()) + { + robots++; + elites--; + } + } + } + } + } + else // normal case + { + // rftr todo + admins = 10; + troops = 5; + elites = 1; + jeeps = 1; + } - //pGroup = CreateNewEnemyGroupDepartingFromSector( SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), 0, grouptroops[0], groupelites[0], grouprobots[0], grouptanks[0], groupjeeps[0] ); - pGroup = CreateNewEnemyGroupDepartingFromSector( SEC_D5, 10, 5, 1, 0, 0, 1 ); + // varying transport group quality/compositions + pGroup = CreateNewEnemyGroupDepartingFromSector( SEC_D5, admins, troops, elites, robots, tanks, jeeps ); //Madd: unlimited reinforcements? if ( !gfUnlimitedTroops ) { - giReinforcementPool -= ubNumSoldiers; + giReinforcementPool -= (admins + troops + elites + robots + jeeps + tanks); giReinforcementPool = max( giReinforcementPool, 0 ); } From 46f99195940c0d2a91f59f18822919127b91818b Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Sat, 18 Feb 2023 00:09:01 -0800 Subject: [PATCH 43/81] Add difficulty-specific behaviours Add last destination behaviour --- Strategic/Strategic Transport Groups.cpp | 86 +++++++++++++++++++----- 1 file changed, 68 insertions(+), 18 deletions(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index a01b7b0be..ba63cbae6 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -66,20 +66,24 @@ BOOLEAN DeployTransportGroup() if (giReinforcementPool <= 0) return FALSE; + const UINT8 difficulty = gGameOptions.ubDifficultyLevel; + // is there a mine here? - // rftr todo: valid destination towns depend on difficulty std::vector mineSectorIds; for (INT8 i = 0; i < NUM_TOWNS; ++i) { // skip towns that have no loyalty if (!gfTownUsesLoyalty[i]) continue; - // filter by TOWN ownership - if (IsTownUnderCompleteControlByEnemy(i) == FALSE) continue; + + // filter by TOWN ownership - expert/insane only + if ((difficulty == DIF_LEVEL_HARD || difficulty == DIF_LEVEL_INSANE) && IsTownUnderCompleteControlByEnemy(i) == FALSE) continue; + // skip towns with a shut down mine const INT8 mineIndex = GetMineIndexForTown(i); if (mineIndex == -1) continue; if (IsMineShutDown(mineIndex) == TRUE) continue; - // filter by MINE ownership + + // filter by MINE ownership - for novice/experienced, as hard/insane would have ignored this town above const INT16 mineSector = GetMineSectorForTown(i); if (StrategicMap[mineSector].fEnemyControlled == FALSE) continue; @@ -87,8 +91,8 @@ BOOLEAN DeployTransportGroup() } ScreenMsg(FONT_RED, MSG_INTERFACE, L"DeployTransportGroup valid town destinations: %d", mineSectorIds.size()); - // rftr todo: special case when only one town left? - if (mineSectorIds.size() < 1) return FALSE; + // no valid destinations + if (mineSectorIds.size() == 0) return FALSE; INT8 transportGroupCount = 0; GROUP* pGroup = gpGroupList; @@ -103,33 +107,79 @@ BOOLEAN DeployTransportGroup() ScreenMsg(FONT_RED, MSG_INTERFACE, L"DeployTransportGroup found existing transport groups: %d", transportGroupCount); // if there are too many active transport groups, don't deploy any more - // rftr todo: based on difficulty? - if (transportGroupCount >= gGameExternalOptions.iMaxSimultaneousTransportGroups) return FALSE; - + // maximum number of active groups is the number of valid destinations at queen decision time + if (transportGroupCount >= min(gGameExternalOptions.iMaxSimultaneousTransportGroups, mineSectorIds.size())) return FALSE; + // rftr todo: create a new group in the capital (same as attack/patrol groups) and send it to a friendly town with a mine! // limitations: max number of transport groups at any given time // track recent transport group interceptions const INT8 recentLossCount = GetAllStrategicEventsOfType(EVENT_TRANSPORT_GROUP_DEFEATED).size(); - // varying transport group quality/compositions + // copied from NPC_ACTION_SEND_SOLDIERS_TO_BATTLE_LOCATION, which happens after the first non-welcome wagon battle - // rftr todo: replace this with townid - // rftr todo: only pick towns that 1) have mines, and 2) are uncontested const UINT8 ubSectorID = (UINT8)mineSectorIds[Random(mineSectorIds.size())]; const SECTORINFO* pSector = &SectorInfo[ ubSectorID ]; // rftr: adjust group size and composition based on recent interceptions, game progress, etc - const INT32 ubNumSoldiers = 17; + UINT8 admins, troops, elites, robots, jeeps, tanks; + admins = troops = elites = robots = jeeps = tanks = 0; + + // special case for only one valid destination - expert/insane only + if ((difficulty == DIF_LEVEL_HARD || difficulty == DIF_LEVEL_INSANE) && mineSectorIds.size() == 1) + { + admins = 1; + elites = zDiffSetting[gGameOptions.ubDifficultyLevel].iMinEnemyGroupSize + 8; + + if (gGameExternalOptions.fASDActive) + { + if (gGameExternalOptions.fASDAssignsJeeps && ASDSoldierUpgradeToJeep()) + { + jeeps++; + elites--; + } + + if (gGameExternalOptions.fASDAssignsTanks) + { + const int numTanks = difficulty == DIF_LEVEL_INSANE ? 2 : 1; + for (int i = 0; i < numTanks; ++i) + { + if (ASDSoldierUpgradeToTank()) + { + tanks++; + elites--; + } + } + } - //InitializeGroup(GROUP_TYPE_TRANSPORT, ubNumSoldiers, grouptroops[0], groupelites[0], grouprobots[0], groupjeeps[0], grouptanks[0], Random(10) < difficultyMod); - //totalusedsoldiers += grouptroops[0] + groupelites[0] + grouprobots[0] + grouptanks[0] + groupjeeps[0]; + if (gGameExternalOptions.fASDAssignsRobots) + { + const int numRobots = Random(5); + for (int i = 0; i < numRobots; ++i) + { + if (ASDSoldierUpgradeToRobot()) + { + robots++; + elites--; + } + } + } + } + } + else // normal case + { + // rftr todo + admins = 10; + troops = 5; + elites = 1; + jeeps = 1; + } - //pGroup = CreateNewEnemyGroupDepartingFromSector( SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), 0, grouptroops[0], groupelites[0], grouprobots[0], grouptanks[0], groupjeeps[0] ); - pGroup = CreateNewEnemyGroupDepartingFromSector( SEC_D5, 10, 5, 1, 0, 0, 1 ); + // varying transport group quality/compositions + pGroup = CreateNewEnemyGroupDepartingFromSector( SEC_D5, admins, troops, elites, robots, tanks, jeeps ); //Madd: unlimited reinforcements? if ( !gfUnlimitedTroops ) { - giReinforcementPool -= ubNumSoldiers; + giReinforcementPool -= (admins + troops + elites + robots + jeeps + tanks); giReinforcementPool = max( giReinforcementPool, 0 ); } From a905aa2e7d7864b1b92ef6ddc40c1a7d517572dc Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Mon, 20 Feb 2023 23:45:02 -0800 Subject: [PATCH 44/81] Update group compositions --- Strategic/Strategic Transport Groups.cpp | 127 +++++++++++++++++------ 1 file changed, 95 insertions(+), 32 deletions(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index ba63cbae6..4aa233853 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -110,16 +110,13 @@ BOOLEAN DeployTransportGroup() // maximum number of active groups is the number of valid destinations at queen decision time if (transportGroupCount >= min(gGameExternalOptions.iMaxSimultaneousTransportGroups, mineSectorIds.size())) return FALSE; - // rftr todo: create a new group in the capital (same as attack/patrol groups) and send it to a friendly town with a mine! - // limitations: max number of transport groups at any given time // track recent transport group interceptions - const INT8 recentLossCount = GetAllStrategicEventsOfType(EVENT_TRANSPORT_GROUP_DEFEATED).size(); + const INT8 recentLossCount = min(5, GetAllStrategicEventsOfType(EVENT_TRANSPORT_GROUP_DEFEATED).size()); // copied from NPC_ACTION_SEND_SOLDIERS_TO_BATTLE_LOCATION, which happens after the first non-welcome wagon battle const UINT8 ubSectorID = (UINT8)mineSectorIds[Random(mineSectorIds.size())]; const SECTORINFO* pSector = &SectorInfo[ ubSectorID ]; - // rftr: adjust group size and composition based on recent interceptions, game progress, etc UINT8 admins, troops, elites, robots, jeeps, tanks; admins = troops = elites = robots = jeeps = tanks = 0; @@ -127,50 +124,116 @@ BOOLEAN DeployTransportGroup() if ((difficulty == DIF_LEVEL_HARD || difficulty == DIF_LEVEL_INSANE) && mineSectorIds.size() == 1) { admins = 1; - elites = zDiffSetting[gGameOptions.ubDifficultyLevel].iMinEnemyGroupSize + 8; + elites = difficulty == DIF_LEVEL_HARD ? 14 : 19; - if (gGameExternalOptions.fASDActive) + if (elites > 0 && gGameExternalOptions.fASDAssignsJeeps && ASDSoldierUpgradeToJeep()) { - if (gGameExternalOptions.fASDAssignsJeeps && ASDSoldierUpgradeToJeep()) - { - jeeps++; - elites--; - } + jeeps++; + elites--; + } - if (gGameExternalOptions.fASDAssignsTanks) + if (gGameExternalOptions.fASDAssignsTanks) + { + const int numTanks = difficulty == DIF_LEVEL_INSANE ? 2 : 1; + for (int i = 0; i < numTanks; ++i) { - const int numTanks = difficulty == DIF_LEVEL_INSANE ? 2 : 1; - for (int i = 0; i < numTanks; ++i) + if (elites > 0 && ASDSoldierUpgradeToTank()) { - if (ASDSoldierUpgradeToTank()) - { - tanks++; - elites--; - } + tanks++; + elites--; } } + } - if (gGameExternalOptions.fASDAssignsRobots) + if (gGameExternalOptions.fASDAssignsRobots) + { + const int numRobots = Random(5); + for (int i = 0; i < numRobots; ++i) { - const int numRobots = Random(5); - for (int i = 0; i < numRobots; ++i) + if (elites > 0 && ASDSoldierUpgradeToRobot()) { - if (ASDSoldierUpgradeToRobot()) - { - robots++; - elites--; - } + robots++; + elites--; } } } } else // normal case { - // rftr todo - admins = 10; - troops = 5; - elites = 1; - jeeps = 1; + const UINT8 progress = min(125, HighestPlayerProgressPercentage() + recentLossCount * 5); + + UINT8 difficultyMod = 1; + switch (difficulty) + { + case DIF_LEVEL_EASY: difficultyMod = 1; break; + case DIF_LEVEL_MEDIUM: difficultyMod = 2; break; + case DIF_LEVEL_HARD: difficultyMod = 3; break; + case DIF_LEVEL_INSANE: difficultyMod = 4; break; + default: break; + } + + // default composition + if (progress < 25) + { + admins = 8 - difficultyMod; + troops = difficultyMod; + } + else if (progress < 50) + { + admins = 10 - difficultyMod * 2; + troops = difficultyMod; + elites = difficultyMod; + } + else if (progress < 75) + { + admins = 2; + troops = 10 - difficultyMod * 2; + elites = difficultyMod * 2; + } + else if (progress <= 100) // intentional equality + { + admins = 2; + troops = 13 - difficultyMod * 3; + elites = difficultyMod * 3; + } + else // at least one recent interception at max progress + { + admins = 2; + troops = 18 - difficultyMod * 4; + elites = difficultyMod * 4; + } + + // add some vehicles, if possible + if (progress >= gGameExternalOptions.usJeepMinimumProgress) + { + if (elites > 0 && gGameExternalOptions.fASDAssignsJeeps && ASDSoldierUpgradeToJeep()) + { + jeeps++; + elites--; + } + } + + if (progress >= gGameExternalOptions.usTankMinimumProgress && Random(100) < (20 + difficultyMod * 10)) + { + if (elites > 0 && gGameExternalOptions.fASDAssignsTanks && ASDSoldierUpgradeToTank()) + { + tanks++; + elites--; + } + } + + if (progress >= gGameExternalOptions.usRobotMinimumProgress && Random(100) < (20 + difficultyMod * 10)) + { + const int numRobots = Random(difficultyMod + 1); + for (int i = 0; i < numRobots; ++i) + { + if (elites > 0 && gGameExternalOptions.fASDAssignsRobots && ASDSoldierUpgradeToRobot()) + { + robots++; + elites--; + } + } + } } // varying transport group quality/compositions From 61d67dc877a2bf7c4871a4b2e70e690b75019460 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Thu, 23 Feb 2023 01:08:31 -0800 Subject: [PATCH 45/81] Block out ARC mission to spawn a transport group --- GameSettings.cpp | 2 ++ GameSettings.h | 2 ++ Strategic/Rebel Command.cpp | 32 ++++++++++++++++++++++++++++++-- Strategic/Rebel Command.h | 1 + Utils/_ChineseText.cpp | 2 ++ Utils/_DutchText.cpp | 2 ++ Utils/_EnglishText.cpp | 2 ++ Utils/_FrenchText.cpp | 2 ++ Utils/_GermanText.cpp | 2 ++ Utils/_ItalianText.cpp | 2 ++ Utils/_PolishText.cpp | 2 ++ Utils/_RussianText.cpp | 2 ++ 12 files changed, 51 insertions(+), 2 deletions(-) diff --git a/GameSettings.cpp b/GameSettings.cpp index e5762d7bd..bb2b88e3e 100644 --- a/GameSettings.cpp +++ b/GameSettings.cpp @@ -4190,6 +4190,8 @@ void LoadRebelCommandSettings() gRebelCommandSettings.iDisruptAsdDuration_Bonus_Nightops = iniReader.ReadInteger("Rebel Command Settings", "DISRUPT_ASD_DURATION_BONUS_NIGHTOPS", 48, 0, 255); gRebelCommandSettings.iDisruptAsdDuration_Bonus_Technician = iniReader.ReadInteger("Rebel Command Settings", "DISRUPT_ASD_DURATION_BONUS_TECHNICIAN", 48, 0, 255); + gRebelCommandSettings.iForgeTransportOrdersSuccessChance = iniReader.ReadInteger("Rebel Command Settings", "FORGE_TRANSPORT_ORDERS_SUCCESS_CHANCE", 50, 0, 100); + gRebelCommandSettings.iGetEnemyMovementTargetsSuccessChance = iniReader.ReadInteger("Rebel Command Settings", "STRATEGIC_INTEL_SUCCESS_CHANCE", 50, 0, 100); gRebelCommandSettings.iGetEnemyMovementTargetsDuration = iniReader.ReadInteger("Rebel Command Settings", "STRATEGIC_INTEL_DURATION", 72, 0, 255); gRebelCommandSettings.iGetEnemyMovementTargetsDuration_Bonus_Covert = iniReader.ReadInteger("Rebel Command Settings", "STRATEGIC_INTEL_DURATION_BONUS_COVERT", 48, 0, 255); diff --git a/GameSettings.h b/GameSettings.h index 833cc56b6..097315e62 100644 --- a/GameSettings.h +++ b/GameSettings.h @@ -1881,6 +1881,8 @@ typedef struct UINT8 iDisruptAsdDuration_Bonus_Nightops; UINT8 iDisruptAsdDuration_Bonus_Technician; + INT8 iForgeTransportOrdersSuccessChance; + INT8 iGetEnemyMovementTargetsSuccessChance; UINT8 iGetEnemyMovementTargetsDuration; UINT8 iGetEnemyMovementTargetsDuration_Bonus_Covert; diff --git a/Strategic/Rebel Command.cpp b/Strategic/Rebel Command.cpp index f7d257ec8..824484a73 100644 --- a/Strategic/Rebel Command.cpp +++ b/Strategic/Rebel Command.cpp @@ -41,8 +41,10 @@ How to add a new admin action: - if effect applies outside of towns, add help text range band as appropriate to SetupAdminActionBox How to add a new mission: -- add to the RebelCommandAgentMissions enum in the header -- add strings to text files (szRebelCommandAgentMissionsText) +- add strings to text files (szRebelCommandText (trait bonuses), szRebelCommandAgentMissionsText (title/description)) +- add to the RebelCommandText and RebelCommandAgentMissions enums in the header +- add to the RebelCommandAgentMissionsText enums in the cpp +- add mission variables to GameSettings - add values to MissionHelpers::missionInfo table in SetupInfo() - add to valid check in HandleStrategicEvent() (allows advance from first event/prepare to second event/active effect) - add to SetupMissionAgentBox() (mission description and merc bonus text) @@ -405,6 +407,7 @@ enum RebelCommandAgentMissionsText // keep this synced with szRebelCommandAgentM { MISSION_TEXT(DEEP_DEPLOYMENT) MISSION_TEXT(DISRUPT_ASD) + MISSION_TEXT(FORGE_TRANSPORT_ORDERS) MISSION_TEXT(GET_ENEMY_MOVEMENT_TARGETS) MISSION_TEXT(IMPROVE_LOCAL_SHOPS) MISSION_TEXT(REDUCE_STRATEGIC_DECISION_SPEED) @@ -2454,6 +2457,12 @@ BOOLEAN SetupMissionAgentBox(UINT16 x, UINT16 y, INT8 index) } } + case RCAM_FORGE_TRANSPORT_ORDERS: + { + // no special modifiers. included for completeness. + } + break; + case RCAM_GET_ENEMY_MOVEMENT_TARGETS: { // no special modifiers. included for completeness. @@ -2847,6 +2856,14 @@ void PrepareMission(INT8 index) } break; + case RCAM_FORGE_TRANSPORT_ORDERS: + { + missionTitle = RCAMT_FORGE_TRANSPORT_ORDERS_TITLE; + missionSuccessChance = gRebelCommandSettings.iForgeTransportOrdersSuccessChance; + missionDuration = 12; + } + break; + case RCAM_GET_ENEMY_MOVEMENT_TARGETS: { missionTitle = RCAMT_GET_ENEMY_MOVEMENT_TARGETS_TITLE; @@ -4299,6 +4316,16 @@ void SetupInfo() {0, 0, 0, 0}, {0, MissionHelpers::DISRUPT_ASD_STEAL_FUEL, MissionHelpers::DISRUPT_ASD_DESTROY_RESERVES, 0} }); + //RCAM_FORGE_TRANSPORT_ORDERS + MissionHelpers::missionInfo.push_back( + { + {COVERT_NT }, + {-1}, + {0}, + {0.f}, + {0}, + {0} + }); //RCAM_GET_ENEMY_MOVEMENT_TARGETS MissionHelpers::missionInfo.push_back( { @@ -4902,6 +4929,7 @@ void HandleStrategicEvent(const UINT32 eventParam) { case RCAM_DEEP_DEPLOYMENT: case RCAM_DISRUPT_ASD: + case RCAM_FORGE_TRANSPORT_ORDERS: case RCAM_GET_ENEMY_MOVEMENT_TARGETS: case RCAM_IMPROVE_LOCAL_SHOPS: case RCAM_REDUCE_STRATEGIC_DECISION_SPEED: diff --git a/Strategic/Rebel Command.h b/Strategic/Rebel Command.h index f8c9bc241..22b6fd3b6 100644 --- a/Strategic/Rebel Command.h +++ b/Strategic/Rebel Command.h @@ -78,6 +78,7 @@ enum RebelCommandAgentMissions RCAM_NONE = -1, RCAM_DEEP_DEPLOYMENT = 0, RCAM_DISRUPT_ASD, // only available if ASD enabled + RCAM_FORGE_TRANSPORT_ORDERS, RCAM_GET_ENEMY_MOVEMENT_TARGETS, // aka Strategic Intel RCAM_IMPROVE_LOCAL_SHOPS, RCAM_REDUCE_STRATEGIC_DECISION_SPEED, // aka Slower Strategic Decisions diff --git a/Utils/_ChineseText.cpp b/Utils/_ChineseText.cpp index 695fc5929..7203f8980 100644 --- a/Utils/_ChineseText.cpp +++ b/Utils/_ChineseText.cpp @@ -12095,6 +12095,8 @@ STR16 szRebelCommandAgentMissionsText[] = L"协同行动,悄悄地抵进敌军,但是要小心:这可能会让你部署在劣势区域。当进攻敌军部队时,部署区会更大。", //L"Coordinate efforts to find ways to sneak up on the enemy, but be careful: it's equally possible to put yourself in a disadvantaged deployment area. When attacking enemy forces, the deployment area is much larger.", L"扰乱ASD", //L"Disrupt ASD", L"破坏Arulco特种部门(ASD)的日常行动。临时阻止ASD部署更多的机械化单位,并且大幅度降低他们的每日收入。", //L"Wreak havoc on the day-to-day operations of the Arulco Special Division. Temporarily prevent the ASD from deploying additional mechanised units, and drastically reduce their daily income.", + L"Forge Transport Orders", + L"Create a bogus supply request. An enemy transport group will be ordered to rendezvous at this agent's location.", L"战略情报", //L"Strategic Intel", L"侦听敌人,发现敌军的攻击目标。当在战略地图上观察队伍时,敌军优先进攻的目标区域会被标红。", //L"Intercept plans and discover where enemies intend to strike. When viewing teams on the strategic map, sectors prioritised by the enemy will be marked in red.", L"强化本地商店", //L"Improve Local Shops", diff --git a/Utils/_DutchText.cpp b/Utils/_DutchText.cpp index 77e4cba5b..59f4fa5a7 100644 --- a/Utils/_DutchText.cpp +++ b/Utils/_DutchText.cpp @@ -12105,6 +12105,8 @@ STR16 szRebelCommandAgentMissionsText[] = L"Coordinate efforts to find ways to sneak up on the enemy, but be careful: it's equally possible to put yourself in a disadvantaged deployment area. When attacking enemy forces, the deployment area is much larger.", L"Disrupt ASD", L"Wreak havoc on the day-to-day operations of the Arulco Special Division. Temporarily prevent the ASD from deploying additional mechanised units, and drastically reduce their daily income.", + L"Forge Transport Orders", + L"Create a bogus supply request. An enemy transport group will be ordered to rendezvous at this agent's location.", L"Strategic Intel", L"Intercept plans and discover where enemies intend to strike. When viewing teams on the strategic map, sectors prioritised by the enemy will be marked in red.", L"Improve Local Shops", diff --git a/Utils/_EnglishText.cpp b/Utils/_EnglishText.cpp index bc75fc678..e91a0957a 100644 --- a/Utils/_EnglishText.cpp +++ b/Utils/_EnglishText.cpp @@ -12095,6 +12095,8 @@ STR16 szRebelCommandAgentMissionsText[] = L"Coordinate efforts to find ways to sneak up on the enemy, but be careful: it's equally possible to put yourself in a disadvantaged deployment area. When attacking enemy forces, the deployment area is much larger.", L"Disrupt ASD", L"Wreak havoc on the day-to-day operations of the Arulco Special Division. Temporarily prevent the ASD from deploying additional mechanised units, and drastically reduce their daily income.", + L"Forge Transport Orders", + L"Create a bogus supply request. An enemy transport group will be ordered to rendezvous at this agent's location.", L"Strategic Intel", L"Intercept plans and discover where enemies intend to strike. When viewing teams on the strategic map, sectors prioritised by the enemy will be marked in red.", L"Improve Local Shops", diff --git a/Utils/_FrenchText.cpp b/Utils/_FrenchText.cpp index dc183be94..1e5579398 100644 --- a/Utils/_FrenchText.cpp +++ b/Utils/_FrenchText.cpp @@ -12087,6 +12087,8 @@ STR16 szRebelCommandAgentMissionsText[] = L"Coordinate efforts to find ways to sneak up on the enemy, but be careful: it's equally possible to put yourself in a disadvantaged deployment area. When attacking enemy forces, the deployment area is much larger.", L"Disrupt ASD", L"Wreak havoc on the day-to-day operations of the Arulco Special Division. Temporarily prevent the ASD from deploying additional mechanised units, and drastically reduce their daily income.", + L"Forge Transport Orders", + L"Create a bogus supply request. An enemy transport group will be ordered to rendezvous at this agent's location.", L"Strategic Intel", L"Intercept plans and discover where enemies intend to strike. When viewing teams on the strategic map, sectors prioritised by the enemy will be marked in red.", L"Improve Local Shops", diff --git a/Utils/_GermanText.cpp b/Utils/_GermanText.cpp index d2d6009a3..1f5664538 100644 --- a/Utils/_GermanText.cpp +++ b/Utils/_GermanText.cpp @@ -12009,6 +12009,8 @@ STR16 szRebelCommandAgentMissionsText[] = L"Coordinate efforts to find ways to sneak up on the enemy, but be careful: it's equally possible to put yourself in a disadvantaged deployment area. When attacking enemy forces, the deployment area is much larger.", L"Disrupt ASD", L"Wreak havoc on the day-to-day operations of the Arulco Special Division. Temporarily prevent the ASD from deploying additional mechanised units, and drastically reduce their daily income.", + L"Forge Transport Orders", + L"Create a bogus supply request. An enemy transport group will be ordered to rendezvous at this agent's location.", L"Strategic Intel", L"Intercept plans and discover where enemies intend to strike. When viewing teams on the strategic map, sectors prioritised by the enemy will be marked in red.", L"Improve Local Shops", diff --git a/Utils/_ItalianText.cpp b/Utils/_ItalianText.cpp index 9a3463944..e6c88a130 100644 --- a/Utils/_ItalianText.cpp +++ b/Utils/_ItalianText.cpp @@ -12096,6 +12096,8 @@ STR16 szRebelCommandAgentMissionsText[] = L"Coordinate efforts to find ways to sneak up on the enemy, but be careful: it's equally possible to put yourself in a disadvantaged deployment area. When attacking enemy forces, the deployment area is much larger.", L"Disrupt ASD", L"Wreak havoc on the day-to-day operations of the Arulco Special Division. Temporarily prevent the ASD from deploying additional mechanised units, and drastically reduce their daily income.", + L"Forge Transport Orders", + L"Create a bogus supply request. An enemy transport group will be ordered to rendezvous at this agent's location.", L"Strategic Intel", L"Intercept plans and discover where enemies intend to strike. When viewing teams on the strategic map, sectors prioritised by the enemy will be marked in red.", L"Improve Local Shops", diff --git a/Utils/_PolishText.cpp b/Utils/_PolishText.cpp index 187348df0..537b533c0 100644 --- a/Utils/_PolishText.cpp +++ b/Utils/_PolishText.cpp @@ -12109,6 +12109,8 @@ STR16 szRebelCommandAgentMissionsText[] = L"Coordinate efforts to find ways to sneak up on the enemy, but be careful: it's equally possible to put yourself in a disadvantaged deployment area. When attacking enemy forces, the deployment area is much larger.", L"Disrupt ASD", L"Wreak havoc on the day-to-day operations of the Arulco Special Division. Temporarily prevent the ASD from deploying additional mechanised units, and drastically reduce their daily income.", + L"Forge Transport Orders", + L"Create a bogus supply request. An enemy transport group will be ordered to rendezvous at this agent's location.", L"Strategic Intel", L"Intercept plans and discover where enemies intend to strike. When viewing teams on the strategic map, sectors prioritised by the enemy will be marked in red.", L"Improve Local Shops", diff --git a/Utils/_RussianText.cpp b/Utils/_RussianText.cpp index c1d100e13..8fa016bcd 100644 --- a/Utils/_RussianText.cpp +++ b/Utils/_RussianText.cpp @@ -12090,6 +12090,8 @@ STR16 szRebelCommandAgentMissionsText[] = L"Coordinate efforts to find ways to sneak up on the enemy, but be careful: it's equally possible to put yourself in a disadvantaged deployment area. When attacking enemy forces, the deployment area is much larger.", L"Disrupt ASD", L"Wreak havoc on the day-to-day operations of the Arulco Special Division. Temporarily prevent the ASD from deploying additional mechanised units, and drastically reduce their daily income.", + L"Forge Transport Orders", + L"Create a bogus supply request. An enemy transport group will be ordered to rendezvous at this agent's location.", L"Strategic Intel", L"Intercept plans and discover where enemies intend to strike. When viewing teams on the strategic map, sectors prioritised by the enemy will be marked in red.", L"Improve Local Shops", From 6d743810ef00bf5e9ff6e6270dca1754a0bef336 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Mon, 27 Feb 2023 00:22:23 -0800 Subject: [PATCH 46/81] Hook up forge transport order mission Move transport group populator into its own function --- Strategic/Rebel Command.cpp | 30 ++- Strategic/Strategic Transport Groups.cpp | 259 ++++++++++++----------- Strategic/Strategic Transport Groups.h | 4 +- 3 files changed, 167 insertions(+), 126 deletions(-) diff --git a/Strategic/Rebel Command.cpp b/Strategic/Rebel Command.cpp index 824484a73..b5ce30aa0 100644 --- a/Strategic/Rebel Command.cpp +++ b/Strategic/Rebel Command.cpp @@ -93,6 +93,7 @@ Points of interest: #include "Strategic Mines.h" #include "Strategic Movement.h" #include "Strategic Town Loyalty.h" +#include "Strategic Transport Groups.h" #include "Structure Wrap.h" #include "Tactical Save.h" #include "Text.h" @@ -2224,6 +2225,7 @@ BOOLEAN SetupMissionAgentBox(UINT16 x, UINT16 y, INT8 index) { case RCAM_DEEP_DEPLOYMENT: swprintf(sText, szRebelCommandAgentMissionsText[RCAMT_DEEP_DEPLOYMENT_TITLE]); break; case RCAM_DISRUPT_ASD: swprintf(sText, szRebelCommandAgentMissionsText[RCAMT_DISRUPT_ASD_TITLE]); break; + case RCAM_FORGE_TRANSPORT_ORDERS: swprintf(sText, szRebelCommandAgentMissionsText[RCAMT_FORGE_TRANSPORT_ORDERS_TITLE]); break; case RCAM_GET_ENEMY_MOVEMENT_TARGETS: swprintf(sText, szRebelCommandAgentMissionsText[RCAMT_GET_ENEMY_MOVEMENT_TARGETS_TITLE]); break; case RCAM_IMPROVE_LOCAL_SHOPS: swprintf(sText, szRebelCommandAgentMissionsText[RCAMT_IMPROVE_LOCAL_SHOPS_TITLE]); break; case RCAM_REDUCE_STRATEGIC_DECISION_SPEED: swprintf(sText, szRebelCommandAgentMissionsText[RCAMT_REDUCE_STRATEGIC_DECISION_SPEED_TITLE]); break; @@ -2244,6 +2246,7 @@ BOOLEAN SetupMissionAgentBox(UINT16 x, UINT16 y, INT8 index) { case RCAM_DEEP_DEPLOYMENT: missionDurationBase = gRebelCommandSettings.iDeepDeploymentDuration; break; case RCAM_DISRUPT_ASD: missionDurationBase = gRebelCommandSettings.iDisruptAsdDuration; break; + case RCAM_FORGE_TRANSPORT_ORDERS: missionDurationBase = 1; break; // instant effect case RCAM_GET_ENEMY_MOVEMENT_TARGETS: missionDurationBase = gRebelCommandSettings.iGetEnemyMovementTargetsDuration; break; case RCAM_IMPROVE_LOCAL_SHOPS: missionDurationBase = gRebelCommandSettings.iImproveLocalShopsDuration; break; case RCAM_REDUCE_STRATEGIC_DECISION_SPEED: missionDurationBase = gRebelCommandSettings.iReduceStrategicDecisionSpeedDuration; break; @@ -2267,6 +2270,7 @@ BOOLEAN SetupMissionAgentBox(UINT16 x, UINT16 y, INT8 index) { case RCAM_DEEP_DEPLOYMENT: missionSuccessChanceBase = gRebelCommandSettings.iDeepDeploymentSuccessChance; break; case RCAM_DISRUPT_ASD: missionSuccessChanceBase = gRebelCommandSettings.iDisruptAsdSuccessChance; break; + case RCAM_FORGE_TRANSPORT_ORDERS: missionSuccessChanceBase = gRebelCommandSettings.iForgeTransportOrdersSuccessChance; break; case RCAM_GET_ENEMY_MOVEMENT_TARGETS: missionSuccessChanceBase = gRebelCommandSettings.iGetEnemyMovementTargetsSuccessChance; break; case RCAM_IMPROVE_LOCAL_SHOPS: missionSuccessChanceBase = gRebelCommandSettings.iImproveLocalShopsSuccessChance; break; case RCAM_REDUCE_STRATEGIC_DECISION_SPEED: missionSuccessChanceBase = gRebelCommandSettings.iReduceStrategicDecisionSpeedSuccessChance; break; @@ -2287,6 +2291,7 @@ BOOLEAN SetupMissionAgentBox(UINT16 x, UINT16 y, INT8 index) { case RCAM_DEEP_DEPLOYMENT: swprintf(sText, szRebelCommandAgentMissionsText[RCAMT_DEEP_DEPLOYMENT_DESC]); break; case RCAM_DISRUPT_ASD: swprintf(sText, szRebelCommandAgentMissionsText[RCAMT_DISRUPT_ASD_DESC]); break; + case RCAM_FORGE_TRANSPORT_ORDERS: swprintf(sText, szRebelCommandAgentMissionsText[RCAMT_FORGE_TRANSPORT_ORDERS_DESC]); break; case RCAM_GET_ENEMY_MOVEMENT_TARGETS: swprintf(sText, szRebelCommandAgentMissionsText[RCAMT_GET_ENEMY_MOVEMENT_TARGETS_DESC]); break; case RCAM_IMPROVE_LOCAL_SHOPS: swprintf(sText, szRebelCommandAgentMissionsText[RCAMT_IMPROVE_LOCAL_SHOPS_DESC]); break; case RCAM_REDUCE_STRATEGIC_DECISION_SPEED: swprintf(sText, szRebelCommandAgentMissionsText[RCAMT_REDUCE_STRATEGIC_DECISION_SPEED_DESC]); break; @@ -2619,7 +2624,13 @@ BOOLEAN SetupMissionAgentBox(UINT16 x, UINT16 y, INT8 index) swprintf(sText, szRebelCommandText[RCT_MISSION_CANT_START_CONTRACT_EXPIRING]); } } - else if (agentIndex[index] == mercs.size() && rebelCommandSaveInfo.availableMissions[index] == RCAM_SEND_SUPPLIES_TO_TOWN) + else if (agentIndex[index] == mercs.size() && + ( + rebelCommandSaveInfo.availableMissions[index] == RCAM_SEND_SUPPLIES_TO_TOWN || + rebelCommandSaveInfo.availableMissions[index] == RCAM_FORGE_TRANSPORT_ORDERS + ) + + ) { canStartMission = FALSE; swprintf(sText, szRebelCommandText[RCT_MISSION_CANT_USE_REBEL_AGENT]); @@ -3914,6 +3925,7 @@ void DailyUpdate() { if (i == RCAM_SOLDIER_BOUNTIES_KINGPIN && !(CheckFact(FACT_KINGPIN_INTRODUCED_SELF, 0) == TRUE && CheckFact(FACT_KINGPIN_DEAD, 0) == FALSE && CheckFact(FACT_KINGPIN_IS_ENEMY, 0) == FALSE && CurrentPlayerProgressPercentage() >= 30)) continue; else if (i == RCAM_DISRUPT_ASD && gGameExternalOptions.fASDActive == FALSE) continue; + else if (i == RCAM_FORGE_TRANSPORT_ORDERS && gGameExternalOptions.fStrategicTransportGroupsEnabled == FALSE) continue; validMissions.insert(static_cast(i)); } @@ -4954,7 +4966,15 @@ void HandleStrategicEvent(const UINT32 eventParam) if (validMission) { const UINT32 activatedMissionParam = SerialiseMissionSecondEvent(evt1.sentGenericRebelAgent, evt1.mercProfileId, mission, extraBits); - AddStrategicEvent(EVENT_REBELCOMMAND, GetWorldTotalMin() + 60 * evt1.missionDurationInHours, activatedMissionParam); + if (mission == RCAM_FORGE_TRANSPORT_ORDERS) + { + // don't send a follow-up event for instant-result missions + } + else + { + AddStrategicEvent(EVENT_REBELCOMMAND, GetWorldTotalMin() + 60 * evt1.missionDurationInHours, activatedMissionParam); + missionMap.insert(std::make_pair(mission, activatedMissionParam)); + } if (!evt1.sentGenericRebelAgent) { @@ -4963,6 +4983,11 @@ void HandleStrategicEvent(const UINT32 eventParam) SOLDIERTYPE* pSoldier = MercPtrs[i]; if (pSoldier->ubProfile == evt1.mercProfileId) { + if (mission == RCAM_FORGE_TRANSPORT_ORDERS) + { + ForceDeployTransportGroup(SECTOR(pSoldier->sSectorX, pSoldier->sSectorY)); + } + // mission successful! give some experience pts StatChange(pSoldier, LDRAMT, 20, FROM_SUCCESS); StatChange(pSoldier, WISDOMAMT, 15, FROM_SUCCESS); @@ -4971,7 +4996,6 @@ void HandleStrategicEvent(const UINT32 eventParam) } } - missionMap.insert(std::make_pair(mission, activatedMissionParam)); swprintf(msgBoxText, szRebelCommandText[RCT_MISSION_SUCCESS], szRebelCommandAgentMissionsText[evt1.missionId * 2]); swprintf(screenMsgText, szRebelCommandText[RCT_MISSION_SUCCESS], szRebelCommandAgentMissionsText[evt1.missionId * 2]); ScreenMsg(FONT_MCOLOR_LTGREEN, MSG_INTERFACE, screenMsgText); diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index 4aa233853..b8914c76b 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -58,6 +58,8 @@ extern BOOLEAN gfTownUsesLoyalty[MAX_TOWNS]; std::map> transportGroupIdToSoldierMap; +void PopulateTransportGroup(UINT8& admins, UINT8& troops, UINT8& elites, UINT8& jeeps, UINT8& tanks, UINT8& robots, UINT8 progress, int difficulty, BOOLEAN trySpecialCase); + BOOLEAN DeployTransportGroup() { if (gGameExternalOptions.fStrategicTransportGroupsEnabled == FALSE) @@ -115,129 +117,13 @@ BOOLEAN DeployTransportGroup() // copied from NPC_ACTION_SEND_SOLDIERS_TO_BATTLE_LOCATION, which happens after the first non-welcome wagon battle const UINT8 ubSectorID = (UINT8)mineSectorIds[Random(mineSectorIds.size())]; - const SECTORINFO* pSector = &SectorInfo[ ubSectorID ]; UINT8 admins, troops, elites, robots, jeeps, tanks; - admins = troops = elites = robots = jeeps = tanks = 0; - - // special case for only one valid destination - expert/insane only - if ((difficulty == DIF_LEVEL_HARD || difficulty == DIF_LEVEL_INSANE) && mineSectorIds.size() == 1) - { - admins = 1; - elites = difficulty == DIF_LEVEL_HARD ? 14 : 19; - - if (elites > 0 && gGameExternalOptions.fASDAssignsJeeps && ASDSoldierUpgradeToJeep()) - { - jeeps++; - elites--; - } - - if (gGameExternalOptions.fASDAssignsTanks) - { - const int numTanks = difficulty == DIF_LEVEL_INSANE ? 2 : 1; - for (int i = 0; i < numTanks; ++i) - { - if (elites > 0 && ASDSoldierUpgradeToTank()) - { - tanks++; - elites--; - } - } - } - - if (gGameExternalOptions.fASDAssignsRobots) - { - const int numRobots = Random(5); - for (int i = 0; i < numRobots; ++i) - { - if (elites > 0 && ASDSoldierUpgradeToRobot()) - { - robots++; - elites--; - } - } - } - } - else // normal case - { - const UINT8 progress = min(125, HighestPlayerProgressPercentage() + recentLossCount * 5); - - UINT8 difficultyMod = 1; - switch (difficulty) - { - case DIF_LEVEL_EASY: difficultyMod = 1; break; - case DIF_LEVEL_MEDIUM: difficultyMod = 2; break; - case DIF_LEVEL_HARD: difficultyMod = 3; break; - case DIF_LEVEL_INSANE: difficultyMod = 4; break; - default: break; - } - - // default composition - if (progress < 25) - { - admins = 8 - difficultyMod; - troops = difficultyMod; - } - else if (progress < 50) - { - admins = 10 - difficultyMod * 2; - troops = difficultyMod; - elites = difficultyMod; - } - else if (progress < 75) - { - admins = 2; - troops = 10 - difficultyMod * 2; - elites = difficultyMod * 2; - } - else if (progress <= 100) // intentional equality - { - admins = 2; - troops = 13 - difficultyMod * 3; - elites = difficultyMod * 3; - } - else // at least one recent interception at max progress - { - admins = 2; - troops = 18 - difficultyMod * 4; - elites = difficultyMod * 4; - } - - // add some vehicles, if possible - if (progress >= gGameExternalOptions.usJeepMinimumProgress) - { - if (elites > 0 && gGameExternalOptions.fASDAssignsJeeps && ASDSoldierUpgradeToJeep()) - { - jeeps++; - elites--; - } - } - - if (progress >= gGameExternalOptions.usTankMinimumProgress && Random(100) < (20 + difficultyMod * 10)) - { - if (elites > 0 && gGameExternalOptions.fASDAssignsTanks && ASDSoldierUpgradeToTank()) - { - tanks++; - elites--; - } - } - - if (progress >= gGameExternalOptions.usRobotMinimumProgress && Random(100) < (20 + difficultyMod * 10)) - { - const int numRobots = Random(difficultyMod + 1); - for (int i = 0; i < numRobots; ++i) - { - if (elites > 0 && gGameExternalOptions.fASDAssignsRobots && ASDSoldierUpgradeToRobot()) - { - robots++; - elites--; - } - } - } - } + const UINT8 progress = min(125, HighestPlayerProgressPercentage() + recentLossCount * 5); + PopulateTransportGroup(admins, troops, elites, jeeps, tanks, robots, progress, difficulty, mineSectorIds.size() == 1); // varying transport group quality/compositions - pGroup = CreateNewEnemyGroupDepartingFromSector( SEC_D5, admins, troops, elites, robots, tanks, jeeps ); + pGroup = CreateNewEnemyGroupDepartingFromSector( SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), admins, troops, elites, robots, tanks, jeeps ); //Madd: unlimited reinforcements? if ( !gfUnlimitedTroops ) @@ -254,12 +140,22 @@ BOOLEAN DeployTransportGroup() return TRUE; } -BOOLEAN ReturnTransportGroup(INT32 option1) +BOOLEAN ForceDeployTransportGroup(UINT8 sectorId) +{ + UINT8 admins, troops, elites, robots, jeeps, tanks; + const INT8 recentLossCount = min(5, GetAllStrategicEventsOfType(EVENT_TRANSPORT_GROUP_DEFEATED).size()); + const UINT8 progress = min(125, HighestPlayerProgressPercentage() + recentLossCount * 5); + const UINT8 difficulty = gGameOptions.ubDifficultyLevel; + PopulateTransportGroup(admins, troops, elites, jeeps, tanks, robots, progress, difficulty, FALSE); + return TRUE; +} + +BOOLEAN ReturnTransportGroup(INT32 groupId) { GROUP* pGroup = gpGroupList; while (pGroup) { - if (pGroup->ubGroupID == option1) + if (pGroup->ubGroupID == groupId) { MoveSAIGroupToSector( &pGroup, SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), EVASIVE, TRANSPORT ); pGroup->uiFlags &= ~GROUPFLAG_TRANSPORT_ENROUTE; @@ -270,7 +166,7 @@ BOOLEAN ReturnTransportGroup(INT32 option1) if (pGroup == nullptr) { - ScreenMsg( FONT_YELLOW, MSG_INTERFACE, L"RETURN_TRANSPORT_GROUP failed to find groupid %d", option1); + ScreenMsg( FONT_YELLOW, MSG_INTERFACE, L"RETURN_TRANSPORT_GROUP failed to find groupid %d", groupId); return FALSE; } @@ -842,3 +738,122 @@ void NotifyTransportGroupDefeated() AddStrategicEvent(EVENT_TRANSPORT_GROUP_DEFEATED, GetWorldTotalMin() + 60 * hoursToRememberDefeat, 0); } +void PopulateTransportGroup(UINT8& admins, UINT8& troops, UINT8& elites, UINT8& jeeps, UINT8& tanks, UINT8& robots, UINT8 progress, int difficulty, BOOLEAN trySpecialCase) +{ + admins = troops = elites = robots = jeeps = tanks = 0; + + // special case for only one valid destination - expert/insane only + if (trySpecialCase && (difficulty == DIF_LEVEL_HARD || difficulty == DIF_LEVEL_INSANE)) + { + admins = 1; + elites = difficulty == DIF_LEVEL_HARD ? 14 : 19; + + if (elites > 0 && gGameExternalOptions.fASDAssignsJeeps && ASDSoldierUpgradeToJeep()) + { + jeeps++; + elites--; + } + + if (gGameExternalOptions.fASDAssignsTanks) + { + const int numTanks = difficulty == DIF_LEVEL_INSANE ? 2 : 1; + for (int i = 0; i < numTanks; ++i) + { + if (elites > 0 && ASDSoldierUpgradeToTank()) + { + tanks++; + elites--; + } + } + } + + if (gGameExternalOptions.fASDAssignsRobots) + { + const int numRobots = Random(5); + for (int i = 0; i < numRobots; ++i) + { + if (elites > 0 && ASDSoldierUpgradeToRobot()) + { + robots++; + elites--; + } + } + } + } + else // normal case + { + UINT8 difficultyMod = 1; + switch (difficulty) + { + case DIF_LEVEL_EASY: difficultyMod = 1; break; + case DIF_LEVEL_MEDIUM: difficultyMod = 2; break; + case DIF_LEVEL_HARD: difficultyMod = 3; break; + case DIF_LEVEL_INSANE: difficultyMod = 4; break; + default: break; + } + + // default composition + if (progress < 25) + { + admins = 8 - difficultyMod; + troops = difficultyMod; + } + else if (progress < 50) + { + admins = 10 - difficultyMod * 2; + troops = difficultyMod; + elites = difficultyMod; + } + else if (progress < 75) + { + admins = 2; + troops = 10 - difficultyMod * 2; + elites = difficultyMod * 2; + } + else if (progress <= 100) // intentional equality + { + admins = 2; + troops = 13 - difficultyMod * 3; + elites = difficultyMod * 3; + } + else // at least one recent interception at max progress + { + admins = 2; + troops = 18 - difficultyMod * 4; + elites = difficultyMod * 4; + } + + // add some vehicles, if possible + if (progress >= gGameExternalOptions.usJeepMinimumProgress) + { + if (elites > 0 && gGameExternalOptions.fASDAssignsJeeps && ASDSoldierUpgradeToJeep()) + { + jeeps++; + elites--; + } + } + + if (progress >= gGameExternalOptions.usTankMinimumProgress && Random(100) < (20 + difficultyMod * 10)) + { + if (elites > 0 && gGameExternalOptions.fASDAssignsTanks && ASDSoldierUpgradeToTank()) + { + tanks++; + elites--; + } + } + + if (progress >= gGameExternalOptions.usRobotMinimumProgress && Random(100) < (20 + difficultyMod * 10)) + { + const int numRobots = Random(difficultyMod + 1); + for (int i = 0; i < numRobots; ++i) + { + if (elites > 0 && gGameExternalOptions.fASDAssignsRobots && ASDSoldierUpgradeToRobot()) + { + robots++; + elites--; + } + } + } + } +} + diff --git a/Strategic/Strategic Transport Groups.h b/Strategic/Strategic Transport Groups.h index 3dbfdf8d3..fc491b093 100644 --- a/Strategic/Strategic Transport Groups.h +++ b/Strategic/Strategic Transport Groups.h @@ -7,7 +7,8 @@ struct GROUP; BOOLEAN DeployTransportGroup(); -BOOLEAN ReturnTransportGroup(INT32); +BOOLEAN ForceDeployTransportGroup(UINT8 sectorId); +BOOLEAN ReturnTransportGroup(INT32 groupId); void FillMapColoursForTransportGroups(INT32(&colorMap)[MAXIMUM_VALID_Y_COORDINATE][MAXIMUM_VALID_X_COORDINATE]); void ProcessTransportGroupReachedDestination(GROUP* pGroup); void UpdateTransportGroupInventory(); @@ -18,3 +19,4 @@ void ClearTransportGroupMap(); void NotifyTransportGroupDefeated(); #endif + From 2cb62f3483917a3068bab7212128acb7feac9e28 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Thu, 2 Mar 2023 00:50:33 -0800 Subject: [PATCH 47/81] Update valid destination check Fix manhattan distance check --- Strategic/Strategic Transport Groups.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index b8914c76b..6d52fe07f 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -77,7 +77,8 @@ BOOLEAN DeployTransportGroup() // skip towns that have no loyalty if (!gfTownUsesLoyalty[i]) continue; - // filter by TOWN ownership - expert/insane only + // filter by TOWN ownership - skip contested towns on expert/insane + if (IsTownUnderCompleteControlByPlayer(i)) continue; if ((difficulty == DIF_LEVEL_HARD || difficulty == DIF_LEVEL_INSANE) && IsTownUnderCompleteControlByEnemy(i) == FALSE) continue; // skip towns with a shut down mine @@ -86,7 +87,7 @@ BOOLEAN DeployTransportGroup() if (IsMineShutDown(mineIndex) == TRUE) continue; // filter by MINE ownership - for novice/experienced, as hard/insane would have ignored this town above - const INT16 mineSector = GetMineSectorForTown(i); + const INT16 mineSector = STRATEGIC_INDEX_TO_SECTOR_INFO(GetMineSectorForTown(i)); if (StrategicMap[mineSector].fEnemyControlled == FALSE) continue; mineSectorIds.push_back(mineSector); @@ -115,7 +116,6 @@ BOOLEAN DeployTransportGroup() // track recent transport group interceptions const INT8 recentLossCount = min(5, GetAllStrategicEventsOfType(EVENT_TRANSPORT_GROUP_DEFEATED).size()); - // copied from NPC_ACTION_SEND_SOLDIERS_TO_BATTLE_LOCATION, which happens after the first non-welcome wagon battle const UINT8 ubSectorID = (UINT8)mineSectorIds[Random(mineSectorIds.size())]; UINT8 admins, troops, elites, robots, jeeps, tanks; @@ -238,7 +238,7 @@ void FillMapColoursForTransportGroups(INT32(&colorMap)[MAXIMUM_VALID_Y_COORDINAT const std::pair sector = key.first; const INT8 range = key.second; - const INT8 dist = abs((gx - sector.first) + (gy - sector.second)); + const INT8 dist = abs((gx - sector.first)) + abs((gy - sector.second)); if (dist <= range) { colorMap[pGroup->ubSectorY-1][pGroup->ubSectorX-1] = targetColor; @@ -255,6 +255,13 @@ void FillMapColoursForTransportGroups(INT32(&colorMap)[MAXIMUM_VALID_Y_COORDINAT wp = wp->next; } + + if (wp == nullptr) + { + // ignore this group - it doesn't have a waypoint (?) + continue; + } + const UINT8 townId = GetTownIdForSector(wp->x, wp->y); if (monitoredTowns.find(townId) != monitoredTowns.end()) { From 4d9d42096b9a4d0d448b6862aadac1a96fbc1312 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Thu, 2 Mar 2023 01:00:19 -0800 Subject: [PATCH 48/81] Fix monitored town colouring --- Strategic/Strategic Transport Groups.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index 6d52fe07f..037b99544 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -195,7 +195,7 @@ void FillMapColoursForTransportGroups(INT32(&colorMap)[MAXIMUM_VALID_Y_COORDINAT { if( MercPtrs[ i ]->bActive && MercPtrs[ i ]->stats.bLife >= OKLIFE && - MercPtrs[ i ]->bAssignment < ON_DUTY && + (MercPtrs[ i ]->bAssignment < ON_DUTY || MercPtrs[ i ]->bAssignment == GATHERINTEL) && !MercPtrs[ i ]->flags.fMercAsleep) { if (gGameOptions.fNewTraitSystem) @@ -281,7 +281,7 @@ void FillMapColoursForTransportGroups(INT32(&colorMap)[MAXIMUM_VALID_Y_COORDINAT const UINT8 townId = GetTownIdForSector(x, y); if (monitoredTowns.find(townId) != monitoredTowns.end() && monitoredTowns[townId]) { - colorMap[x-1][y-1] = targetColor; + colorMap[y-1][x-1] = targetColor; } } } From 012789cb6c77cebe18cb9b00c5b9b403e4976843 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Fri, 3 Mar 2023 00:34:41 -0800 Subject: [PATCH 49/81] Add transport group to quest/intel strategic view --- Strategic/Map Screen Interface Map.cpp | 19 +++++++++++++++++++ Strategic/Strategic Transport Groups.cpp | 9 +++++++++ Strategic/Strategic Transport Groups.h | 9 +++++++++ 3 files changed, 37 insertions(+) diff --git a/Strategic/Map Screen Interface Map.cpp b/Strategic/Map Screen Interface Map.cpp index 99e334fbb..0be554827 100644 --- a/Strategic/Map Screen Interface Map.cpp +++ b/Strategic/Map Screen Interface Map.cpp @@ -8587,6 +8587,25 @@ void DetermineMapIntelData( INT32 asSectorZ ) } } + // transport groups + std::map map = GetTransportGroupSectorInfo(); + for (const auto iter : map) + { + CHAR16 str[128]; + + switch (iter.second) + { + case TransportGroupSectorInfo::TransportGroupSectorInfo_LocatedGroup: + swprintf( str, L"Transport group"); + break; + + case TransportGroupSectorInfo::TransportGroupSectorInfo_LocatedDestination: + swprintf( str, L"Transport group en route"); + break; + } + AddIntelAndQuestMapDataForSector( SECTORX(iter.first), SECTORY(iter.first), MAP_SHADE_LT_YELLOW, -1, str, L"" ); + } + // uncovered terrorists we know of for ( int cnt = 0; cnt < 6; ++cnt ) { diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index 037b99544..17768b029 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -57,6 +57,7 @@ extern BOOLEAN gfTownUsesLoyalty[MAX_TOWNS]; //extern STRATEGIC_STATUS gStrategicStatus; std::map> transportGroupIdToSoldierMap; +std::map transportGroupSectorInfo; void PopulateTransportGroup(UINT8& admins, UINT8& troops, UINT8& elites, UINT8& jeeps, UINT8& tanks, UINT8& robots, UINT8 progress, int difficulty, BOOLEAN trySpecialCase); @@ -117,6 +118,7 @@ BOOLEAN DeployTransportGroup() const INT8 recentLossCount = min(5, GetAllStrategicEventsOfType(EVENT_TRANSPORT_GROUP_DEFEATED).size()); const UINT8 ubSectorID = (UINT8)mineSectorIds[Random(mineSectorIds.size())]; + ScreenMsg(FONT_RED, MSG_INTERFACE, L"DeployTransportGroup sending group to sectorId: %d (%d/%d)", ubSectorID, SECTORX(ubSectorID), SECTORY(ubSectorID)); UINT8 admins, troops, elites, robots, jeeps, tanks; const UINT8 progress = min(125, HighestPlayerProgressPercentage() + recentLossCount * 5); @@ -187,6 +189,7 @@ void FillMapColoursForTransportGroups(INT32(&colorMap)[MAXIMUM_VALID_Y_COORDINAT const INT8 DETECTION_RANGE_RADIO = 3; const INT8 DETECTION_RANGE_COVERT = 0; GROUP* pGroup = gpGroupList; + transportGroupSectorInfo.clear(); // build map of detection sectors + ranges std::map, INT8> detectionMap; @@ -242,6 +245,7 @@ void FillMapColoursForTransportGroups(INT32(&colorMap)[MAXIMUM_VALID_Y_COORDINAT if (dist <= range) { colorMap[pGroup->ubSectorY-1][pGroup->ubSectorX-1] = targetColor; + transportGroupSectorInfo[SECTOR(pGroup->ubSectorX, pGroup->ubSectorY)] = TransportGroupSectorInfo::TransportGroupSectorInfo_LocatedGroup; } } @@ -282,6 +286,7 @@ void FillMapColoursForTransportGroups(INT32(&colorMap)[MAXIMUM_VALID_Y_COORDINAT if (monitoredTowns.find(townId) != monitoredTowns.end() && monitoredTowns[townId]) { colorMap[y-1][x-1] = targetColor; + transportGroupSectorInfo[SECTOR(x, y)] = TransportGroupSectorInfo::TransportGroupSectorInfo_LocatedDestination; } } } @@ -864,3 +869,7 @@ void PopulateTransportGroup(UINT8& admins, UINT8& troops, UINT8& elites, UINT8& } } +const std::map GetTransportGroupSectorInfo() +{ + return transportGroupSectorInfo; +} diff --git a/Strategic/Strategic Transport Groups.h b/Strategic/Strategic Transport Groups.h index fc491b093..3fd873c54 100644 --- a/Strategic/Strategic Transport Groups.h +++ b/Strategic/Strategic Transport Groups.h @@ -3,6 +3,13 @@ #include "Campaign Types.h" #include "Types.h" +#include + +enum TransportGroupSectorInfo +{ + TransportGroupSectorInfo_LocatedGroup = 0, + TransportGroupSectorInfo_LocatedDestination, +}; struct GROUP; @@ -13,6 +20,8 @@ void FillMapColoursForTransportGroups(INT32(&colorMap)[MAXIMUM_VALID_Y_COORDINAT void ProcessTransportGroupReachedDestination(GROUP* pGroup); void UpdateTransportGroupInventory(); +const std::map GetTransportGroupSectorInfo(); + void AddToTransportGroupMap(UINT8 groupId, int soldierClass, UINT8 amount); void ClearTransportGroupMap(); From f89f5f9eb54fd9dcb1b8c2be5540e62dcfc0d179 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Sat, 4 Mar 2023 00:39:04 -0800 Subject: [PATCH 50/81] Turncoats in towns can detect incoming transport groups --- Strategic/Strategic Transport Groups.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index 17768b029..5fee0c967 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -42,6 +42,7 @@ TODO LIST: #include "message.h" #include "Overhead.h" #include "Overhead Types.h" +#include "Queen Command.h" #include "random.h" #include "Soldier Control.h" #include "strategic.h" @@ -180,9 +181,6 @@ void FillMapColoursForTransportGroups(INT32(&colorMap)[MAXIMUM_VALID_Y_COORDINAT if (gGameExternalOptions.fStrategicTransportGroupsEnabled == FALSE) return; - // spies identify incoming transport groups - // RIS identifies ALL transport groups in monitored areas? in all areas? - const auto debugColor = MAP_SHADE_LT_BLUE; const auto targetColor = MAP_SHADE_LT_YELLOW; const INT8 DETECTION_RANGE_SCOUT = 1; @@ -223,6 +221,21 @@ void FillMapColoursForTransportGroups(INT32(&colorMap)[MAXIMUM_VALID_Y_COORDINAT } } + // turncoats in towns can detect incoming transport groups + for (int x = MINIMUM_VALID_X_COORDINATE; x <= MAXIMUM_VALID_X_COORDINATE; ++x) + { + for (int y = MINIMUM_VALID_Y_COORDINATE; y <= MAXIMUM_VALID_Y_COORDINATE; ++y) + { + const UINT8 townId = GetTownIdForSector(x, y); + if (townId < 0) continue; + + CorrectTurncoatCount(x, y); + const UINT16 numTurncoats = NumTurncoatsOfClassInSector(x, y, SOLDIER_CLASS_ADMINISTRATOR) + NumTurncoatsOfClassInSector(x, y, SOLDIER_CLASS_ARMY) + NumTurncoatsOfClassInSector(x, y, SOLDIER_CLASS_ELITE); + + monitoredTowns[townId] = FALSE; + } + } + while (pGroup) { if (pGroup->usGroupTeam == ENEMY_TEAM) From 2d359c188275dc205b2a2efd0c64c11d968d0c6e Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Sat, 4 Mar 2023 00:39:57 -0800 Subject: [PATCH 51/81] update todo list --- Strategic/Strategic Transport Groups.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index 5fee0c967..5510df050 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -17,16 +17,8 @@ Transport group compositions will vary based on the player's progress, how many and the difficulty of the game. TODO LIST: -- determine how/when/what groups are deployed - use proper loyalty degradation (Strategic Loyalty lua) (maybe...) - use enemygunchoices and enemyitemchoices to populate bonus loot, depending on jeep or no jeep -- track previous failed transports? transport group alertness level? partially degrades over time? - - we can use strategic status (gStrategicStatus. there's tons of unused padding). that way we don't need to muck with savegames, - as the bytes are already there. - - what do we actually want to track? - - alertness level (affects group compositions) - - recent losses (strategic events?) (affects group compositions) - - groups should track their own "readiness level" (ie, strategic stats when they were spawned) (could use the padding in GROUP->ENEMYGROUP) */ #include "Strategic Transport Groups.h" From 4eb266aee273e0651855b6869949e87d10a6efa6 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Mon, 6 Mar 2023 01:16:50 -0800 Subject: [PATCH 52/81] Add loot to foot soldiers --- Strategic/Strategic Transport Groups.cpp | 105 ++++++++++++++++------- 1 file changed, 72 insertions(+), 33 deletions(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index 5510df050..15a0be704 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -405,10 +405,10 @@ void UpdateTransportGroupInventory() MISC, GRENADE_THROWN, GUNS, + AMMO_BOXES, GRENADELAUNCHERS, ROCKETLAUNCHERS, - AMMO_BOXES, - AMMO_CRATES, + TRANSPORT_LOOT_START = GAS_CANS, TRANSPORT_LOOT_END = ROCKETLAUNCHERS, @@ -417,7 +417,6 @@ void UpdateTransportGroupInventory() std::map> itemMap; std::map> ammoBoxes; // map coolness to ammo vector - std::map> ammoCrates; // map coolness to ammo vector // rftr todo: instead of building ammo caches, perhaps we could examine ChooseWeaponForSoldierCreateStruct(). excerpt: // usAmmoIndex = RandomMagazine( &pp->Inv[HANDPOS], ubChanceStandardAmmo, max(Item[usGunIndex].ubCoolness, HighestPlayerProgressPercentage() / 10 + 3 ), pp->ubSoldierClass); @@ -425,10 +424,25 @@ void UpdateTransportGroupInventory() // for conversion, see the following (ammo conversion in strategic inventory) // void SortSectorInventoryAmmo(bool useBoxes) - // one-time item cache build + // item cache build { - //gExtendedArmyGunChoices[SOLDIER_CLASS_ELITE][gunLevel]; - //gArmyItemChoices[SOLDIER_CLASS_ELITE][typeIndex]; + // let's be nice to the player and only drop ammo for guns their mercs have in inventory + std::set playerCalibres; + for (INT16 i = gTacticalStatus.Team[OUR_TEAM].bFirstID; i <= gTacticalStatus.Team[OUR_TEAM].bLastID; i++) + { + if (MercPtrs[i]->bActive && !(MercPtrs[i]->flags.uiStatusFlags & SOLDIER_VEHICLE)) + { + for (int j = 0 ; MercPtrs[i]->inv.size(); ++j) + { + OBJECTTYPE& obj = MercPtrs[i]->inv[j]; + if (obj.exists() + && Item[obj.usItem].usItemClass == IC_GUN) + { + playerCalibres.insert(Weapon[Item[obj.usItem].ubClassIndex].ubCalibre); + } + } + } + } for (UINT16 i = 0; i < gMAXITEMS_READ; ++i) { @@ -464,16 +478,13 @@ void UpdateTransportGroupInventory() } else if (Item[i].usItemClass & IC_AMMO) { - if (Magazine[Item[i].ubClassIndex].ubMagType == AMMO_BOX - || Magazine[Item[i].ubClassIndex].ubMagType == AMMO_CRATE) + if (Magazine[Item[i].ubClassIndex].ubMagType == AMMO_BOX && playerCalibres.find(Magazine[Item[i].ubClassIndex].ubCalibre) != playerCalibres.end()) { - if ((gGameOptions.fGunNut || !Item[i].biggunlist) - && (gGameOptions.ubGameStyle == STYLE_SCIFI || !Item[i].scifi)) + ammoBoxes[Item[i].ubCoolness].push_back(i); + + if (Item[i].ubCoolness <= ((progress+5) / 10)+1) { - if (Magazine[Item[i].ubClassIndex].ubMagType == AMMO_BOX) - ammoBoxes[Item[i].ubCoolness].push_back(i); - else - ammoCrates[Item[i].ubCoolness].push_back(i); + itemMap[AMMO_BOXES].push_back(i); } } } @@ -552,7 +563,6 @@ void UpdateTransportGroupInventory() // but give a little extra, since the jeep exploding can outright destroy things if (pSoldier->ubSoldierClass == SOLDIER_CLASS_JEEP) { - OBJECTTYPE itemToAdd; //if (outgoing) { // en route to target destination - carrying ammo, supplies, etc @@ -630,6 +640,10 @@ void UpdateTransportGroupInventory() } break; + case AMMO_BOXES: + // intentionally do nothin' + break; + default: ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Warning: ignoring unhandled transport group loot type: %d", itemType); // nothing! @@ -649,7 +663,11 @@ void UpdateTransportGroupInventory() || pSoldier->ubSoldierClass == SOLDIER_CLASS_ARMY || pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE) { - // jeep is carrying everything, so just force inventory to be dropped! + // jeep is carrying most things, so soldiers just have ammo + const UINT16 ammoId = itemMap[AMMO_BOXES][Random(itemMap[AMMO_BOXES].size())]; + addItemToInventory(pSoldier, ammoId, 1); + + // force inventory to be dropped! for (int i = 0; i < pSoldier->inv.size(); ++i) { OBJECTTYPE* item = &pSoldier->inv[i]; @@ -673,26 +691,47 @@ void UpdateTransportGroupInventory() // there are still un-updated soldiers! begin the update! soldierClassIter->second--; - // rftr todo: move this into its own function - // rftr todo: don't forget to call this for reinforcing troops! - // adjust soldier inventory for transport groups + //if (outgoing) + { + for (int i = TRANSPORT_LOOT_START; i <= TRANSPORT_LOOT_END; ++i) + { + const ItemTypes itemType = static_cast(i); + if (itemMap[itemType].size() > 0) + { + const UINT16 id = itemMap[itemType][Random(itemMap[itemType].size())]; + switch (itemType) + { + case GAS_CANS: + case MEDICAL_MEDKITS: + case MEDICAL_OTHER: + case TOOL_KITS: + case GUNS: + case GRENADELAUNCHERS: + case ROCKETLAUNCHERS: + case GRENADE_THROWN: + case MISC: + // skip for foot soldiers! + break; + + case BACKPACKS: + addItemToInventory(pSoldier, id, 1); + break; - // ideas: - // soldiers have backpacks + kits + ammo box (BONUS: make sure the backpack goes in the backpack slot for lobot compatibility. that might be a fix outside of this feature tho) - // jeeps have ammo crates and/or lots of boxes. reduce bullet count in crate? + case MEDICAL_FIRSTAIDKITS: + addItemToInventory(pSoldier, id, 1); + break; - // add backpack to soldier's inventory! - OBJECTTYPE itemToAdd; - if (itemMap[BACKPACKS].size() > 0) - { - CreateItem(itemMap[BACKPACKS][0], 100, &itemToAdd); - pSoldier->inv[BPACKPOCKPOS] = itemToAdd; - } + case AMMO_BOXES: + addItemToInventory(pSoldier, id, 1); + break; - //if (outgoing) - { - // add ammo to the soldier's inventory! - addItemToInventory(pSoldier, ammoBoxes[10][0], 1); + default: + ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Warning: ignoring unhandled transport group loot type: %d", itemType); + // nothing! + break; + } + } + } } //else // returning home { From 8e061cc1c8163a5c0de973b9967b595007b4ca75 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Sat, 15 Apr 2023 23:59:06 -0700 Subject: [PATCH 53/81] Add camo kits to loot cache --- Strategic/Strategic Transport Groups.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index 15a0be704..a0354ccda 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -402,6 +402,7 @@ void UpdateTransportGroupInventory() TOOL_KITS, BACKPACKS, RADIOS, + CAMO_KITS, MISC, GRENADE_THROWN, GUNS, @@ -472,10 +473,8 @@ void UpdateTransportGroupInventory() itemMap[BACKPACKS].push_back(i); } } - else if (Item[i].usItemClass & IC_MISC) - { - itemMap[MISC].push_back(i); - } + else if (Item[i].camouflagekit) itemMap[CAMO_KITS].push_back(i); + else if (Item[i].usItemClass & IC_MISC) itemMap[MISC].push_back(i); else if (Item[i].usItemClass & IC_AMMO) { if (Magazine[Item[i].ubClassIndex].ubMagType == AMMO_BOX && playerCalibres.find(Magazine[Item[i].ubClassIndex].ubCalibre) != playerCalibres.end()) From dccfcdfceadb455d5bd53494d6bb21bbf64d9655 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Sun, 16 Apr 2023 00:26:50 -0700 Subject: [PATCH 54/81] Add attachments to loot cache --- Strategic/Strategic Transport Groups.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index a0354ccda..4fe11c287 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -402,6 +402,7 @@ void UpdateTransportGroupInventory() TOOL_KITS, BACKPACKS, RADIOS, + ATTACHMENTS, CAMO_KITS, MISC, GRENADE_THROWN, @@ -474,7 +475,23 @@ void UpdateTransportGroupInventory() } } else if (Item[i].camouflagekit) itemMap[CAMO_KITS].push_back(i); - else if (Item[i].usItemClass & IC_MISC) itemMap[MISC].push_back(i); + else if (Item[i].usItemClass & IC_MISC) + { + switch (Item[i].attachmentclass) + { + case AC_BIPOD: + case AC_MUZZLE: + case AC_LASER: + case AC_SIGHT: + case AC_SCOPE: + case AC_FOREGRIP: + itemMap[ATTACHMENTS].push_back(i); + break; + default: + itemMap[MISC].push_back(i); + break; + } + } else if (Item[i].usItemClass & IC_AMMO) { if (Magazine[Item[i].ubClassIndex].ubMagType == AMMO_BOX && playerCalibres.find(Magazine[Item[i].ubClassIndex].ubCalibre) != playerCalibres.end()) From 2049a080be9f3bc342bc94f8c045ffd6eda3d706 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Mon, 17 Apr 2023 00:28:02 -0700 Subject: [PATCH 55/81] Add camo kits and attachments to jeep/soldier drop logic --- Strategic/Strategic Transport Groups.cpp | 33 ++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index 4fe11c287..69ae56eb8 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -590,6 +590,17 @@ void UpdateTransportGroupInventory() const UINT16 id = itemMap[itemType][Random(itemMap[itemType].size())]; switch (itemType) { + case BACKPACKS: + case RADIOS: + case MISC: + case AMMO_BOXES: + // intentionally do nothing + break; + + case GAS_CANS: + addItemToInventory(pSoldier, id, 1); + break; + case MEDICAL_MEDKITS: case MEDICAL_OTHER: case TOOL_KITS: @@ -656,8 +667,16 @@ void UpdateTransportGroupInventory() } break; - case AMMO_BOXES: - // intentionally do nothin' + case ATTACHMENTS: + for (int loop = 0; loop < 5; ++loop) + { + const UINT16 attachmentId = itemMap[itemType][Random(itemMap[itemType].size())]; + addItemToInventory(pSoldier, attachmentId, 2); + } + break; + + case CAMO_KITS: + addItemToInventory(pSoldier, id, 6); break; default: @@ -741,6 +760,16 @@ void UpdateTransportGroupInventory() addItemToInventory(pSoldier, id, 1); break; + case CAMO_KITS: + addItemToInventory(pSoldier, id, 1); + break; + + case ATTACHMENTS: + // low chance of attachments + if (Random(100) < 25) + addItemToInventory(pSoldier, id, 1); + break; + default: ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Warning: ignoring unhandled transport group loot type: %d", itemType); // nothing! From 7f14d16cf0eba685d46516fb601acacdd176b5a1 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Sun, 23 Apr 2023 14:28:56 -0700 Subject: [PATCH 56/81] Screw it we'll have the same loot for incoming and outgoing groups. Updated comments --- Strategic/Strategic Transport Groups.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index 69ae56eb8..6125e440a 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -689,7 +689,8 @@ void UpdateTransportGroupInventory() } //else // returning home { - // coming back home - carrying money/loot/??? + // I can't really think of a good different loot set for returning transport groups, so we'll have the same loot + // regardless of whether the group is outgoing or incoming. I'll keep the in/out flag in case that changes } transportGroupIdToSoldierMap[pSoldier->ubGroupID][SOLDIER_CLASS_JEEP]--; @@ -780,7 +781,8 @@ void UpdateTransportGroupInventory() } //else // returning home { - // coming back home - carrying money/loot/??? + // I can't really think of a good different loot set for returning transport groups, so we'll have the same loot + // regardless of whether the group is outgoing or incoming. I'll keep the in/out flag in case that changes } // force inventory to be dropped! From 6cc451c690292ba267ca45b0c59191b0a60f0c23 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Thu, 25 May 2023 21:21:02 -0700 Subject: [PATCH 57/81] Add transport group debug flag --- GameSettings.cpp | 1 + GameSettings.h | 1 + Strategic/Strategic Transport Groups.cpp | 25 ++++++++++++++++-------- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/GameSettings.cpp b/GameSettings.cpp index bb2b88e3e..38acc5161 100644 --- a/GameSettings.cpp +++ b/GameSettings.cpp @@ -2161,6 +2161,7 @@ void LoadGameExternalOptions() gGameExternalOptions.fAlternativeHelicopterFuelSystem = iniReader.ReadBoolean("Strategic Gameplay Settings","ALTERNATIVE_HELICOPTER_FUEL_SYSTEM", TRUE); gGameExternalOptions.fHelicopterPassengersCanGetHit = iniReader.ReadBoolean("Strategic Gameplay Settings","HELICOPTER_PASSENGERS_CAN_GET_HIT", TRUE); + gGameExternalOptions.fStrategicTransportGroupsDebug = iniReader.ReadBoolean("Strategic Gameplay Settings", "STRATEGIC_TRANSPORT_GROUPS_DEBUG", FALSE, FALSE); gGameExternalOptions.fStrategicTransportGroupsEnabled = iniReader.ReadBoolean("Strategic Gameplay Settings", "STRATEGIC_TRANSPORT_GROUPS_ENABLED", FALSE); gGameExternalOptions.iMaxSimultaneousTransportGroups = iniReader.ReadInteger("Strategic Gameplay Settings", "MAX_SIMULTANEOUS_STRATEGIC_TRANSPORT_GROUPS", 5, 1, 10); diff --git a/GameSettings.h b/GameSettings.h index 097315e62..13bc6f6d6 100644 --- a/GameSettings.h +++ b/GameSettings.h @@ -1602,6 +1602,7 @@ typedef struct BOOLEAN fAlternativeHelicopterFuelSystem; BOOLEAN fHelicopterPassengersCanGetHit; + BOOLEAN fStrategicTransportGroupsDebug; BOOLEAN fStrategicTransportGroupsEnabled; INT8 iMaxSimultaneousTransportGroups; diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index 6125e440a..ba71ea8b7 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -86,7 +86,9 @@ BOOLEAN DeployTransportGroup() mineSectorIds.push_back(mineSector); } - ScreenMsg(FONT_RED, MSG_INTERFACE, L"DeployTransportGroup valid town destinations: %d", mineSectorIds.size()); + + if (gGameExternalOptions.fStrategicTransportGroupsDebug) + ScreenMsg(FONT_RED, MSG_INTERFACE, L"DeployTransportGroup valid town destinations: %d", mineSectorIds.size()); // no valid destinations if (mineSectorIds.size() == 0) return FALSE; @@ -101,7 +103,9 @@ BOOLEAN DeployTransportGroup() } pGroup = pGroup->next; } - ScreenMsg(FONT_RED, MSG_INTERFACE, L"DeployTransportGroup found existing transport groups: %d", transportGroupCount); + + if (gGameExternalOptions.fStrategicTransportGroupsDebug) + ScreenMsg(FONT_RED, MSG_INTERFACE, L"DeployTransportGroup found existing transport groups: %d", transportGroupCount); // if there are too many active transport groups, don't deploy any more // maximum number of active groups is the number of valid destinations at queen decision time @@ -111,7 +115,9 @@ BOOLEAN DeployTransportGroup() const INT8 recentLossCount = min(5, GetAllStrategicEventsOfType(EVENT_TRANSPORT_GROUP_DEFEATED).size()); const UINT8 ubSectorID = (UINT8)mineSectorIds[Random(mineSectorIds.size())]; - ScreenMsg(FONT_RED, MSG_INTERFACE, L"DeployTransportGroup sending group to sectorId: %d (%d/%d)", ubSectorID, SECTORX(ubSectorID), SECTORY(ubSectorID)); + + if (gGameExternalOptions.fStrategicTransportGroupsDebug) + ScreenMsg(FONT_RED, MSG_INTERFACE, L"DeployTransportGroup sending group to sectorId: %d (%d/%d)", ubSectorID, SECTORX(ubSectorID), SECTORY(ubSectorID)); UINT8 admins, troops, elites, robots, jeeps, tanks; const UINT8 progress = min(125, HighestPlayerProgressPercentage() + recentLossCount * 5); @@ -161,7 +167,8 @@ BOOLEAN ReturnTransportGroup(INT32 groupId) if (pGroup == nullptr) { - ScreenMsg( FONT_YELLOW, MSG_INTERFACE, L"RETURN_TRANSPORT_GROUP failed to find groupid %d", groupId); + if (gGameExternalOptions.fStrategicTransportGroupsDebug) + ScreenMsg( FONT_YELLOW, MSG_INTERFACE, L"RETURN_TRANSPORT_GROUP failed to find groupid %d", groupId); return FALSE; } @@ -235,8 +242,8 @@ void FillMapColoursForTransportGroups(INT32(&colorMap)[MAXIMUM_VALID_Y_COORDINAT const UINT8 intention = pGroup->pEnemyGroup->ubIntention; if (intention == TRANSPORT ) { - // rftr todo: delete me! - colorMap[pGroup->ubSectorY-1][pGroup->ubSectorX-1] = debugColor; + if (gGameExternalOptions.fStrategicTransportGroupsDebug) + colorMap[pGroup->ubSectorY-1][pGroup->ubSectorX-1] = debugColor; // check if current location is known const INT16 gx = pGroup->ubSectorX; @@ -680,7 +687,8 @@ void UpdateTransportGroupInventory() break; default: - ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Warning: ignoring unhandled transport group loot type: %d", itemType); + if (gGameExternalOptions.fStrategicTransportGroupsDebug) + ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Warning: ignoring unhandled transport group loot type: %d", itemType); // nothing! break; } @@ -772,7 +780,8 @@ void UpdateTransportGroupInventory() break; default: - ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Warning: ignoring unhandled transport group loot type: %d", itemType); + if (gGameExternalOptions.fStrategicTransportGroupsDebug) + ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Warning: ignoring unhandled transport group loot type: %d", itemType); // nothing! break; } From 044812ae50dca9b6e66040fa4a00a7bacddd539f Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Thu, 25 May 2023 21:39:49 -0700 Subject: [PATCH 58/81] Add transport groups to feature toggles menu --- GameSettings.cpp | 3 +++ GameSettings.h | 1 + Utils/_ChineseText.cpp | 3 +++ Utils/_DutchText.cpp | 3 +++ Utils/_EnglishText.cpp | 3 +++ Utils/_FrenchText.cpp | 3 +++ Utils/_GermanText.cpp | 3 +++ Utils/_ItalianText.cpp | 3 +++ Utils/_PolishText.cpp | 3 +++ Utils/_RussianText.cpp | 3 +++ 10 files changed, 28 insertions(+) diff --git a/GameSettings.cpp b/GameSettings.cpp index 38acc5161..881a3c944 100644 --- a/GameSettings.cpp +++ b/GameSettings.cpp @@ -248,6 +248,7 @@ void UpdateFeatureFlags() gGameExternalOptions.gfAllowSnow = gGameSettings.fFeatures[FF_ALLOW_SNOW]; gGameExternalOptions.fMiniEventsEnabled = gGameSettings.fFeatures[FF_MINI_EVENTS]; gGameExternalOptions.fRebelCommandEnabled = gGameSettings.fFeatures[FF_REBEL_COMMAND]; + gGameExternalOptions.fStrategicTransportGroupsEnabled = gGameSettings.fFeatures[FF_STRATEGIC_TRANSPORT_GROUPS]; } else { @@ -497,6 +498,7 @@ BOOLEAN LoadFeatureFlags() gGameSettings.fFeatures[FF_ALLOW_SNOW] = iniReader.ReadBoolean("JA2 Feature Flags", "FF_ALLOW_SNOW", TRUE, FALSE); gGameSettings.fFeatures[FF_MINI_EVENTS] = iniReader.ReadBoolean("JA2 Feature Flags", "FF_MINI_EVENTS", FALSE, FALSE); gGameSettings.fFeatures[FF_REBEL_COMMAND] = iniReader.ReadBoolean("JA2 Feature Flags", "FF_REBEL_COMMAND", FALSE, FALSE); + gGameSettings.fFeatures[FF_STRATEGIC_TRANSPORT_GROUPS] = iniReader.ReadBoolean("JA2 Feature Flags", "FF_STRATEGIC_TRANSPORT_GROUPS", FALSE, FALSE); } } catch(vfs::Exception) @@ -725,6 +727,7 @@ BOOLEAN SaveFeatureFlags() settings << "FF_ALLOW_SNOW = " << (gGameSettings.fFeatures[FF_ALLOW_SNOW] ? "TRUE" : "FALSE") << endl; settings << "FF_MINI_EVENTS = " << (gGameSettings.fFeatures[FF_MINI_EVENTS] ? "TRUE" : "FALSE") << endl; settings << "FF_REBEL_COMMAND = " << (gGameSettings.fFeatures[FF_REBEL_COMMAND] ? "TRUE" : "FALSE") << endl; + settings << "FF_STRATEGIC_TRANSPORT_GROUPS = " << (gGameSettings.fFeatures[FF_STRATEGIC_TRANSPORT_GROUPS] ? "TRUE" : "FALSE") << endl; try { diff --git a/GameSettings.h b/GameSettings.h index 13bc6f6d6..8ca4097e3 100644 --- a/GameSettings.h +++ b/GameSettings.h @@ -181,6 +181,7 @@ enum FF_ALLOW_SNOW, FF_MINI_EVENTS, FF_REBEL_COMMAND, + FF_STRATEGIC_TRANSPORT_GROUPS, NUM_FEATURE_FLAGS, }; diff --git a/Utils/_ChineseText.cpp b/Utils/_ChineseText.cpp index c96be0ed0..c928069ef 100644 --- a/Utils/_ChineseText.cpp +++ b/Utils/_ChineseText.cpp @@ -6262,6 +6262,7 @@ STR16 z113FeaturesToggleText[] = L"天气功能:暴风雪", //L"Weather: Snow", L"随机事件功能", //L"Mini Events", L"反抗军司令部功能", //L"Arulco Rebel Command", + L"Strategic Transport Groups", }; STR16 z113FeaturesHelpText[] = @@ -6309,6 +6310,7 @@ STR16 z113FeaturesHelpText[] = L"|天|气|功|能|:|暴|风|雪\n \n覆盖 [Tactical Weather Settings] ALLOW_SNOW\n \n暴风雪降低了能见度。\n \n配置选项:\nSNOW_EVENTS_PER_DAY\nSNOW_CHANCE_PER_DAY\nSNOW_MIN_LENGTH_IN_MINUTES\nSNOW_MAX_LENGTH_IN_MINUTES\nWEAPON_RELIABILITY_REDUCTION_SNOW\nBREATH_GAIN_REDUCTION_SNOW\nVISUAL_DISTANCE_DECREASE_SNOW\nHEARING_REDUCTION_SNOW\n \n", //L"|W|e|a|t|h|e|r|: |S|n|o|w\nOverrides [Tactical Weather Settings] ALLOW_SNOW\n \nSnowstorms decrease visibility.\n \nConfigurable Options:\nSNOW_EVENTS_PER_DAY\nSNOW_CHANCE_PER_DAY\nSNOW_MIN_LENGTH_IN_MINUTES\nSNOW_MAX_LENGTH_IN_MINUTES\nWEAPON_RELIABILITY_REDUCTION_SNOW\nBREATH_GAIN_REDUCTION_SNOW\nVISUAL_DISTANCE_DECREASE_SNOW\nHEARING_REDUCTION_SNOW", L"|随|机|事|件|功|能\n \n覆盖 [Mini Events Settings] MINI_EVENTS_ENABLED\n \n可能发生一些随机互动事件。\n \n配置选项:\nMINI_EVENTS_MIN_HOURS_BETWEEN_EVENTS\nMINI_EVENTS_MAX_HOURS_BETWEEN_EVENTS\n \n详细信息请查看MiniEvents.lua。\n \n", //L"|M|i|n|i |E|v|e|n|t|s\nOverrides [Mini Events Settings] MINI_EVENTS_ENABLED\n \nRandom events can occur.\n \nConfigurable Options:\nMINI_EVENTS_MIN_HOURS_BETWEEN_EVENTS\nMINI_EVENTS_MAX_HOURS_BETWEEN_EVENTS\n \nSee MiniEvents.lua for more details.", L"|反|抗|军|司|令|部|功|能\n \n覆盖 [Rebel Command Settings] REBEL_COMMAND_ENABLED\n \n允许你升级占领的城镇,控制反抗军在战略层面上运作。\n \n详细的内容设定请查看RebelCommand_Settings.ini。\n \n", //L"|A|R|C\nOverrides [Rebel Command Settings] REBEL_COMMAND_ENABLED\n \nCommand the rebel movement at the strategic level, and upgrade captured towns.\n \nFor tweakable values, see RebelCommand_Settings.ini.", + L"|S|t|r|a|t|e|g|i|c |T|r|a|n|s|p|o|r|t |G|r|o|u|p|s\nOverrides [Strategic Gameplay Settings] STRATEGIC_TRANSPORT_GROUPS_ENABLED\n \nTransport groups carry valuable equipment across the map.\n \nConfigurable Options:\nMAX_SIMULTANEOUS_STRATEGIC_TRANSPORT_GROUPS", }; STR16 z113FeaturesPanelText[] = @@ -6356,6 +6358,7 @@ STR16 z113FeaturesPanelText[] = L"启用暴风雪功能。在暴风雪中,更难被看到,武器退化更快,呼吸也更困难。", //L"Toggle snow. In a snowstorm, it is harder to see, weapons degrade faster, and it is a little harder to regain breath.", L"在游戏过程中,可能会弹出简短的事件。您可以从两个选项中选择一个,这可能会产生积极或消极的影响。事件可以影响各种各样的事情,但主要是你的佣兵。", //L"During the course of a campaign, brief events can pop up. You can select one of two responses, which may have positive and/or negative effects. Events can affect a wide variety of things, but mostly your mercs.", L"在完成反抗军食物运送任务后,你可以访问他们的(A.R.C)指挥部网站。在这里你可以设定反抗军的政策,也可以为占领区单独设置地方政策。这将带来丰厚的奖励。作为代价,城镇的民忠会上升得更慢,所以你需要更加努力地让当地人信任你。", //L"After completing the food delivery quest for the rebels, they will grant you access to their command website (A.R.C.). You can set the rebels' country-wide directive there, and capturing towns allows you to enact policies in that region that provide powerful bonuses. This comes at a price - town loyalty will rise slower, so you will need to work harder to have the locals trust you.", + L"The enemy sends groups across the map. If you can find and intercept them, they will probably have valuable gear. However, depending on your difficulty, each group that completes its transport mission provides the AI with strategic resources. Best experienced with Arulco Strategic Division enabled.", }; diff --git a/Utils/_DutchText.cpp b/Utils/_DutchText.cpp index 2a14d22fd..82f93e9d4 100644 --- a/Utils/_DutchText.cpp +++ b/Utils/_DutchText.cpp @@ -6265,6 +6265,7 @@ STR16 z113FeaturesToggleText[] = L"Weather: Snow", L"Mini Events", L"Arulco Rebel Command", + L"Strategic Transport Groups", }; STR16 z113FeaturesHelpText[] = @@ -6312,6 +6313,7 @@ STR16 z113FeaturesHelpText[] = L"|W|e|a|t|h|e|r|: |S|n|o|w\nOverrides [Tactical Weather Settings] ALLOW_SNOW\n \nSnowstorms decrease visibility.\n \nConfigurable Options:\nSNOW_EVENTS_PER_DAY\nSNOW_CHANCE_PER_DAY\nSNOW_MIN_LENGTH_IN_MINUTES\nSNOW_MAX_LENGTH_IN_MINUTES\nWEAPON_RELIABILITY_REDUCTION_SNOW\nBREATH_GAIN_REDUCTION_SNOW\nVISUAL_DISTANCE_DECREASE_SNOW\nHEARING_REDUCTION_SNOW", L"|M|i|n|i |E|v|e|n|t|s\nOverrides [Mini Events Settings] MINI_EVENTS_ENABLED\n \nRandom events can occur.\n \nConfigurable Options:\nMINI_EVENTS_MIN_HOURS_BETWEEN_EVENTS\nMINI_EVENTS_MAX_HOURS_BETWEEN_EVENTS\n \nSee MiniEvents.lua for more details.", L"|A|R|C\nOverrides [Rebel Command Settings] REBEL_COMMAND_ENABLED\n \nCommand the rebel movement at the strategic level, and upgrade captured towns.\n \nFor tweakable values, see RebelCommand_Settings.ini.", + L"|S|t|r|a|t|e|g|i|c |T|r|a|n|s|p|o|r|t |G|r|o|u|p|s\nOverrides [Strategic Gameplay Settings] STRATEGIC_TRANSPORT_GROUPS_ENABLED\n \nTransport groups carry valuable equipment across the map.\n \nConfigurable Options:\nMAX_SIMULTANEOUS_STRATEGIC_TRANSPORT_GROUPS", }; STR16 z113FeaturesPanelText[] = @@ -6359,6 +6361,7 @@ STR16 z113FeaturesPanelText[] = L"Toggle snow. In a snowstorm, it is harder to see, weapons degrade faster, and it is a little harder to regain breath.", L"During the course of a campaign, brief events can pop up. You can select one of two responses, which may have positive and/or negative effects. Events can affect a wide variety of things, but mostly your mercs.", L"After completing the food delivery quest for the rebels, they will grant you access to their command website (A.R.C.). You can set the rebels' country-wide directive there, and capturing towns allows you to enact policies in that region that provide powerful bonuses. This comes at a price - town loyalty will rise slower, so you will need to work harder to have the locals trust you.", + L"The enemy sends groups across the map. If you can find and intercept them, they will probably have valuable gear. However, depending on your difficulty, each group that completes its transport mission provides the AI with strategic resources. Best experienced with Arulco Strategic Division enabled.", }; diff --git a/Utils/_EnglishText.cpp b/Utils/_EnglishText.cpp index da9b0e9cc..858246c17 100644 --- a/Utils/_EnglishText.cpp +++ b/Utils/_EnglishText.cpp @@ -6262,6 +6262,7 @@ STR16 z113FeaturesToggleText[] = L"Weather: Snow", L"Mini Events", L"Arulco Rebel Command", + L"Strategic Transport Groups", }; STR16 z113FeaturesHelpText[] = @@ -6309,6 +6310,7 @@ STR16 z113FeaturesHelpText[] = L"|W|e|a|t|h|e|r|: |S|n|o|w\nOverrides [Tactical Weather Settings] ALLOW_SNOW\n \nSnowstorms decrease visibility.\n \nConfigurable Options:\nSNOW_EVENTS_PER_DAY\nSNOW_CHANCE_PER_DAY\nSNOW_MIN_LENGTH_IN_MINUTES\nSNOW_MAX_LENGTH_IN_MINUTES\nWEAPON_RELIABILITY_REDUCTION_SNOW\nBREATH_GAIN_REDUCTION_SNOW\nVISUAL_DISTANCE_DECREASE_SNOW\nHEARING_REDUCTION_SNOW", L"|M|i|n|i |E|v|e|n|t|s\nOverrides [Mini Events Settings] MINI_EVENTS_ENABLED\n \nRandom events can occur.\n \nConfigurable Options:\nMINI_EVENTS_MIN_HOURS_BETWEEN_EVENTS\nMINI_EVENTS_MAX_HOURS_BETWEEN_EVENTS\n \nSee MiniEvents.lua for more details.", L"|A|R|C\nOverrides [Rebel Command Settings] REBEL_COMMAND_ENABLED\n \nCommand the rebel movement at the strategic level, and upgrade captured towns.\n \nFor tweakable values, see RebelCommand_Settings.ini.", + L"|S|t|r|a|t|e|g|i|c |T|r|a|n|s|p|o|r|t |G|r|o|u|p|s\nOverrides [Strategic Gameplay Settings] STRATEGIC_TRANSPORT_GROUPS_ENABLED\n \nTransport groups carry valuable equipment across the map.\n \nConfigurable Options:\nMAX_SIMULTANEOUS_STRATEGIC_TRANSPORT_GROUPS", }; STR16 z113FeaturesPanelText[] = @@ -6356,6 +6358,7 @@ STR16 z113FeaturesPanelText[] = L"Toggle snow. In a snowstorm, it is harder to see, weapons degrade faster, and it is a little harder to regain breath.", L"During the course of a campaign, brief events can pop up. You can select one of two responses, which may have positive and/or negative effects. Events can affect a wide variety of things, but mostly your mercs.", L"After completing the food delivery quest for the rebels, they will grant you access to their command website (A.R.C.). You can set the rebels' country-wide directive there, and capturing towns allows you to enact policies in that region that provide powerful bonuses. This comes at a price - town loyalty will rise slower, so you will need to work harder to have the locals trust you.", + L"The enemy sends groups across the map. If you can find and intercept them, they will probably have valuable gear. However, depending on your difficulty, each group that completes its transport mission provides the AI with strategic resources. Best experienced with Arulco Strategic Division enabled.", }; diff --git a/Utils/_FrenchText.cpp b/Utils/_FrenchText.cpp index a9b712084..64e771552 100644 --- a/Utils/_FrenchText.cpp +++ b/Utils/_FrenchText.cpp @@ -6270,6 +6270,7 @@ STR16 z113FeaturesToggleText[] = L"Weather: Snow", L"Mini Events", L"Arulco Rebel Command", + L"Strategic Transport Groups", }; STR16 z113FeaturesHelpText[] = @@ -6317,6 +6318,7 @@ STR16 z113FeaturesHelpText[] = L"|W|e|a|t|h|e|r|: |S|n|o|w\nOverrides [Tactical Weather Settings] ALLOW_SNOW\n \nSnowstorms decrease visibility.\n \nConfigurable Options:\nSNOW_EVENTS_PER_DAY\nSNOW_CHANCE_PER_DAY\nSNOW_MIN_LENGTH_IN_MINUTES\nSNOW_MAX_LENGTH_IN_MINUTES\nWEAPON_RELIABILITY_REDUCTION_SNOW\nBREATH_GAIN_REDUCTION_SNOW\nVISUAL_DISTANCE_DECREASE_SNOW\nHEARING_REDUCTION_SNOW", L"|M|i|n|i |E|v|e|n|t|s\nOverrides [Mini Events Settings] MINI_EVENTS_ENABLED\n \nRandom events can occur.\n \nConfigurable Options:\nMINI_EVENTS_MIN_HOURS_BETWEEN_EVENTS\nMINI_EVENTS_MAX_HOURS_BETWEEN_EVENTS\n \nSee MiniEvents.lua for more details.", L"|A|R|C\nOverrides [Rebel Command Settings] REBEL_COMMAND_ENABLED\n \nCommand the rebel movement at the strategic level, and upgrade captured towns.\n \nFor tweakable values, see RebelCommand_Settings.ini.", + L"|S|t|r|a|t|e|g|i|c |T|r|a|n|s|p|o|r|t |G|r|o|u|p|s\nOverrides [Strategic Gameplay Settings] STRATEGIC_TRANSPORT_GROUPS_ENABLED\n \nTransport groups carry valuable equipment across the map.\n \nConfigurable Options:\nMAX_SIMULTANEOUS_STRATEGIC_TRANSPORT_GROUPS", }; STR16 z113FeaturesPanelText[] = @@ -6364,6 +6366,7 @@ STR16 z113FeaturesPanelText[] = L"Toggle snow. In a snowstorm, it is harder to see, weapons degrade faster, and it is a little harder to regain breath.", L"During the course of a campaign, brief events can pop up. You can select one of two responses, which may have positive and/or negative effects. Events can affect a wide variety of things, but mostly your mercs.", L"After completing the food delivery quest for the rebels, they will grant you access to their command website (A.R.C.). You can set the rebels' country-wide directive there, and capturing towns allows you to enact policies in that region that provide powerful bonuses. This comes at a price - town loyalty will rise slower, so you will need to work harder to have the locals trust you.", + L"The enemy sends groups across the map. If you can find and intercept them, they will probably have valuable gear. However, depending on your difficulty, each group that completes its transport mission provides the AI with strategic resources. Best experienced with Arulco Strategic Division enabled.", }; diff --git a/Utils/_GermanText.cpp b/Utils/_GermanText.cpp index 61f5c42d6..9f66ec9ae 100644 --- a/Utils/_GermanText.cpp +++ b/Utils/_GermanText.cpp @@ -6133,6 +6133,7 @@ STR16 z113FeaturesToggleText[] = L"Weather: Snow", L"Mini Events", L"Arulco Rebel Command", + L"Strategic Transport Groups", }; STR16 z113FeaturesHelpText[] = @@ -6180,6 +6181,7 @@ STR16 z113FeaturesHelpText[] = L"|W|e|a|t|h|e|r|: |S|n|o|w\nOverrides [Tactical Weather Settings] ALLOW_SNOW\n \nSnowstorms decrease visibility.\n \nConfigurable Options:\nSNOW_EVENTS_PER_DAY\nSNOW_CHANCE_PER_DAY\nSNOW_MIN_LENGTH_IN_MINUTES\nSNOW_MAX_LENGTH_IN_MINUTES\nWEAPON_RELIABILITY_REDUCTION_SNOW\nBREATH_GAIN_REDUCTION_SNOW\nVISUAL_DISTANCE_DECREASE_SNOW\nHEARING_REDUCTION_SNOW", L"|M|i|n|i |E|v|e|n|t|s\nOverrides [Mini Events Settings] MINI_EVENTS_ENABLED\n \nRandom events can occur.\n \nConfigurable Options:\nMINI_EVENTS_MIN_HOURS_BETWEEN_EVENTS\nMINI_EVENTS_MAX_HOURS_BETWEEN_EVENTS\n \nSee MiniEvents.lua for more details.", L"|A|R|C\nOverrides [Rebel Command Settings] REBEL_COMMAND_ENABLED\n \nCommand the rebel movement at the strategic level, and upgrade captured towns.\n \nFor tweakable values, see RebelCommand_Settings.ini.", + L"|S|t|r|a|t|e|g|i|c |T|r|a|n|s|p|o|r|t |G|r|o|u|p|s\nOverrides [Strategic Gameplay Settings] STRATEGIC_TRANSPORT_GROUPS_ENABLED\n \nTransport groups carry valuable equipment across the map.\n \nConfigurable Options:\nMAX_SIMULTANEOUS_STRATEGIC_TRANSPORT_GROUPS", }; STR16 z113FeaturesPanelText[] = @@ -6227,6 +6229,7 @@ STR16 z113FeaturesPanelText[] = L"Toggle snow. In a snowstorm, it is harder to see, weapons degrade faster, and it is a little harder to regain breath.", L"During the course of a campaign, brief events can pop up. You can select one of two responses, which may have positive and/or negative effects. Events can affect a wide variety of things, but mostly your mercs.", L"After completing the food delivery quest for the rebels, they will grant you access to their command website (A.R.C.). You can set the rebels' country-wide directive there, and capturing towns allows you to enact policies in that region that provide powerful bonuses. This comes at a price - town loyalty will rise slower, so you will need to work harder to have the locals trust you.", + L"The enemy sends groups across the map. If you can find and intercept them, they will probably have valuable gear. However, depending on your difficulty, each group that completes its transport mission provides the AI with strategic resources. Best experienced with Arulco Strategic Division enabled.", }; diff --git a/Utils/_ItalianText.cpp b/Utils/_ItalianText.cpp index 48ba9f370..460ad5f0e 100644 --- a/Utils/_ItalianText.cpp +++ b/Utils/_ItalianText.cpp @@ -6251,6 +6251,7 @@ STR16 z113FeaturesToggleText[] = L"Weather: Snow", L"Mini Events", L"Arulco Rebel Command", + L"Strategic Transport Groups", }; STR16 z113FeaturesHelpText[] = @@ -6298,6 +6299,7 @@ STR16 z113FeaturesHelpText[] = L"|W|e|a|t|h|e|r|: |S|n|o|w\nOverrides [Tactical Weather Settings] ALLOW_SNOW\n \nSnowstorms decrease visibility.\n \nConfigurable Options:\nSNOW_EVENTS_PER_DAY\nSNOW_CHANCE_PER_DAY\nSNOW_MIN_LENGTH_IN_MINUTES\nSNOW_MAX_LENGTH_IN_MINUTES\nWEAPON_RELIABILITY_REDUCTION_SNOW\nBREATH_GAIN_REDUCTION_SNOW\nVISUAL_DISTANCE_DECREASE_SNOW\nHEARING_REDUCTION_SNOW", L"|M|i|n|i |E|v|e|n|t|s\nOverrides [Mini Events Settings] MINI_EVENTS_ENABLED\n \nRandom events can occur.\n \nConfigurable Options:\nMINI_EVENTS_MIN_HOURS_BETWEEN_EVENTS\nMINI_EVENTS_MAX_HOURS_BETWEEN_EVENTS\n \nSee MiniEvents.lua for more details.", L"|A|R|C\nOverrides [Rebel Command Settings] REBEL_COMMAND_ENABLED\n \nCommand the rebel movement at the strategic level, and upgrade captured towns.\n \nFor tweakable values, see RebelCommand_Settings.ini.", + L"|S|t|r|a|t|e|g|i|c |T|r|a|n|s|p|o|r|t |G|r|o|u|p|s\nOverrides [Strategic Gameplay Settings] STRATEGIC_TRANSPORT_GROUPS_ENABLED\n \nTransport groups carry valuable equipment across the map.\n \nConfigurable Options:\nMAX_SIMULTANEOUS_STRATEGIC_TRANSPORT_GROUPS", }; STR16 z113FeaturesPanelText[] = @@ -6345,6 +6347,7 @@ STR16 z113FeaturesPanelText[] = L"Toggle snow. In a snowstorm, it is harder to see, weapons degrade faster, and it is a little harder to regain breath.", L"During the course of a campaign, brief events can pop up. You can select one of two responses, which may have positive and/or negative effects. Events can affect a wide variety of things, but mostly your mercs.", L"After completing the food delivery quest for the rebels, they will grant you access to their command website (A.R.C.). You can set the rebels' country-wide directive there, and capturing towns allows you to enact policies in that region that provide powerful bonuses. This comes at a price - town loyalty will rise slower, so you will need to work harder to have the locals trust you.", + L"The enemy sends groups across the map. If you can find and intercept them, they will probably have valuable gear. However, depending on your difficulty, each group that completes its transport mission provides the AI with strategic resources. Best experienced with Arulco Strategic Division enabled.", }; diff --git a/Utils/_PolishText.cpp b/Utils/_PolishText.cpp index 099f1ea3c..cf5add1d0 100644 --- a/Utils/_PolishText.cpp +++ b/Utils/_PolishText.cpp @@ -6266,6 +6266,7 @@ STR16 z113FeaturesToggleText[] = L"Weather: Snow", L"Mini Events", L"Arulco Rebel Command", + L"Strategic Transport Groups", }; STR16 z113FeaturesHelpText[] = @@ -6313,6 +6314,7 @@ STR16 z113FeaturesHelpText[] = L"|W|e|a|t|h|e|r|: |S|n|o|w\nOverrides [Tactical Weather Settings] ALLOW_SNOW\n \nSnowstorms decrease visibility.\n \nConfigurable Options:\nSNOW_EVENTS_PER_DAY\nSNOW_CHANCE_PER_DAY\nSNOW_MIN_LENGTH_IN_MINUTES\nSNOW_MAX_LENGTH_IN_MINUTES\nWEAPON_RELIABILITY_REDUCTION_SNOW\nBREATH_GAIN_REDUCTION_SNOW\nVISUAL_DISTANCE_DECREASE_SNOW\nHEARING_REDUCTION_SNOW", L"|M|i|n|i |E|v|e|n|t|s\nOverrides [Mini Events Settings] MINI_EVENTS_ENABLED\n \nRandom events can occur.\n \nConfigurable Options:\nMINI_EVENTS_MIN_HOURS_BETWEEN_EVENTS\nMINI_EVENTS_MAX_HOURS_BETWEEN_EVENTS\n \nSee MiniEvents.lua for more details.", L"|A|R|C\nOverrides [Rebel Command Settings] REBEL_COMMAND_ENABLED\n \nCommand the rebel movement at the strategic level, and upgrade captured towns.\n \nFor tweakable values, see RebelCommand_Settings.ini.", + L"|S|t|r|a|t|e|g|i|c |T|r|a|n|s|p|o|r|t |G|r|o|u|p|s\nOverrides [Strategic Gameplay Settings] STRATEGIC_TRANSPORT_GROUPS_ENABLED\n \nTransport groups carry valuable equipment across the map.\n \nConfigurable Options:\nMAX_SIMULTANEOUS_STRATEGIC_TRANSPORT_GROUPS", }; STR16 z113FeaturesPanelText[] = @@ -6360,6 +6362,7 @@ STR16 z113FeaturesPanelText[] = L"Toggle snow. In a snowstorm, it is harder to see, weapons degrade faster, and it is a little harder to regain breath.", L"During the course of a campaign, brief events can pop up. You can select one of two responses, which may have positive and/or negative effects. Events can affect a wide variety of things, but mostly your mercs.", L"After completing the food delivery quest for the rebels, they will grant you access to their command website (A.R.C.). You can set the rebels' country-wide directive there, and capturing towns allows you to enact policies in that region that provide powerful bonuses. This comes at a price - town loyalty will rise slower, so you will need to work harder to have the locals trust you.", + L"The enemy sends groups across the map. If you can find and intercept them, they will probably have valuable gear. However, depending on your difficulty, each group that completes its transport mission provides the AI with strategic resources. Best experienced with Arulco Strategic Division enabled.", }; diff --git a/Utils/_RussianText.cpp b/Utils/_RussianText.cpp index 8fa016bcd..1cd7cd5ab 100644 --- a/Utils/_RussianText.cpp +++ b/Utils/_RussianText.cpp @@ -6258,6 +6258,7 @@ STR16 z113FeaturesToggleText[] = L"Weather: Snow", L"Mini Events", L"Arulco Rebel Command", + L"Strategic Transport Groups", }; STR16 z113FeaturesHelpText[] = @@ -6305,6 +6306,7 @@ STR16 z113FeaturesHelpText[] = L"|W|e|a|t|h|e|r|: |S|n|o|w\nOverrides [Tactical Weather Settings] ALLOW_SNOW\n \nSnowstorms decrease visibility.\n \nConfigurable Options:\nSNOW_EVENTS_PER_DAY\nSNOW_CHANCE_PER_DAY\nSNOW_MIN_LENGTH_IN_MINUTES\nSNOW_MAX_LENGTH_IN_MINUTES\nWEAPON_RELIABILITY_REDUCTION_SNOW\nBREATH_GAIN_REDUCTION_SNOW\nVISUAL_DISTANCE_DECREASE_SNOW\nHEARING_REDUCTION_SNOW", L"|M|i|n|i |E|v|e|n|t|s\nOverrides [Mini Events Settings] MINI_EVENTS_ENABLED\n \nRandom events can occur.\n \nConfigurable Options:\nMINI_EVENTS_MIN_HOURS_BETWEEN_EVENTS\nMINI_EVENTS_MAX_HOURS_BETWEEN_EVENTS\n \nSee MiniEvents.lua for more details.", L"|A|R|C\nOverrides [Rebel Command Settings] REBEL_COMMAND_ENABLED\n \nCommand the rebel movement at the strategic level, and upgrade captured towns.\n \nFor tweakable values, see RebelCommand_Settings.ini.", + L"|S|t|r|a|t|e|g|i|c |T|r|a|n|s|p|o|r|t |G|r|o|u|p|s\nOverrides [Strategic Gameplay Settings] STRATEGIC_TRANSPORT_GROUPS_ENABLED\n \nTransport groups carry valuable equipment across the map.\n \nConfigurable Options:\nMAX_SIMULTANEOUS_STRATEGIC_TRANSPORT_GROUPS", }; STR16 z113FeaturesPanelText[] = @@ -6352,6 +6354,7 @@ STR16 z113FeaturesPanelText[] = L"Toggle snow. In a snowstorm, it is harder to see, weapons degrade faster, and it is a little harder to regain breath.", L"During the course of a campaign, brief events can pop up. You can select one of two responses, which may have positive and/or negative effects. Events can affect a wide variety of things, but mostly your mercs.", L"After completing the food delivery quest for the rebels, they will grant you access to their command website (A.R.C.). You can set the rebels' country-wide directive there, and capturing towns allows you to enact policies in that region that provide powerful bonuses. This comes at a price - town loyalty will rise slower, so you will need to work harder to have the locals trust you.", + L"The enemy sends groups across the map. If you can find and intercept them, they will probably have valuable gear. However, depending on your difficulty, each group that completes its transport mission provides the AI with strategic resources. Best experienced with Arulco Strategic Division enabled.", }; From 9120383d1300d46471f9657995bf4f7afbf62984 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Mon, 29 May 2023 06:49:32 -0700 Subject: [PATCH 59/81] Fix element assignments --- Utils/XML_Items.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Utils/XML_Items.cpp b/Utils/XML_Items.cpp index 0dc1938d3..c48b2cb28 100644 --- a/Utils/XML_Items.cpp +++ b/Utils/XML_Items.cpp @@ -1507,34 +1507,34 @@ itemEndElementHandle(void *userData, const XML_Char *name) } else if (strcmp(name, "ProvidesRobotNightVision") == 0) { - pData->curElement == ELEMENT; + pData->curElement = ELEMENT; pData->curItem.fProvidesRobotNightVision = (BOOLEAN)atol(pData->szCharData); } else if (strcmp(name, "ProvidesRobotLaserBonus") == 0) { - pData->curElement == ELEMENT; + pData->curElement = ELEMENT; pData->curItem.fProvidesRobotLaserBonus = (BOOLEAN)atol(pData->szCharData); } else if (strcmp(name, "FoodSystemExclusive") == 0) { - pData->curElement == ELEMENT; + pData->curElement = ELEMENT; if (atol(pData->szCharData)) pData->curItem.usLimitedToSystem|= FOOD_SYSTEM_FLAG; } else if (strcmp(name, "DiseaseSystemExclusive") == 0) { - pData->curElement == ELEMENT; + pData->curElement = ELEMENT; if (atol(pData->szCharData)) pData->curItem.usLimitedToSystem|= DISEASE_SYSTEM_FLAG; } else if (strcmp(name, "TransportGroupMinProgress") == 0) { - pData->curElement == ELEMENT; + pData->curElement = ELEMENT; pData->curItem.iTransportGroupMinProgress = (INT8)atoi(pData->szCharData); } else if (strcmp(name, "TransportGroupMaxProgress") == 0) { - pData->curElement == ELEMENT; + pData->curElement = ELEMENT; pData->curItem.iTransportGroupMaxProgress = (INT8)atoi(pData->szCharData); } From f06d863b436e884cb4cd1d9dde8d0feab8a5109d Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Thu, 1 Jun 2023 00:12:38 -0700 Subject: [PATCH 60/81] Some cleanup --- Strategic/Queen Command.cpp | 2 -- Strategic/Strategic AI.cpp | 3 --- Strategic/Strategic Movement.cpp | 2 +- Strategic/Strategic Transport Groups.cpp | 34 ++++++++---------------- 4 files changed, 12 insertions(+), 29 deletions(-) diff --git a/Strategic/Queen Command.cpp b/Strategic/Queen Command.cpp index 7600f1b86..d87ea1742 100644 --- a/Strategic/Queen Command.cpp +++ b/Strategic/Queen Command.cpp @@ -687,7 +687,6 @@ BOOLEAN PrepareEnemyForSectorBattle() } } - // rftr todo: check if feature is enabled UpdateTransportGroupInventory(); ValidateEnemiesHaveWeapons(); @@ -1141,7 +1140,6 @@ BOOLEAN PrepareEnemyForSectorBattle() pGroup = pGroup->next; } - // rftr todo: check if feature is enabled UpdateTransportGroupInventory(); ValidateEnemiesHaveWeapons(); diff --git a/Strategic/Strategic AI.cpp b/Strategic/Strategic AI.cpp index 11160c850..869da5b1e 100644 --- a/Strategic/Strategic AI.cpp +++ b/Strategic/Strategic AI.cpp @@ -3466,9 +3466,6 @@ void EvaluateQueenSituation() uiOffset += dEnemyGeneralsSpeedupFactor * (zDiffSetting[gGameOptions.ubDifficultyLevel].iBaseDelayInMinutesBetweenEvaluations + Random( zDiffSetting[gGameOptions.ubDifficultyLevel].iEvaluationDelayVariance )); - // rftr todo: send transport group here? - ScreenMsg( FONT_RED, MSG_INTERFACE, L"Evaluating queen situation..."); - // Check/update reinforcements pool if old behavior is enabled if ( !gfUnlimitedTroops && zDiffSetting[gGameOptions.ubDifficultyLevel].iQueenPoolIncrementDaysPerDifficultyLevel == 0 ) { diff --git a/Strategic/Strategic Movement.cpp b/Strategic/Strategic Movement.cpp index 0a3f0c001..dd11dce20 100644 --- a/Strategic/Strategic Movement.cpp +++ b/Strategic/Strategic Movement.cpp @@ -3635,7 +3635,7 @@ INT32 GetSectorMvtTimeForGroup( UINT8 ubSector, UINT8 ubDirection, GROUP *pGroup dEnemyGeneralsSpeedupFactor = max( 0.75f, dEnemyGeneralsSpeedupFactor - gStrategicStatus.usVIPsLeft * gGameExternalOptions.fEnemyGeneralStrategicMovementSpeedBonus ); } - // rftr todo: transport groups move slower than normal + // rftr: transport groups move slower than normal const FLOAT transportSpeedFactor = 0.75f; iBestTraverseTime = dEnemyGeneralsSpeedupFactor * transportSpeedFactor * iBestTraverseTime; diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index ba71ea8b7..a5e68e824 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -16,10 +16,6 @@ addition, transport groups will also be carrying supplies that the player may fi Transport group compositions will vary based on the player's progress, how many interceptions have been completed recently, and the difficulty of the game. -TODO LIST: -- use proper loyalty degradation (Strategic Loyalty lua) (maybe...) -- use enemygunchoices and enemyitemchoices to populate bonus loot, depending on jeep or no jeep - */ #include "Strategic Transport Groups.h" @@ -44,10 +40,11 @@ TODO LIST: #include "Strategic Movement.h" #include "Strategic Town Loyalty.h" +#define TRANSPORT_GROUP_DEBUG(x, ...) if (gGameExternalOptions.fStrategicTransportGroupsDebug) {ScreenMsg(FONT_RED, MSG_INTERFACE, x, __VA_ARGS__);} + extern ARMY_GUN_CHOICE_TYPE gExtendedArmyGunChoices[SOLDIER_GUN_CHOICE_SELECTIONS][ARMY_GUN_LEVELS]; extern ARMY_GUN_CHOICE_TYPE gArmyItemChoices[SOLDIER_GUN_CHOICE_SELECTIONS][MAX_ITEM_TYPES]; extern BOOLEAN gfTownUsesLoyalty[MAX_TOWNS]; -//extern STRATEGIC_STATUS gStrategicStatus; std::map> transportGroupIdToSoldierMap; std::map transportGroupSectorInfo; @@ -87,8 +84,7 @@ BOOLEAN DeployTransportGroup() mineSectorIds.push_back(mineSector); } - if (gGameExternalOptions.fStrategicTransportGroupsDebug) - ScreenMsg(FONT_RED, MSG_INTERFACE, L"DeployTransportGroup valid town destinations: %d", mineSectorIds.size()); + TRANSPORT_GROUP_DEBUG(L"DeployTransportGroup valid town destinations: %d", mineSectorIds.size()); // no valid destinations if (mineSectorIds.size() == 0) return FALSE; @@ -104,8 +100,7 @@ BOOLEAN DeployTransportGroup() pGroup = pGroup->next; } - if (gGameExternalOptions.fStrategicTransportGroupsDebug) - ScreenMsg(FONT_RED, MSG_INTERFACE, L"DeployTransportGroup found existing transport groups: %d", transportGroupCount); + TRANSPORT_GROUP_DEBUG(L"DeployTransportGroup found existing transport groups: %d", transportGroupCount); // if there are too many active transport groups, don't deploy any more // maximum number of active groups is the number of valid destinations at queen decision time @@ -116,8 +111,7 @@ BOOLEAN DeployTransportGroup() const UINT8 ubSectorID = (UINT8)mineSectorIds[Random(mineSectorIds.size())]; - if (gGameExternalOptions.fStrategicTransportGroupsDebug) - ScreenMsg(FONT_RED, MSG_INTERFACE, L"DeployTransportGroup sending group to sectorId: %d (%d/%d)", ubSectorID, SECTORX(ubSectorID), SECTORY(ubSectorID)); + TRANSPORT_GROUP_DEBUG(L"DeployTransportGroup sending group to sectorId: %d (%d/%d)", ubSectorID, SECTORX(ubSectorID), SECTORY(ubSectorID)); UINT8 admins, troops, elites, robots, jeeps, tanks; const UINT8 progress = min(125, HighestPlayerProgressPercentage() + recentLossCount * 5); @@ -167,8 +161,7 @@ BOOLEAN ReturnTransportGroup(INT32 groupId) if (pGroup == nullptr) { - if (gGameExternalOptions.fStrategicTransportGroupsDebug) - ScreenMsg( FONT_YELLOW, MSG_INTERFACE, L"RETURN_TRANSPORT_GROUP failed to find groupid %d", groupId); + TRANSPORT_GROUP_DEBUG(L"RETURN_TRANSPORT_GROUP failed to find groupid %d", groupId); return FALSE; } @@ -427,12 +420,6 @@ void UpdateTransportGroupInventory() std::map> ammoBoxes; // map coolness to ammo vector - // rftr todo: instead of building ammo caches, perhaps we could examine ChooseWeaponForSoldierCreateStruct(). excerpt: - // usAmmoIndex = RandomMagazine( &pp->Inv[HANDPOS], ubChanceStandardAmmo, max(Item[usGunIndex].ubCoolness, HighestPlayerProgressPercentage() / 10 + 3 ), pp->ubSoldierClass); - // however, we'd still need to convert the magazine into an ammo box - // for conversion, see the following (ammo conversion in strategic inventory) - // void SortSectorInventoryAmmo(bool useBoxes) - // item cache build { // let's be nice to the player and only drop ammo for guns their mercs have in inventory @@ -687,8 +674,7 @@ void UpdateTransportGroupInventory() break; default: - if (gGameExternalOptions.fStrategicTransportGroupsDebug) - ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Warning: ignoring unhandled transport group loot type: %d", itemType); + TRANSPORT_GROUP_DEBUG(L"Warning: ignoring unhandled transport group loot type: %d", itemType); // nothing! break; } @@ -780,8 +766,7 @@ void UpdateTransportGroupInventory() break; default: - if (gGameExternalOptions.fStrategicTransportGroupsDebug) - ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Warning: ignoring unhandled transport group loot type: %d", itemType); + TRANSPORT_GROUP_DEBUG(L"Warning: ignoring unhandled transport group loot type: %d", itemType); // nothing! break; } @@ -973,3 +958,6 @@ const std::map GetTransportGroupSectorInfo() { return transportGroupSectorInfo; } + +#undef TRANSPORT_GROUP_DEBUG + From fe380bd2b3c80bd056620161d9f1f2f58390c399 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Thu, 1 Jun 2023 01:00:13 -0700 Subject: [PATCH 61/81] Fix ammobox checks --- Strategic/Strategic Transport Groups.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index a5e68e824..85212064f 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -418,8 +418,6 @@ void UpdateTransportGroupInventory() std::map> itemMap; - std::map> ammoBoxes; // map coolness to ammo vector - // item cache build { // let's be nice to the player and only drop ammo for guns their mercs have in inventory @@ -428,7 +426,7 @@ void UpdateTransportGroupInventory() { if (MercPtrs[i]->bActive && !(MercPtrs[i]->flags.uiStatusFlags & SOLDIER_VEHICLE)) { - for (int j = 0 ; MercPtrs[i]->inv.size(); ++j) + for (int j = 0 ; j < MercPtrs[i]->inv.size(); ++j) { OBJECTTYPE& obj = MercPtrs[i]->inv[j]; if (obj.exists() @@ -490,8 +488,6 @@ void UpdateTransportGroupInventory() { if (Magazine[Item[i].ubClassIndex].ubMagType == AMMO_BOX && playerCalibres.find(Magazine[Item[i].ubClassIndex].ubCalibre) != playerCalibres.end()) { - ammoBoxes[Item[i].ubCoolness].push_back(i); - if (Item[i].ubCoolness <= ((progress+5) / 10)+1) { itemMap[AMMO_BOXES].push_back(i); @@ -568,6 +564,7 @@ void UpdateTransportGroupInventory() std::map::iterator soldierClassIter = groupIter->second.find(SOLDIER_CLASS_JEEP); if (soldierClassIter != groupIter->second.end()) { + TRANSPORT_GROUP_DEBUG(L"Found group with jeep"); // this group has a jeep in it! // only jeeps carry things // but give a little extra, since the jeep exploding can outright destroy things @@ -694,8 +691,11 @@ void UpdateTransportGroupInventory() || pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE) { // jeep is carrying most things, so soldiers just have ammo - const UINT16 ammoId = itemMap[AMMO_BOXES][Random(itemMap[AMMO_BOXES].size())]; - addItemToInventory(pSoldier, ammoId, 1); + if (itemMap[AMMO_BOXES].size() > 0) + { + const UINT16 ammoId = itemMap[AMMO_BOXES][Random(itemMap[AMMO_BOXES].size())]; + addItemToInventory(pSoldier, ammoId, 1); + } // force inventory to be dropped! for (int i = 0; i < pSoldier->inv.size(); ++i) @@ -711,6 +711,7 @@ void UpdateTransportGroupInventory() } else { + TRANSPORT_GROUP_DEBUG(L"Found group with NO jeep"); // no jeep in group, add things normally soldierClassIter = groupIter->second.find(pSoldier->ubSoldierClass); if (soldierClassIter != groupIter->second.end()) From adc99ecaff43cb427e51cf6aece1c5c6b7d2bc7d Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Thu, 1 Jun 2023 01:28:41 -0700 Subject: [PATCH 62/81] Fixes: - properly check jeep counts in groups - don't double-decrement soldiers adding items to non-jeep group soldier inventories --- Strategic/Strategic Transport Groups.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index 85212064f..1dcd03039 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -562,9 +562,9 @@ void UpdateTransportGroupInventory() // found a matching transport groupid std::map::iterator soldierClassIter = groupIter->second.find(SOLDIER_CLASS_JEEP); - if (soldierClassIter != groupIter->second.end()) + if (soldierClassIter != groupIter->second.end() && groupIter->second[SOLDIER_CLASS_JEEP] > 0) { - TRANSPORT_GROUP_DEBUG(L"Found group with jeep"); + TRANSPORT_GROUP_DEBUG(L"Found groupid[%d] with admin[%d] troop[%d] elite[%d] jeep[%d]", groupIter->first, groupIter->second[SOLDIER_CLASS_ADMINISTRATOR], groupIter->second[SOLDIER_CLASS_ARMY], groupIter->second[SOLDIER_CLASS_ELITE], groupIter->second[SOLDIER_CLASS_JEEP]); // this group has a jeep in it! // only jeeps carry things // but give a little extra, since the jeep exploding can outright destroy things @@ -711,7 +711,7 @@ void UpdateTransportGroupInventory() } else { - TRANSPORT_GROUP_DEBUG(L"Found group with NO jeep"); + TRANSPORT_GROUP_DEBUG(L"Found jeepless groupid[%d] with admin[%d] troop[%d] elite[%d] jeep[%d]", groupIter->first, groupIter->second[SOLDIER_CLASS_ADMINISTRATOR], groupIter->second[SOLDIER_CLASS_ARMY], groupIter->second[SOLDIER_CLASS_ELITE], groupIter->second[SOLDIER_CLASS_JEEP]); // no jeep in group, add things normally soldierClassIter = groupIter->second.find(pSoldier->ubSoldierClass); if (soldierClassIter != groupIter->second.end()) @@ -719,9 +719,6 @@ void UpdateTransportGroupInventory() // found a matching soldierclass if (soldierClassIter->second > 0) { - // there are still un-updated soldiers! begin the update! - soldierClassIter->second--; - //if (outgoing) { for (int i = TRANSPORT_LOOT_START; i <= TRANSPORT_LOOT_END; ++i) From 94c05f0d3cba09b6b1ce659fbbd136c34a2cb3c9 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Thu, 1 Jun 2023 11:13:49 -0700 Subject: [PATCH 63/81] Fix: cache original group jeep counts as we iterate through the soldier list --- Strategic/Strategic Transport Groups.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index 1dcd03039..3fdd954dc 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -540,6 +540,8 @@ void UpdateTransportGroupInventory() } }; + // cache the initial jeep count of every group we find + std::map cachedGroupJeepCount; for (int slot = firstSlot; (slot <= lastSlot); ++slot) { SOLDIERTYPE* pSoldier = &Menptr[slot]; @@ -562,7 +564,12 @@ void UpdateTransportGroupInventory() // found a matching transport groupid std::map::iterator soldierClassIter = groupIter->second.find(SOLDIER_CLASS_JEEP); - if (soldierClassIter != groupIter->second.end() && groupIter->second[SOLDIER_CLASS_JEEP] > 0) + if (cachedGroupJeepCount.find(groupIter->first) == cachedGroupJeepCount.end()) + { + cachedGroupJeepCount[groupIter->first] = soldierClassIter == groupIter->second.end() ? 0 : groupIter->second[SOLDIER_CLASS_JEEP]; + } + + if (soldierClassIter != groupIter->second.end() && cachedGroupJeepCount.find(groupIter->first) != cachedGroupJeepCount.end() && cachedGroupJeepCount[groupIter->first] > 0) { TRANSPORT_GROUP_DEBUG(L"Found groupid[%d] with admin[%d] troop[%d] elite[%d] jeep[%d]", groupIter->first, groupIter->second[SOLDIER_CLASS_ADMINISTRATOR], groupIter->second[SOLDIER_CLASS_ARMY], groupIter->second[SOLDIER_CLASS_ELITE], groupIter->second[SOLDIER_CLASS_JEEP]); // this group has a jeep in it! From ec7aa9e5d9ac655f85a6a7f4ee55216baad08bd8 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Sun, 4 Jun 2023 23:55:19 -0700 Subject: [PATCH 64/81] Ammo boxes are always valid loot --- Strategic/Strategic Transport Groups.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index 3fdd954dc..bee45d855 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -1,3 +1,4 @@ +#pragma optimize("",off) /* Strategic Transport Groups by rftr @@ -441,7 +442,7 @@ void UpdateTransportGroupInventory() for (UINT16 i = 0; i < gMAXITEMS_READ; ++i) { if (!ItemIsLegal(i, TRUE)) continue; - if (Item[i].iTransportGroupMaxProgress == 0 || Item[i].iTransportGroupMinProgress > progress || progress > Item[i].iTransportGroupMaxProgress) continue; + if ((Item[i].usItemClass & IC_AMMO) == 0 && (Item[i].iTransportGroupMaxProgress == 0 || Item[i].iTransportGroupMinProgress > progress || progress > Item[i].iTransportGroupMaxProgress)) continue; if (Item[i].medical) { @@ -488,7 +489,7 @@ void UpdateTransportGroupInventory() { if (Magazine[Item[i].ubClassIndex].ubMagType == AMMO_BOX && playerCalibres.find(Magazine[Item[i].ubClassIndex].ubCalibre) != playerCalibres.end()) { - if (Item[i].ubCoolness <= ((progress+5) / 10)+1) + if (Item[i].ubCoolness <= ((progress+5) / 10)+2) { itemMap[AMMO_BOXES].push_back(i); } From ba831566211271b8ef5db2210e8d54e9ad48f9f8 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Mon, 5 Jun 2023 23:18:02 -0700 Subject: [PATCH 65/81] Properly put backpacks on soldiers --- Strategic/Strategic Transport Groups.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index bee45d855..c3cfadbe8 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -705,6 +705,14 @@ void UpdateTransportGroupInventory() addItemToInventory(pSoldier, ammoId, 1); } + if (itemMap[BACKPACKS].size() > 0 && UsingNewInventorySystem()) + { + OBJECTTYPE obj; + CreateItem(Random(itemMap[BACKPACKS].size()), 100, &obj); + obj.fFlags |= OBJECT_UNDROPPABLE; + pSoldier->inv[BPACKPOCKPOS] = obj; + } + // force inventory to be dropped! for (int i = 0; i < pSoldier->inv.size(); ++i) { @@ -750,7 +758,15 @@ void UpdateTransportGroupInventory() break; case BACKPACKS: - addItemToInventory(pSoldier, id, 1); + { + if (UsingNewInventorySystem()) + { + OBJECTTYPE obj; + CreateItem(id, 100, &obj); + obj.fFlags |= OBJECT_UNDROPPABLE; + pSoldier->inv[BPACKPOCKPOS] = obj; + } + } break; case MEDICAL_FIRSTAIDKITS: From e01e2b9892c84160c5776d862d9e8b03594365fc Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Thu, 8 Jun 2023 22:26:35 -0700 Subject: [PATCH 66/81] Delete visual studio files --- Strategic/Strategic_VS2005.vcproj | 823 ----------------------------- Strategic/Strategic_VS2008.vcproj | 821 ---------------------------- Strategic/Strategic_VS2010.vcxproj | 316 ----------- Strategic/Strategic_VS2013.vcxproj | 336 ------------ Strategic/Strategic_VS2017.vcxproj | 337 ------------ Strategic/Strategic_VS2019.vcxproj | 514 ------------------ 6 files changed, 3147 deletions(-) delete mode 100644 Strategic/Strategic_VS2005.vcproj delete mode 100644 Strategic/Strategic_VS2008.vcproj delete mode 100644 Strategic/Strategic_VS2010.vcxproj delete mode 100644 Strategic/Strategic_VS2013.vcxproj delete mode 100644 Strategic/Strategic_VS2017.vcxproj delete mode 100644 Strategic/Strategic_VS2019.vcxproj diff --git a/Strategic/Strategic_VS2005.vcproj b/Strategic/Strategic_VS2005.vcproj deleted file mode 100644 index be354fb69..000000000 --- a/Strategic/Strategic_VS2005.vcproj +++ /dev/null @@ -1,823 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Strategic/Strategic_VS2008.vcproj b/Strategic/Strategic_VS2008.vcproj deleted file mode 100644 index 3f265c8d3..000000000 --- a/Strategic/Strategic_VS2008.vcproj +++ /dev/null @@ -1,821 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Strategic/Strategic_VS2010.vcxproj b/Strategic/Strategic_VS2010.vcxproj deleted file mode 100644 index c091fe63a..000000000 --- a/Strategic/Strategic_VS2010.vcxproj +++ /dev/null @@ -1,316 +0,0 @@ - - - - - Debug - Win32 - - - MapEditorD - Win32 - - - MapEditor - Win32 - - - Release - Win32 - - - Relese_WithDebugInfo - Win32 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {DE9B77CC-7CD5-4951-9B7F-BAC7B4A8169C} - Win32Proj - Strategic - Strategic - - - - StaticLibrary - true - NotSet - - - StaticLibrary - true - NotSet - - - StaticLibrary - false - false - NotSet - - - StaticLibrary - false - false - NotSet - - - StaticLibrary - false - false - NotSet - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - NotUsing - Level3 - Disabled - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreadedDebug - - - - - - - Windows - true - - - - - NotUsing - Level3 - Disabled - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreadedDebug - - - - - - - Windows - true - - - - - Level3 - NotUsing - MaxSpeed - true - true - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreaded - - - - - - - Windows - true - true - true - - - - - Level3 - NotUsing - MaxSpeed - true - true - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreaded - - - - - - - Windows - true - true - true - - - - - Level3 - NotUsing - Disabled - true - true - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreaded - - - - - EditAndContinue - - - Windows - true - true - true - - - - - - \ No newline at end of file diff --git a/Strategic/Strategic_VS2013.vcxproj b/Strategic/Strategic_VS2013.vcxproj deleted file mode 100644 index 7b65a7049..000000000 --- a/Strategic/Strategic_VS2013.vcxproj +++ /dev/null @@ -1,336 +0,0 @@ - - - - - Debug - Win32 - - - MapEditorD - Win32 - - - MapEditor - Win32 - - - Release - Win32 - - - Release_WithDebugInfo - Win32 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {DE9B77CC-7CD5-4951-9B7F-BAC7B4A8169C} - Win32Proj - Strategic - Strategic - - - - StaticLibrary - true - NotSet - v120 - - - StaticLibrary - true - NotSet - v120 - - - StaticLibrary - false - false - NotSet - v120 - - - StaticLibrary - false - false - NotSet - v120 - - - StaticLibrary - false - false - NotSet - v120 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - $(SolutionDir)\lib\VS2013\$(JA2Config)_$(JA2LangPrefix)\$(Configuration)\ - $(SolutionDir)\build\VS2013\$(JA2Config)_$(JA2LangPrefix)\$(ProjectName)_$(Configuration)\ - - - $(SolutionDir)\lib\VS2013\$(JA2Config)_$(JA2LangPrefix)\$(Configuration)\ - $(SolutionDir)\build\VS2013\$(JA2Config)_$(JA2LangPrefix)\$(ProjectName)_$(Configuration)\ - - - $(SolutionDir)\lib\VS2013\$(JA2Config)_$(JA2LangPrefix)\$(Configuration)\ - $(SolutionDir)\build\VS2013\$(JA2Config)_$(JA2LangPrefix)\$(ProjectName)_$(Configuration)\ - - - $(SolutionDir)\lib\VS2013\$(JA2Config)_$(JA2LangPrefix)\$(Configuration)\ - $(SolutionDir)\build\VS2013\$(JA2Config)_$(JA2LangPrefix)\$(ProjectName)_$(Configuration)\ - - - $(SolutionDir)\lib\VS2013\$(JA2Config)_$(JA2LangPrefix)\$(Configuration)\ - $(SolutionDir)\build\VS2013\$(JA2Config)_$(JA2LangPrefix)\$(ProjectName)_$(Configuration)\ - - - - NotUsing - Level3 - Disabled - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreadedDebug - - - - - - - Windows - true - - - - - NotUsing - Level3 - Disabled - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreadedDebug - - - - - - - Windows - true - - - - - Level3 - NotUsing - MaxSpeed - true - true - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreaded - - - - - - - Windows - true - true - true - - - - - Level3 - NotUsing - MaxSpeed - true - true - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreaded - - - - - - - Windows - true - true - true - - - - - Level3 - NotUsing - Disabled - true - true - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreaded - - - - - EditAndContinue - - - Windows - true - true - true - - - - - - \ No newline at end of file diff --git a/Strategic/Strategic_VS2017.vcxproj b/Strategic/Strategic_VS2017.vcxproj deleted file mode 100644 index 542e72aca..000000000 --- a/Strategic/Strategic_VS2017.vcxproj +++ /dev/null @@ -1,337 +0,0 @@ - - - - - Debug - Win32 - - - MapEditorD - Win32 - - - MapEditor - Win32 - - - Release - Win32 - - - Release_WithDebugInfo - Win32 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {DE9B77CC-7CD5-4951-9B7F-BAC7B4A8169C} - Win32Proj - Strategic - Strategic - 10.0.15063.0 - - - - StaticLibrary - true - NotSet - v141 - - - StaticLibrary - true - NotSet - v141 - - - StaticLibrary - false - false - NotSet - v141 - - - StaticLibrary - false - false - NotSet - v141 - - - StaticLibrary - false - false - NotSet - v141 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - $(SolutionDir)\lib\VS2013\$(JA2Config)_$(JA2LangPrefix)\$(Configuration)\ - $(SolutionDir)\build\VS2013\$(JA2Config)_$(JA2LangPrefix)\$(ProjectName)_$(Configuration)\ - - - $(SolutionDir)\lib\VS2013\$(JA2Config)_$(JA2LangPrefix)\$(Configuration)\ - $(SolutionDir)\build\VS2013\$(JA2Config)_$(JA2LangPrefix)\$(ProjectName)_$(Configuration)\ - - - $(SolutionDir)\lib\VS2013\$(JA2Config)_$(JA2LangPrefix)\$(Configuration)\ - $(SolutionDir)\build\VS2013\$(JA2Config)_$(JA2LangPrefix)\$(ProjectName)_$(Configuration)\ - - - $(SolutionDir)\lib\VS2013\$(JA2Config)_$(JA2LangPrefix)\$(Configuration)\ - $(SolutionDir)\build\VS2013\$(JA2Config)_$(JA2LangPrefix)\$(ProjectName)_$(Configuration)\ - - - $(SolutionDir)\lib\VS2013\$(JA2Config)_$(JA2LangPrefix)\$(Configuration)\ - $(SolutionDir)\build\VS2013\$(JA2Config)_$(JA2LangPrefix)\$(ProjectName)_$(Configuration)\ - - - - NotUsing - Level3 - Disabled - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreadedDebug - - - - - - - Windows - true - - - - - NotUsing - Level3 - Disabled - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreadedDebug - - - - - - - Windows - true - - - - - Level3 - NotUsing - MaxSpeed - true - true - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreaded - - - - - - - Windows - true - true - true - - - - - Level3 - NotUsing - MaxSpeed - true - true - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreaded - - - - - - - Windows - true - true - true - - - - - Level3 - NotUsing - Disabled - true - true - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreaded - - - - - EditAndContinue - - - Windows - true - true - true - - - - - - \ No newline at end of file diff --git a/Strategic/Strategic_VS2019.vcxproj b/Strategic/Strategic_VS2019.vcxproj deleted file mode 100644 index 9d6cbf2c1..000000000 --- a/Strategic/Strategic_VS2019.vcxproj +++ /dev/null @@ -1,514 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - MapEditorD - Win32 - - - MapEditorD - x64 - - - MapEditor - Win32 - - - MapEditor - x64 - - - Release_WithDebugInfo - x64 - - - Release - Win32 - - - Release_WithDebugInfo - Win32 - - - Release - x64 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {DE9B77CC-7CD5-4951-9B7F-BAC7B4A8169C} - Win32Proj - Strategic - Strategic - 10.0 - - - - StaticLibrary - true - NotSet - v142 - - - StaticLibrary - true - NotSet - v142 - - - StaticLibrary - true - NotSet - v142 - - - StaticLibrary - true - NotSet - v142 - - - StaticLibrary - false - false - NotSet - v142 - - - StaticLibrary - false - false - NotSet - v142 - - - StaticLibrary - false - false - NotSet - v142 - - - StaticLibrary - false - false - NotSet - v142 - - - StaticLibrary - false - false - NotSet - v142 - - - StaticLibrary - false - false - NotSet - v142 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - $(SolutionDir)\lib\VS2013\$(JA2Config)_$(JA2LangPrefix)\$(Configuration)\ - $(SolutionDir)\build\VS2013\$(JA2Config)_$(JA2LangPrefix)\$(ProjectName)_$(Configuration)\ - - - - $(SolutionDir)\lib\VS2013\$(JA2Config)_$(JA2LangPrefix)\$(Configuration)\ - $(SolutionDir)\build\VS2013\$(JA2Config)_$(JA2LangPrefix)\$(ProjectName)_$(Configuration)\ - - - $(SolutionDir)\lib\VS2013\$(JA2Config)_$(JA2LangPrefix)\$(Configuration)\ - $(SolutionDir)\build\VS2013\$(JA2Config)_$(JA2LangPrefix)\$(ProjectName)_$(Configuration)\ - CppCoreCheckConstRules.ruleset - - - $(SolutionDir)\lib\VS2013\$(JA2Config)_$(JA2LangPrefix)\$(Configuration)\ - $(SolutionDir)\build\VS2013\$(JA2Config)_$(JA2LangPrefix)\$(ProjectName)_$(Configuration)\ - - - $(SolutionDir)\lib\VS2013\$(JA2Config)_$(JA2LangPrefix)\$(Configuration)\ - $(SolutionDir)\build\VS2013\$(JA2Config)_$(JA2LangPrefix)\$(ProjectName)_$(Configuration)\ - - - - NotUsing - Level3 - Disabled - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreadedDebug - - - - - - - Windows - true - - - - - NotUsing - Level3 - Disabled - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreadedDebug - - - - - - - Windows - true - - - - - NotUsing - Level3 - Disabled - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreadedDebug - - - - - - - Windows - true - - - - - NotUsing - Level3 - Disabled - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreadedDebug - - - - - - - Windows - true - - - - - Level3 - NotUsing - MaxSpeed - true - true - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreaded - - - - - - - Windows - true - true - true - - - - - Level3 - NotUsing - MaxSpeed - true - true - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreaded - - - - - - - Windows - true - true - true - - - - - Level3 - NotUsing - MaxSpeed - true - true - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreaded - - - - - - - Windows - true - true - true - - - - - Level3 - NotUsing - MaxSpeed - true - true - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreaded - - - - - - - Windows - true - true - true - - - - - Level3 - NotUsing - Disabled - true - true - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreaded - - - - - EditAndContinue - - - Windows - true - true - true - - - - - Level3 - NotUsing - Disabled - true - true - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreaded - - - - - ProgramDatabase - - - Windows - true - true - true - - - - - - \ No newline at end of file From 88e13a0e0948f7776b2401173e9933f5e98c4c98 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Thu, 22 Jun 2023 21:01:52 -0700 Subject: [PATCH 67/81] Try deploying transport groups before (and in addition to) creating reinforcement groups --- Strategic/Strategic AI.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Strategic/Strategic AI.cpp b/Strategic/Strategic AI.cpp index 869da5b1e..c64d85ed1 100644 --- a/Strategic/Strategic AI.cpp +++ b/Strategic/Strategic AI.cpp @@ -3495,6 +3495,9 @@ void EvaluateQueenSituation() // Gradually promote any remaining admins into troops UpgradeAdminsToTroops(); + // consider deploying a transport group + ExecuteStrategicAIAction( NPC_ACTION_DEPLOY_TRANSPORT_GROUP, 0, 0 ); + // we either have reinforcements or a request for reinforcements if (giRequestPoints > 0 && (giReinforcementPoints > 0 || giReinforcementPool > 0)) { @@ -3576,8 +3579,6 @@ void EvaluateQueenSituation() } } - ExecuteStrategicAIAction( NPC_ACTION_DEPLOY_TRANSPORT_GROUP, 0, 0 ); - ValidateWeights( 27 ); } From b758ab94cbe2564518933d60435e94306576fbf2 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Sat, 24 Jun 2023 01:13:15 -0700 Subject: [PATCH 68/81] Fix mine ownership check --- Strategic/Strategic Transport Groups.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index c3cfadbe8..c7b96c375 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -79,13 +79,16 @@ BOOLEAN DeployTransportGroup() if (IsMineShutDown(mineIndex) == TRUE) continue; // filter by MINE ownership - for novice/experienced, as hard/insane would have ignored this town above - const INT16 mineSector = STRATEGIC_INDEX_TO_SECTOR_INFO(GetMineSectorForTown(i)); + const INT16 mineSector = (GetMineSectorForTown(i)); if (StrategicMap[mineSector].fEnemyControlled == FALSE) continue; - mineSectorIds.push_back(mineSector); + mineSectorIds.push_back(STRATEGIC_INDEX_TO_SECTOR_INFO(mineSector)); } - TRANSPORT_GROUP_DEBUG(L"DeployTransportGroup valid town destinations: %d", mineSectorIds.size()); + for (int a = 0; a < mineSectorIds.size(); ++a) + { + TRANSPORT_GROUP_DEBUG(L"DeployTransportGroup valid town destination: %d (%d/%d)", mineSectorIds[a], SECTORX(mineSectorIds[a]), SECTORY(mineSectorIds[a])); + } // no valid destinations if (mineSectorIds.size() == 0) return FALSE; From 59085d7ba73d2605f5222adbbbd8c9184555ce44 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Sat, 24 Jun 2023 02:46:22 -0700 Subject: [PATCH 69/81] Reduce transport group speed to 50% --- Strategic/Strategic Movement.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Strategic/Strategic Movement.cpp b/Strategic/Strategic Movement.cpp index dd11dce20..039a59f4b 100644 --- a/Strategic/Strategic Movement.cpp +++ b/Strategic/Strategic Movement.cpp @@ -3636,7 +3636,7 @@ INT32 GetSectorMvtTimeForGroup( UINT8 ubSector, UINT8 ubDirection, GROUP *pGroup } // rftr: transport groups move slower than normal - const FLOAT transportSpeedFactor = 0.75f; + const FLOAT transportSpeedFactor = 0.5f; iBestTraverseTime = dEnemyGeneralsSpeedupFactor * transportSpeedFactor * iBestTraverseTime; From 319513336e322b5ae03a76c8dda781e12216191b Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Sat, 24 Jun 2023 14:22:32 -0700 Subject: [PATCH 70/81] Recent losses impacts max simultaneous groups --- Strategic/Strategic Transport Groups.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index c7b96c375..1c535abda 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -106,13 +106,14 @@ BOOLEAN DeployTransportGroup() TRANSPORT_GROUP_DEBUG(L"DeployTransportGroup found existing transport groups: %d", transportGroupCount); - // if there are too many active transport groups, don't deploy any more - // maximum number of active groups is the number of valid destinations at queen decision time - if (transportGroupCount >= min(gGameExternalOptions.iMaxSimultaneousTransportGroups, mineSectorIds.size())) return FALSE; - // track recent transport group interceptions const INT8 recentLossCount = min(5, GetAllStrategicEventsOfType(EVENT_TRANSPORT_GROUP_DEFEATED).size()); + // if there are too many active transport groups, don't deploy any more + // maximum number of active groups is the number of valid destinations at queen decision time + const INT8 maxGroups = gGameExternalOptions.iMaxSimultaneousTransportGroups - recentLossCount; + if (transportGroupCount >= min(max(maxGroups, 0), mineSectorIds.size())) return FALSE; + const UINT8 ubSectorID = (UINT8)mineSectorIds[Random(mineSectorIds.size())]; TRANSPORT_GROUP_DEBUG(L"DeployTransportGroup sending group to sectorId: %d (%d/%d)", ubSectorID, SECTORX(ubSectorID), SECTORY(ubSectorID)); From abb96ee4dc9593835230eba78c997c2ce8bb48a9 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Sun, 25 Jun 2023 12:19:48 -0700 Subject: [PATCH 71/81] Fix group nullptr when ordering a group to return home Fix town monitoring logic Fix turncoat monitoring Update debug info --- Strategic/Strategic Transport Groups.cpp | 57 +++++++++++++++++------- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index 1c535abda..976ed8f8f 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -43,6 +43,11 @@ and the difficulty of the game. #define TRANSPORT_GROUP_DEBUG(x, ...) if (gGameExternalOptions.fStrategicTransportGroupsDebug) {ScreenMsg(FONT_RED, MSG_INTERFACE, x, __VA_ARGS__);} +// how many turncoats are required to monitor a town for transport groups? +#define ELITE_TURNCOAT_MONITOR_REQUIREMENT 1 +#define TROOP_TURNCOAT_MONITOR_REQUIREMENT 3 +#define ADMIN_TURNCOAT_MONITOR_REQUIREMENT 5 + extern ARMY_GUN_CHOICE_TYPE gExtendedArmyGunChoices[SOLDIER_GUN_CHOICE_SELECTIONS][ARMY_GUN_LEVELS]; extern ARMY_GUN_CHOICE_TYPE gArmyItemChoices[SOLDIER_GUN_CHOICE_SELECTIONS][MAX_ITEM_TYPES]; extern BOOLEAN gfTownUsesLoyalty[MAX_TOWNS]; @@ -95,16 +100,21 @@ BOOLEAN DeployTransportGroup() INT8 transportGroupCount = 0; GROUP* pGroup = gpGroupList; + std::vector> groupIds; while (pGroup) { if (pGroup->usGroupTeam == ENEMY_TEAM && pGroup->pEnemyGroup->ubIntention == TRANSPORT) { + groupIds.emplace_back(pGroup->ubGroupID, pGroup->ubSectorX, pGroup->ubSectorY); transportGroupCount++; } pGroup = pGroup->next; } - TRANSPORT_GROUP_DEBUG(L"DeployTransportGroup found existing transport groups: %d", transportGroupCount); + for (int a = 0; a < groupIds.size(); ++a) + { + TRANSPORT_GROUP_DEBUG(L"DeployTransportGroup found existing transport groupid: %d at %d/%d", std::get<0>(groupIds[a]), std::get<1>(groupIds[a]), std::get<2>(groupIds[a])); + } // track recent transport group interceptions const INT8 recentLossCount = min(5, GetAllStrategicEventsOfType(EVENT_TRANSPORT_GROUP_DEFEATED).size()); @@ -158,7 +168,8 @@ BOOLEAN ReturnTransportGroup(INT32 groupId) if (pGroup->ubGroupID == groupId) { MoveSAIGroupToSector( &pGroup, SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), EVASIVE, TRANSPORT ); - pGroup->uiFlags &= ~GROUPFLAG_TRANSPORT_ENROUTE; + if (pGroup) + pGroup->uiFlags &= ~GROUPFLAG_TRANSPORT_ENROUTE; break; } pGroup = pGroup->next; @@ -186,9 +197,15 @@ void FillMapColoursForTransportGroups(INT32(&colorMap)[MAXIMUM_VALID_Y_COORDINAT GROUP* pGroup = gpGroupList; transportGroupSectorInfo.clear(); + enum class MonitoredSectorState { + Unmonitored, + Monitored, + GroupIncoming, + } monitoredSectorState; + // build map of detection sectors + ranges std::map, INT8> detectionMap; - std::map monitoredTowns; + std::map monitoredTowns; for( INT16 i = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; i <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; i++ ) { if( MercPtrs[ i ]->bActive && @@ -211,7 +228,7 @@ void FillMapColoursForTransportGroups(INT32(&colorMap)[MAXIMUM_VALID_Y_COORDINAT if (MercPtrs[i]->bAssignment == GATHERINTEL) { detectionMap[std::pair(MercPtrs[i]->sSectorX, MercPtrs[i]->sSectorY)] = DETECTION_RANGE_COVERT; - monitoredTowns[GetTownIdForSector(MercPtrs[i]->sSectorX, MercPtrs[i]->sSectorY)] = FALSE; + monitoredTowns[GetTownIdForSector(MercPtrs[i]->sSectorX, MercPtrs[i]->sSectorY)] = MonitoredSectorState::Monitored; } } } @@ -224,15 +241,21 @@ void FillMapColoursForTransportGroups(INT32(&colorMap)[MAXIMUM_VALID_Y_COORDINAT for (int y = MINIMUM_VALID_Y_COORDINATE; y <= MAXIMUM_VALID_Y_COORDINATE; ++y) { const UINT8 townId = GetTownIdForSector(x, y); - if (townId < 0) continue; + if (townId == BLANK_SECTOR) continue; CorrectTurncoatCount(x, y); - const UINT16 numTurncoats = NumTurncoatsOfClassInSector(x, y, SOLDIER_CLASS_ADMINISTRATOR) + NumTurncoatsOfClassInSector(x, y, SOLDIER_CLASS_ARMY) + NumTurncoatsOfClassInSector(x, y, SOLDIER_CLASS_ELITE); - - monitoredTowns[townId] = FALSE; + const UINT16 adminTurncoats = NumTurncoatsOfClassInSector(x, y, SOLDIER_CLASS_ADMINISTRATOR); + const UINT16 troopTurncoats = NumTurncoatsOfClassInSector(x, y, SOLDIER_CLASS_ARMY); + const UINT16 eliteTurncoats = NumTurncoatsOfClassInSector(x, y, SOLDIER_CLASS_ELITE); + + monitoredTowns[townId] = (gGameExternalOptions.fStrategicTransportGroupsDebug + || (adminTurncoats >= ADMIN_TURNCOAT_MONITOR_REQUIREMENT) + || (troopTurncoats >= TROOP_TURNCOAT_MONITOR_REQUIREMENT) + || (eliteTurncoats >= ELITE_TURNCOAT_MONITOR_REQUIREMENT)) ? MonitoredSectorState::Monitored : MonitoredSectorState::Unmonitored; } } + // colour all groups while (pGroup) { if (pGroup->usGroupTeam == ENEMY_TEAM) @@ -240,9 +263,6 @@ void FillMapColoursForTransportGroups(INT32(&colorMap)[MAXIMUM_VALID_Y_COORDINAT const UINT8 intention = pGroup->pEnemyGroup->ubIntention; if (intention == TRANSPORT ) { - if (gGameExternalOptions.fStrategicTransportGroupsDebug) - colorMap[pGroup->ubSectorY-1][pGroup->ubSectorX-1] = debugColor; - // check if current location is known const INT16 gx = pGroup->ubSectorX; const INT16 gy = pGroup->ubSectorY; @@ -258,7 +278,7 @@ void FillMapColoursForTransportGroups(INT32(&colorMap)[MAXIMUM_VALID_Y_COORDINAT transportGroupSectorInfo[SECTOR(pGroup->ubSectorX, pGroup->ubSectorY)] = TransportGroupSectorInfo::TransportGroupSectorInfo_LocatedGroup; } } - + // check if target location is monitored WAYPOINT* wp = pGroup->pWaypoints; @@ -277,9 +297,15 @@ void FillMapColoursForTransportGroups(INT32(&colorMap)[MAXIMUM_VALID_Y_COORDINAT } const UINT8 townId = GetTownIdForSector(wp->x, wp->y); - if (monitoredTowns.find(townId) != monitoredTowns.end()) + if (monitoredTowns.find(townId) != monitoredTowns.end() && monitoredTowns[townId] == MonitoredSectorState::Monitored) { - monitoredTowns[townId] = TRUE; + monitoredTowns[townId] = MonitoredSectorState::GroupIncoming; + } + + // debug: colour all group locations + if (gGameExternalOptions.fStrategicTransportGroupsDebug) + { + colorMap[pGroup->ubSectorY-1][pGroup->ubSectorX-1] = debugColor; } } } @@ -293,13 +319,14 @@ void FillMapColoursForTransportGroups(INT32(&colorMap)[MAXIMUM_VALID_Y_COORDINAT for (int y = MINIMUM_VALID_Y_COORDINATE; y <= MAXIMUM_VALID_Y_COORDINATE; ++y) { const UINT8 townId = GetTownIdForSector(x, y); - if (monitoredTowns.find(townId) != monitoredTowns.end() && monitoredTowns[townId]) + if (monitoredTowns.find(townId) != monitoredTowns.end() && monitoredTowns[townId] == MonitoredSectorState::GroupIncoming) { colorMap[y-1][x-1] = targetColor; transportGroupSectorInfo[SECTOR(x, y)] = TransportGroupSectorInfo::TransportGroupSectorInfo_LocatedDestination; } } } + } void ProcessTransportGroupReachedDestination(GROUP* pGroup) From b73c0d47b99562e388cdb95e7682d0ae19fdc717 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Sun, 25 Jun 2023 14:50:35 -0700 Subject: [PATCH 72/81] Ensure radio op has a radio for detection --- Strategic/Strategic Transport Groups.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index 976ed8f8f..e678039f5 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -219,7 +219,7 @@ void FillMapColoursForTransportGroups(INT32(&colorMap)[MAXIMUM_VALID_Y_COORDINAT { detectionMap[std::pair(MercPtrs[i]->sSectorX, MercPtrs[i]->sSectorY)] = DETECTION_RANGE_SCOUT; } - else if (HAS_SKILL_TRAIT(MercPtrs[i], RADIO_OPERATOR_NT)) + else if (HAS_SKILL_TRAIT(MercPtrs[i], RADIO_OPERATOR_NT) && MercPtrs[i]->CanUseRadio(FALSE)) { detectionMap[std::pair(MercPtrs[i]->sSectorX, MercPtrs[i]->sSectorY)] = DETECTION_RANGE_RADIO; } From 258ea8e2283cf29ea5d68ccb80085e346802bd3a Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Sun, 25 Jun 2023 18:38:57 -0700 Subject: [PATCH 73/81] Add nullptr check Fix turncoat monitor check overriding covops gather intel state --- Strategic/Queen Command.cpp | 4 +--- Strategic/Strategic Transport Groups.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Strategic/Queen Command.cpp b/Strategic/Queen Command.cpp index d87ea1742..04dbed610 100644 --- a/Strategic/Queen Command.cpp +++ b/Strategic/Queen Command.cpp @@ -2429,9 +2429,7 @@ void AddEnemiesToBattle( GROUP *pGroup, UINT8 ubStrategicInsertionCode, UINT8 ub UpdateMercInSector( pSoldier, gWorldSectorX, gWorldSectorY, 0 ); } - // rftr todo: check reinforcements for transport group presence? - // rftr todo: better: transport groups cannot/do not reinforce - if (pGroup->pEnemyGroup->ubIntention == TRANSPORT) + if (pGroup && pGroup->pEnemyGroup->ubIntention == TRANSPORT) { ScreenMsg(FONT_RED, MSG_INTERFACE, L"Transport group attempting to reinforce? This shouldn't happen!"); } diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index e678039f5..45d855d98 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -248,10 +248,10 @@ void FillMapColoursForTransportGroups(INT32(&colorMap)[MAXIMUM_VALID_Y_COORDINAT const UINT16 troopTurncoats = NumTurncoatsOfClassInSector(x, y, SOLDIER_CLASS_ARMY); const UINT16 eliteTurncoats = NumTurncoatsOfClassInSector(x, y, SOLDIER_CLASS_ELITE); - monitoredTowns[townId] = (gGameExternalOptions.fStrategicTransportGroupsDebug - || (adminTurncoats >= ADMIN_TURNCOAT_MONITOR_REQUIREMENT) - || (troopTurncoats >= TROOP_TURNCOAT_MONITOR_REQUIREMENT) - || (eliteTurncoats >= ELITE_TURNCOAT_MONITOR_REQUIREMENT)) ? MonitoredSectorState::Monitored : MonitoredSectorState::Unmonitored; + if (gGameExternalOptions.fStrategicTransportGroupsDebug + || (adminTurncoats >= ADMIN_TURNCOAT_MONITOR_REQUIREMENT) + || (troopTurncoats >= TROOP_TURNCOAT_MONITOR_REQUIREMENT) + || (eliteTurncoats >= ELITE_TURNCOAT_MONITOR_REQUIREMENT)) monitoredTowns[townId] = MonitoredSectorState::Monitored; } } From 90eaee89d0a7ae9fbf4bfa5ed0035f0a8f046dd7 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Mon, 26 Jun 2023 23:57:08 -0700 Subject: [PATCH 74/81] Fix backpack creation for soldiers in jeep groups --- Strategic/Strategic Transport Groups.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index 45d855d98..087211cc9 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -739,7 +739,7 @@ void UpdateTransportGroupInventory() if (itemMap[BACKPACKS].size() > 0 && UsingNewInventorySystem()) { OBJECTTYPE obj; - CreateItem(Random(itemMap[BACKPACKS].size()), 100, &obj); + CreateItem(itemMap[BACKPACKS][Random(itemMap[BACKPACKS].size())], 100, &obj); obj.fFlags |= OBJECT_UNDROPPABLE; pSoldier->inv[BPACKPOCKPOS] = obj; } From 67fdbe75e444848a9eb8409200e6bd02678ee3cf Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Tue, 27 Jun 2023 20:45:17 -0700 Subject: [PATCH 75/81] Transport group turncoats broadcast their location --- Strategic/Strategic Transport Groups.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index 087211cc9..0a9474c78 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -278,7 +278,16 @@ void FillMapColoursForTransportGroups(INT32(&colorMap)[MAXIMUM_VALID_Y_COORDINAT transportGroupSectorInfo[SECTOR(pGroup->ubSectorX, pGroup->ubSectorY)] = TransportGroupSectorInfo::TransportGroupSectorInfo_LocatedGroup; } } - + + // turncoats reveal their group's location + if (pGroup->pEnemyGroup->ubNumAdmins_Turncoat >= ADMIN_TURNCOAT_MONITOR_REQUIREMENT + || pGroup->pEnemyGroup->ubNumTroops_Turncoat >= TROOP_TURNCOAT_MONITOR_REQUIREMENT + || pGroup->pEnemyGroup->ubNumElites_Turncoat >= ELITE_TURNCOAT_MONITOR_REQUIREMENT) + { + colorMap[pGroup->ubSectorY-1][pGroup->ubSectorX-1] = targetColor; + transportGroupSectorInfo[SECTOR(pGroup->ubSectorX, pGroup->ubSectorY)] = TransportGroupSectorInfo::TransportGroupSectorInfo_LocatedGroup; + } + // check if target location is monitored WAYPOINT* wp = pGroup->pWaypoints; From 976c712958ccd72e533920b42178c2f4fd6c3080 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Tue, 27 Jun 2023 20:47:55 -0700 Subject: [PATCH 76/81] Fix transport speed modifier applying to all groups --- Strategic/Strategic Movement.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Strategic/Strategic Movement.cpp b/Strategic/Strategic Movement.cpp index 039a59f4b..d6d19b176 100644 --- a/Strategic/Strategic Movement.cpp +++ b/Strategic/Strategic Movement.cpp @@ -3636,7 +3636,7 @@ INT32 GetSectorMvtTimeForGroup( UINT8 ubSector, UINT8 ubDirection, GROUP *pGroup } // rftr: transport groups move slower than normal - const FLOAT transportSpeedFactor = 0.5f; + const FLOAT transportSpeedFactor = pGroup->pEnemyGroup->ubIntention == TRANSPORT ? 2.0f : 1.0f; iBestTraverseTime = dEnemyGeneralsSpeedupFactor * transportSpeedFactor * iBestTraverseTime; From 2375860af5015c05eb431b735ea761dd4e2f829b Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Sat, 1 Jul 2023 22:41:51 -0700 Subject: [PATCH 77/81] Add face items to transport group loot --- Strategic/Strategic Transport Groups.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index 0a9474c78..a180b7a4b 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -444,6 +444,7 @@ void UpdateTransportGroupInventory() BACKPACKS, RADIOS, ATTACHMENTS, + FACE_ITEMS, CAMO_KITS, MISC, GRENADE_THROWN, @@ -507,6 +508,7 @@ void UpdateTransportGroupInventory() itemMap[BACKPACKS].push_back(i); } } + else if (Item[i].usItemClass & IC_FACE) itemMap[FACE_ITEMS].push_back(i); else if (Item[i].camouflagekit) itemMap[CAMO_KITS].push_back(i); else if (Item[i].usItemClass & IC_MISC) { @@ -714,6 +716,10 @@ void UpdateTransportGroupInventory() } break; + case FACE_ITEMS: + addItemToInventory(pSoldier, id, 5); + break; + case CAMO_KITS: addItemToInventory(pSoldier, id, 6); break; @@ -817,6 +823,12 @@ void UpdateTransportGroupInventory() addItemToInventory(pSoldier, id, 1); break; + case FACE_ITEMS: + // low chance of face item + if (Random(100) < 50) + addItemToInventory(pSoldier, id, 1); + break; + case CAMO_KITS: addItemToInventory(pSoldier, id, 1); break; From cdaddcab499a93aff36a6295a102a6b0a610a237 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Mon, 3 Jul 2023 17:37:29 -0700 Subject: [PATCH 78/81] Properly populate transport groups moving into a sector where a battle is in progress --- Strategic/Queen Command.cpp | 15 ++++++++++----- Strategic/Strategic Movement.cpp | 8 ++++++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/Strategic/Queen Command.cpp b/Strategic/Queen Command.cpp index 04dbed610..074ef6c32 100644 --- a/Strategic/Queen Command.cpp +++ b/Strategic/Queen Command.cpp @@ -2184,6 +2184,16 @@ void AddEnemiesToBattle( GROUP *pGroup, UINT8 ubStrategicInsertionCode, UINT8 ub UINT8 ubTotalSoldiers; UINT8 bDesiredDirection=0; + // while transport groups can't normally reinforce, this covers the case where a transport group enters a sector (via normal movement) + // where a battle is in progress. + if (pGroup && pGroup->pEnemyGroup->ubIntention == TRANSPORT) + { + AddToTransportGroupMap(pGroup->ubGroupID, SOLDIER_CLASS_ADMINISTRATOR, ubNumAdmins); + AddToTransportGroupMap(pGroup->ubGroupID, SOLDIER_CLASS_ARMY, ubNumTroops); + AddToTransportGroupMap(pGroup->ubGroupID, SOLDIER_CLASS_ELITE, ubNumElites); + AddToTransportGroupMap(pGroup->ubGroupID, SOLDIER_CLASS_JEEP, ubNumJeeps); + } + switch( ubStrategicInsertionCode ) { case INSERTION_CODE_NORTH: bDesiredDirection = SOUTHEAST; break; @@ -2429,11 +2439,6 @@ void AddEnemiesToBattle( GROUP *pGroup, UINT8 ubStrategicInsertionCode, UINT8 ub UpdateMercInSector( pSoldier, gWorldSectorX, gWorldSectorY, 0 ); } - if (pGroup && pGroup->pEnemyGroup->ubIntention == TRANSPORT) - { - ScreenMsg(FONT_RED, MSG_INTERFACE, L"Transport group attempting to reinforce? This shouldn't happen!"); - } - // HEADROCK HAM 3.2: enemy reinforcements arrive with 0 APs. if (gGameExternalOptions.ubReinforcementsFirstTurnFreeze == 1 || gGameExternalOptions.ubReinforcementsFirstTurnFreeze == 2) { diff --git a/Strategic/Strategic Movement.cpp b/Strategic/Strategic Movement.cpp index d6d19b176..881783a18 100644 --- a/Strategic/Strategic Movement.cpp +++ b/Strategic/Strategic Movement.cpp @@ -50,6 +50,7 @@ #include "Creature Spreading.h" // added by Flugente #include "MilitiaIndividual.h" // added by Flugente #include "Rebel Command.h" + #include "Strategic Transport Groups.h" #include "MilitiaSquads.h" #include "Vehicles.h" @@ -3819,6 +3820,13 @@ void HandleArrivalOfReinforcements( GROUP *pGroup ) ResetMortarsOnTeamCount(); ResetNumSquadleadersInArmyGroup(); // added by SANDRO AddPossiblePendingEnemiesToBattle(); + + if (pGroup->pEnemyGroup->ubIntention == TRANSPORT) + { + // normally, transport groups can't reinforce, but this can be hit normally if a battle is occuring in a sector + // where a transport group is moving into. + UpdateTransportGroupInventory(); + } } else if ( pGroup->usGroupTeam == MILITIA_TEAM ) { From e46c2e06dd9d78f063f793db4aec95e42e21063d Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Mon, 3 Jul 2023 22:47:23 -0700 Subject: [PATCH 79/81] Update text --- Strategic/Map Screen Interface Map.cpp | 4 ++-- Utils/Text.h | 2 ++ Utils/_ChineseText.cpp | 2 ++ Utils/_DutchText.cpp | 2 ++ Utils/_EnglishText.cpp | 2 ++ Utils/_FrenchText.cpp | 2 ++ Utils/_GermanText.cpp | 2 ++ Utils/_ItalianText.cpp | 2 ++ Utils/_PolishText.cpp | 2 ++ Utils/_RussianText.cpp | 2 ++ 10 files changed, 20 insertions(+), 2 deletions(-) diff --git a/Strategic/Map Screen Interface Map.cpp b/Strategic/Map Screen Interface Map.cpp index 0be554827..b709c3a02 100644 --- a/Strategic/Map Screen Interface Map.cpp +++ b/Strategic/Map Screen Interface Map.cpp @@ -8596,11 +8596,11 @@ void DetermineMapIntelData( INT32 asSectorZ ) switch (iter.second) { case TransportGroupSectorInfo::TransportGroupSectorInfo_LocatedGroup: - swprintf( str, L"Transport group"); + swprintf( str, gpStrategicString[STR_PB_TRANSPORT_GROUP]); break; case TransportGroupSectorInfo::TransportGroupSectorInfo_LocatedDestination: - swprintf( str, L"Transport group en route"); + swprintf( str, gpStrategicString[STR_PB_TRANSPORT_GROUP_EN_ROUTE]); break; } AddIntelAndQuestMapDataForSector( SECTORX(iter.first), SECTORY(iter.first), MAP_SHADE_LT_YELLOW, -1, str, L"" ); diff --git a/Utils/Text.h b/Utils/Text.h index 74bd5f6b7..21037737a 100644 --- a/Utils/Text.h +++ b/Utils/Text.h @@ -1912,6 +1912,8 @@ enum STR_PB_ZOMBIE, STR_PB_BANDIT, STR_PB_BANDIT_KILLCIVS_IN_SECTOR, + STR_PB_TRANSPORT_GROUP, + STR_PB_TRANSPORT_GROUP_EN_ROUTE, TEXT_NUM_STRATEGIC_TEXT }; diff --git a/Utils/_ChineseText.cpp b/Utils/_ChineseText.cpp index a40e6e65b..2a943df5e 100644 --- a/Utils/_ChineseText.cpp +++ b/Utils/_ChineseText.cpp @@ -3568,6 +3568,8 @@ STR16 gpStrategicString[] = L"僵尸", //L"Zombie", L"土匪", //L"Bandit", L"土匪杀死了%d名平民,在%s分区。", //注:这里的%d和%s不可以随意放前面或后面,一定要按英文顺序,不然会出错。(%d和%s 在中文中不能反过来。) L"Bandits attack and kill %d civilians in sector %s.", + L"Transport group", + L"Transport group en route", }; STR16 gpGameClockString[] = diff --git a/Utils/_DutchText.cpp b/Utils/_DutchText.cpp index 01f5dc5a1..00abf9fcb 100644 --- a/Utils/_DutchText.cpp +++ b/Utils/_DutchText.cpp @@ -3568,6 +3568,8 @@ STR16 gpStrategicString[] = L"Zombie", L"Bandit", L"Bandits attack and kill %d civilians in sector %s.", + L"Transport group", + L"Transport group en route", }; STR16 gpGameClockString[] = diff --git a/Utils/_EnglishText.cpp b/Utils/_EnglishText.cpp index 2287339b7..5f4b9f5e7 100644 --- a/Utils/_EnglishText.cpp +++ b/Utils/_EnglishText.cpp @@ -3568,6 +3568,8 @@ STR16 gpStrategicString[] = L"Zombie", L"Bandit", L"Bandits attack and kill %d civilians in sector %s.", + L"Transport group", + L"Transport group en route", }; STR16 gpGameClockString[] = diff --git a/Utils/_FrenchText.cpp b/Utils/_FrenchText.cpp index 77a9555db..f97f68de8 100644 --- a/Utils/_FrenchText.cpp +++ b/Utils/_FrenchText.cpp @@ -3576,6 +3576,8 @@ STR16 gpStrategicString[] = L"Zombie", L"Bandit", L"Bandits attack and kill %d civilians in sector %s.", + L"Transport group", + L"Transport group en route", }; STR16 gpGameClockString[] = diff --git a/Utils/_GermanText.cpp b/Utils/_GermanText.cpp index aef070dfe..0e86f7f69 100644 --- a/Utils/_GermanText.cpp +++ b/Utils/_GermanText.cpp @@ -3605,6 +3605,8 @@ STR16 gpStrategicString[] = L"Zombie", L"Bandit", L"Bandits attack and kill %d civilians in sector %s.", + L"Transport group", + L"Transport group en route", }; STR16 gpGameClockString[] = diff --git a/Utils/_ItalianText.cpp b/Utils/_ItalianText.cpp index 43628a067..272ff9da7 100644 --- a/Utils/_ItalianText.cpp +++ b/Utils/_ItalianText.cpp @@ -3563,6 +3563,8 @@ STR16 gpStrategicString[] = L"Zombie", L"Bandit", L"Bandits attack and kill %d civilians in sector %s.", + L"Transport group", + L"Transport group en route", }; STR16 gpGameClockString[] = diff --git a/Utils/_PolishText.cpp b/Utils/_PolishText.cpp index e1af6f578..35548ba15 100644 --- a/Utils/_PolishText.cpp +++ b/Utils/_PolishText.cpp @@ -3574,6 +3574,8 @@ STR16 gpStrategicString[] = L"Zombie", L"Bandit", L"Bandits attack and kill %d civilians in sector %s.", + L"Transport group", + L"Transport group en route", }; STR16 gpGameClockString[] = diff --git a/Utils/_RussianText.cpp b/Utils/_RussianText.cpp index 28258c62b..0345b8301 100644 --- a/Utils/_RussianText.cpp +++ b/Utils/_RussianText.cpp @@ -3568,6 +3568,8 @@ STR16 gpStrategicString[] = L"Zombie", L"Bandit", L"Bandits attack and kill %d civilians in sector %s.", + L"Transport group", + L"Transport group en route", }; STR16 gpGameClockString[] = From 44c3c6809b1bfa83ad3262bcc2d486e385ea84d9 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Tue, 4 Jul 2023 00:00:10 -0700 Subject: [PATCH 80/81] Remove pragma --- Strategic/Strategic Transport Groups.cpp | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index a180b7a4b..4451b5a67 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -1,4 +1,4 @@ -#pragma optimize("",off) +//#pragma optimize("",off) /* Strategic Transport Groups by rftr @@ -444,7 +444,6 @@ void UpdateTransportGroupInventory() BACKPACKS, RADIOS, ATTACHMENTS, - FACE_ITEMS, CAMO_KITS, MISC, GRENADE_THROWN, @@ -508,7 +507,6 @@ void UpdateTransportGroupInventory() itemMap[BACKPACKS].push_back(i); } } - else if (Item[i].usItemClass & IC_FACE) itemMap[FACE_ITEMS].push_back(i); else if (Item[i].camouflagekit) itemMap[CAMO_KITS].push_back(i); else if (Item[i].usItemClass & IC_MISC) { @@ -716,10 +714,6 @@ void UpdateTransportGroupInventory() } break; - case FACE_ITEMS: - addItemToInventory(pSoldier, id, 5); - break; - case CAMO_KITS: addItemToInventory(pSoldier, id, 6); break; @@ -823,12 +817,6 @@ void UpdateTransportGroupInventory() addItemToInventory(pSoldier, id, 1); break; - case FACE_ITEMS: - // low chance of face item - if (Random(100) < 50) - addItemToInventory(pSoldier, id, 1); - break; - case CAMO_KITS: addItemToInventory(pSoldier, id, 1); break; From 954c439a94da35e142c6a3acc8b230815195aa56 Mon Sep 17 00:00:00 2001 From: rftrdev <102184004+rftrdev@users.noreply.github.com> Date: Tue, 4 Jul 2023 23:16:43 -0700 Subject: [PATCH 81/81] Fix forged group not actually moving --- Strategic/Strategic Transport Groups.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Strategic/Strategic Transport Groups.cpp b/Strategic/Strategic Transport Groups.cpp index 4451b5a67..f8e19dab2 100644 --- a/Strategic/Strategic Transport Groups.cpp +++ b/Strategic/Strategic Transport Groups.cpp @@ -157,6 +157,22 @@ BOOLEAN ForceDeployTransportGroup(UINT8 sectorId) const UINT8 progress = min(125, HighestPlayerProgressPercentage() + recentLossCount * 5); const UINT8 difficulty = gGameOptions.ubDifficultyLevel; PopulateTransportGroup(admins, troops, elites, jeeps, tanks, robots, progress, difficulty, FALSE); + + // varying transport group quality/compositions + GROUP* pGroup = CreateNewEnemyGroupDepartingFromSector( SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), admins, troops, elites, robots, tanks, jeeps ); + + //Madd: unlimited reinforcements? + if ( !gfUnlimitedTroops ) + { + giReinforcementPool -= (admins + troops + elites + robots + jeeps + tanks); + + giReinforcementPool = max( giReinforcementPool, 0 ); + } + + MoveSAIGroupToSector( &pGroup, sectorId, EVASIVE, TRANSPORT ); + + pGroup->uiFlags |= GROUPFLAG_TRANSPORT_ENROUTE; + return TRUE; }