diff --git a/GameSettings.cpp b/GameSettings.cpp index a130d2e9..265a1982 100644 --- a/GameSettings.cpp +++ b/GameSettings.cpp @@ -4180,6 +4180,18 @@ void LoadRebelCommandSettings() gRebelCommandSettings.iDeepDeploymentDuration_Bonus_Stealthy = iniReader.ReadInteger("Rebel Command Settings", "DEEP_DEPLOYMENT_DURATION_BONUS_STEALTHY" , 36, 0, 255); gRebelCommandSettings.iDeepDeploymentDuration_Bonus_Survival = iniReader.ReadInteger("Rebel Command Settings", "DEEP_DEPLOYMENT_DURATION_BONUS_SURVIVAL" , 36, 0, 255); + gRebelCommandSettings.iDisruptAsdSuccessChance = iniReader.ReadInteger("Rebel Command Settings", "DISRUPT_ASD_SUCCESS_CHANCE", 50, 0, 100); + gRebelCommandSettings.fDisruptAsdIncomeReductionModifier = iniReader.ReadFloat("Rebel Command Settings", "DISRUPT_ASD_INCOME_MODIFIER", 0.5f, 0.f, 1.f); + gRebelCommandSettings.fDisruptAsdIncomeReductionModifier_Covert = iniReader.ReadFloat("Rebel Command Settings", "DISRUPT_ASD_INCOME_MODIFIER_COVERT", 0.5f, 0.f, 1.f); + gRebelCommandSettings.fDisruptAsdIncomeReductionModifier_Demolitions = iniReader.ReadFloat("Rebel Command Settings", "DISRUPT_ASD_INCOME_MODIFIER_DEMOLITIONS", 0.5f, 0.f, 1.f); + gRebelCommandSettings.fDisruptAsdIncomeReductionModifier_Nightops = iniReader.ReadFloat("Rebel Command Settings", "DISRUPT_ASD_INCOME_MODIFIER_NIGHTOPS", 0.5f, 0.f, 1.f); + gRebelCommandSettings.fDisruptAsdIncomeReductionModifier_Technician = iniReader.ReadFloat("Rebel Command Settings", "DISRUPT_ASD_INCOME_MODIFIER_TECHNICIAN", 0.5f, 0.f, 1.f); + gRebelCommandSettings.iDisruptAsdDuration = iniReader.ReadInteger("Rebel Command Settings", "DISRUPT_ASD_DURATION", 72, 0, 255); + gRebelCommandSettings.iDisruptAsdDuration_Bonus_Covert = iniReader.ReadInteger("Rebel Command Settings", "DISRUPT_ASD_DURATION_BONUS_COVERT", 48, 0, 255); + gRebelCommandSettings.iDisruptAsdDuration_Bonus_Demolitions = iniReader.ReadInteger("Rebel Command Settings", "DISRUPT_ASD_DURATION_BONUS_DEMOLITIONS", 48, 0, 255); + 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.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 0f302a87..61989eb3 100644 --- a/GameSettings.h +++ b/GameSettings.h @@ -1865,6 +1865,18 @@ typedef struct UINT8 iDeepDeploymentDuration_Bonus_Stealthy; UINT8 iDeepDeploymentDuration_Bonus_Survival; + INT8 iDisruptAsdSuccessChance; + FLOAT fDisruptAsdIncomeReductionModifier; + FLOAT fDisruptAsdIncomeReductionModifier_Covert; + FLOAT fDisruptAsdIncomeReductionModifier_Demolitions; + FLOAT fDisruptAsdIncomeReductionModifier_Nightops; + FLOAT fDisruptAsdIncomeReductionModifier_Technician; + UINT8 iDisruptAsdDuration; + UINT8 iDisruptAsdDuration_Bonus_Covert; + UINT8 iDisruptAsdDuration_Bonus_Demolitions; + UINT8 iDisruptAsdDuration_Bonus_Nightops; + UINT8 iDisruptAsdDuration_Bonus_Technician; + INT8 iGetEnemyMovementTargetsSuccessChance; UINT8 iGetEnemyMovementTargetsDuration; UINT8 iGetEnemyMovementTargetsDuration_Bonus_Covert; diff --git a/Strategic/ASD.cpp b/Strategic/ASD.cpp index 84c67085..6d5861de 100644 --- a/Strategic/ASD.cpp +++ b/Strategic/ASD.cpp @@ -52,6 +52,7 @@ #include "Sound Control.h" #include "renderworld.h" #include "Isometric Utils.h" +#include "Rebel Command.h" #endif @@ -548,9 +549,22 @@ UINT32 ASDResourceCostMoney( UINT8 aType ) return gGameExternalOptions.gASDResource_Cost[aType]; } +INT32 GetStrategicAIResourceCount( UINT8 aType ) +{ + if (aType < 0 || aType >= ASD_RESOURCE_MAX) + return 0; + + return gASDResource[aType]; +} + // add resources to the AIs resource pool void AddStrategicAIResources( UINT8 aType, INT32 aAmount ) { + if (aType == ASD_MONEY) + { + aAmount *= RebelCommand::GetASDIncomeModifier(); + } + gASDResource[aType] = max( 0, gASDResource[aType] + aAmount ); if ( aType == ASD_HELI ) diff --git a/Strategic/ASD.h b/Strategic/ASD.h index 0b786fbe..62cd5b18 100644 --- a/Strategic/ASD.h +++ b/Strategic/ASD.h @@ -56,6 +56,8 @@ void SetASDFlag( UINT32 aFlag ); UINT32 ASDResourceDeliveryTime( UINT8 aType ); UINT32 ASDResourceCostMoney( UINT8 aType ); +INT32 GetStrategicAIResourceCount( UINT8 aType ); + // add resources to the AIs resource pool void AddStrategicAIResources( UINT8 aType, INT32 aAmount ); diff --git a/Strategic/Rebel Command.cpp b/Strategic/Rebel Command.cpp index 57114ecb..9997934b 100644 --- a/Strategic/Rebel Command.cpp +++ b/Strategic/Rebel Command.cpp @@ -63,6 +63,7 @@ Points of interest: #else #include "Rebel Command.h" +#include "ASD.h" #include "Button System.h" #include "Campaign.h" #include "Campaign Types.h" @@ -95,6 +96,8 @@ Points of interest: #include "Strategic Mines.h" #include "Strategic Movement.h" #include "Strategic Town Loyalty.h" +#include "Structure Wrap.h" +#include "Tactical Save.h" #include "Text.h" #include "Town Militia.h" #include "Utilities.h" @@ -125,12 +128,36 @@ extern GROUP *gpGroupList; namespace RebelCommand { +namespace ItemIdCache +{ + // cache these values on load so that we don't need to search for them every time something happens + std::vector gasCans; + std::vector firstAidKits; + std::vector medKits; + std::vector toolKits; + std::vector ammo[10]; // coolness + + void Clear() + { + gasCans.clear(); + firstAidKits.clear(); + medKits.clear(); + toolKits.clear(); + for (int i = 0; i < 10; ++i) + { + ammo[i].clear(); + } + } +} + namespace MissionHelpers { constexpr UINT16 DEEP_DEPLOYMENT_RANGE_BONUS_COVERT = 1; constexpr UINT16 DEEP_DEPLOYMENT_RANGE_BONUS_SCOUTING = 2; constexpr UINT16 DEEP_DEPLOYMENT_RANGE_BONUS_STEALTHY = 3; constexpr UINT16 DEEP_DEPLOYMENT_RANGE_BONUS_SURVIVAL = 4; +constexpr UINT16 DISRUPT_ASD_STEAL_FUEL = 1; +constexpr UINT16 DISRUPT_ASD_DESTROY_RESERVES = 2; constexpr UINT16 REDUCE_STRATEGIC_DECISION_SPEED_MODIFIER_COVERT = 1; constexpr UINT16 REDUCE_STRATEGIC_DECISION_SPEED_MODIFIER_DEPUTY = 2; constexpr UINT16 REDUCE_STRATEGIC_DECISION_SPEED_MODIFIER_SNITCH = 3; @@ -310,6 +337,9 @@ enum RebelCommandText // keep this synced with szRebelCommandText in the text fi RCT_MISSION_AGENT_BONUS, RCT_MISSION_BONUS_SUCCESS_CHANCE, RCT_MISSION_BONUS_DEPLOY_RANGE, + RCT_MISSION_BONUS_ASD_INCOME_REDUCTION, + RCT_MISSION_BONUS_STEAL_FUEL, + RCT_MISSION_BONUS_DESTROY_RESERVES, RCT_MISSION_BONUS_DECISION_TIME, RCT_MISSION_BONUS_UNALERTED_VISION_PENALTY, RCT_MISSION_BONUS_INFANTRY_GEAR_QUALITY, @@ -377,6 +407,7 @@ enum RebelCommandDirectivesText // keep this synced with szRebelCommandDirective enum RebelCommandAgentMissionsText // keep this synced with szRebelCommandAgentMissionsText in the text files { MISSION_TEXT(DEEP_DEPLOYMENT) + MISSION_TEXT(DISRUPT_ASD) MISSION_TEXT(GET_ENEMY_MOVEMENT_TARGETS) MISSION_TEXT(IMPROVE_LOCAL_SHOPS) MISSION_TEXT(REDUCE_STRATEGIC_DECISION_SPEED) @@ -507,8 +538,10 @@ void PrepareMission(INT8 index); void ToggleWebsiteView(); void UpdateAdminActionChangeList(INT16 regionId); +void ApplyAdditionalASDEffects(); constexpr BOOLEAN CanAdminActionBeToggled(RebelCommandAdminActions action) { return action != RebelCommandAdminActions::RCAA_SUPPLY_LINE; } BOOLEAN CanAdminActionBeUsed(INT32 regionIndex, INT32 actionIndex); +void CreateItemAtAirport(UINT16 itemId, INT16 status); INT32 GetAdminActionCostForRegion(INT16 regionId); INT16 GetAdminActionInRegion(INT16 regionId, RebelCommandAdminActions adminAction); UINT8 GetRegionLoyalty(INT16 regionId); @@ -538,7 +571,6 @@ INT16 iCurrentRegionId = 1; INT32 iIncomingSuppliesPerDay = 0; SaveInfo rebelCommandSaveInfo; WebsiteState websiteState; -//INT8 missionIndex[NUM_ARC_AGENT_SLOTS]; INT8 agentIndex[NUM_ARC_AGENT_SLOTS]; std::unordered_map missionMap; MissionOverviewSubview missionOverviewSubview = MOS_MISSION_LIST; @@ -688,6 +720,29 @@ BOOLEAN CanAdminActionBeUsed(INT32 regionIndex, INT32 actionIndex) return TRUE; } +void CreateItemAtAirport(UINT16 itemId, INT16 status) +{ + // create an item - use bobby ray's delivery coordinates/gridno + OBJECTTYPE obj; + const BOOLEAN success = CreateItem(itemId, status, &obj); + if (!success) + { + ScreenMsg(FONT_MCOLOR_RED, MSG_INTERFACE, L"Warning - CreateItemAtAirport() failed for itemid %d", itemId); + return; + } + const BOOLEAN airportSectorLoaded = gWorldSectorX == BOBBYR_SHIPPING_DEST_SECTOR_X && gWorldSectorY == BOBBYR_SHIPPING_DEST_SECTOR_Y && gbWorldSectorZ == BOBBYR_SHIPPING_DEST_SECTOR_Z; + + if (airportSectorLoaded) + { + SetOpenableStructureToClosed( BOBBYR_SHIPPING_DEST_GRIDNO, 0 ); + AddItemToPool( BOBBYR_SHIPPING_DEST_GRIDNO, &obj, -1, 0, 0, 0 ); + } + else + { + AddItemsToUnLoadedSector(BOBBYR_SHIPPING_DEST_SECTOR_X, BOBBYR_SHIPPING_DEST_SECTOR_Y, BOBBYR_SHIPPING_DEST_SECTOR_Z, BOBBYR_SHIPPING_DEST_GRIDNO, 1, &obj, 0, 0, 0, -1, FALSE); + } +} + INT32 GetAdminActionCostForRegion(INT16 regionId) { INT16 totalLocalActions = 0; @@ -1165,6 +1220,8 @@ void UpdateAdminActionChangeList(INT16 regionId) BOOLEAN EnterWebsite() { + // rftr todo: temp debugging + rebelCommandSaveInfo.availableMissions[0] = RCAM_DISRUPT_ASD; UpdateAdminActionChangeList(iCurrentRegionId); // make sure we have a valid directive @@ -2165,6 +2222,7 @@ BOOLEAN SetupMissionAgentBox(UINT16 x, UINT16 y, INT8 index) switch (rebelCommandSaveInfo.availableMissions[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_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; @@ -2183,6 +2241,7 @@ BOOLEAN SetupMissionAgentBox(UINT16 x, UINT16 y, INT8 index) switch (rebelCommandSaveInfo.availableMissions[index]) { case RCAM_DEEP_DEPLOYMENT: missionDurationBase = gRebelCommandSettings.iDeepDeploymentDuration; break; + case RCAM_DISRUPT_ASD: missionDurationBase = gRebelCommandSettings.iDisruptAsdDuration; break; 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; @@ -2204,6 +2263,7 @@ BOOLEAN SetupMissionAgentBox(UINT16 x, UINT16 y, INT8 index) switch (rebelCommandSaveInfo.availableMissions[index]) { case RCAM_DEEP_DEPLOYMENT: missionSuccessChanceBase = gRebelCommandSettings.iDeepDeploymentSuccessChance; break; + case RCAM_DISRUPT_ASD: missionSuccessChanceBase = gRebelCommandSettings.iDisruptAsdSuccessChance; 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; @@ -2222,6 +2282,7 @@ BOOLEAN SetupMissionAgentBox(UINT16 x, UINT16 y, INT8 index) switch (rebelCommandSaveInfo.availableMissions[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_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; @@ -2361,6 +2422,36 @@ BOOLEAN SetupMissionAgentBox(UINT16 x, UINT16 y, INT8 index) } break; + case RCAM_DISRUPT_ASD: + { + CHAR16 text[100]; + floatModifier = max(floatModifier, gRebelCommandSettings.fDisruptAsdIncomeReductionModifier); + floatModifier *= 100.f; + swprintf(text, szRebelCommandText[RCT_MISSION_BONUS_ASD_INCOME_REDUCTION], floatModifier, L"%s", locSkillText[floatModifierSkill]); + agentBonusText.push_back(text); + + if (gGameOptions.fNewTraitSystem) + { + switch (extraBits) + { + case MissionHelpers::DISRUPT_ASD_STEAL_FUEL: + { + const UINT8 townId = GetTownIdForSector(BOBBYR_SHIPPING_DEST_SECTOR_X, BOBBYR_SHIPPING_DEST_SECTOR_Y); + swprintf(text, szRebelCommandText[RCT_MISSION_BONUS_STEAL_FUEL], pTownNames[townId], locSkillText[TECHNICIAN_NT]); + agentBonusText.push_back(text); + } + break; + + case MissionHelpers::DISRUPT_ASD_DESTROY_RESERVES: + { + swprintf(text, szRebelCommandText[RCT_MISSION_BONUS_DESTROY_RESERVES], locSkillText[DEMOLITIONS_NT]); + agentBonusText.push_back(text); + } + break; + } + } + } + case RCAM_GET_ENEMY_MOVEMENT_TARGETS: { // no special modifiers. included for completeness. @@ -2727,6 +2818,14 @@ void PrepareMission(INT8 index) } break; + case RCAM_DISRUPT_ASD: + { + missionTitle = RCAMT_DISRUPT_ASD_TITLE; + missionSuccessChance = gRebelCommandSettings.iDisruptAsdSuccessChance; + missionDuration = gRebelCommandSettings.iDisruptAsdDuration; + } + break; + case RCAM_GET_ENEMY_MOVEMENT_TARGETS: { missionTitle = RCAMT_GET_ENEMY_MOVEMENT_TARGETS_TITLE; @@ -3759,12 +3858,16 @@ void DailyUpdate() rebelCommandSaveInfo.cachedBountyPayout = 0; } + // RCAM_DISRUPT_ASD + ApplyAdditionalASDEffects(); + if (GetWorldDay() % gRebelCommandSettings.iMissionRefreshTimeDays == 0) { std::unordered_set validMissions; for (int i = 0; i < RCAM_NUM_MISSIONS; ++i) { 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; validMissions.insert(static_cast(i)); } @@ -4129,6 +4232,7 @@ void SetupInfo() aa.fValue3 = 0.f; info.adminActions.insert(info.adminActions.begin() + RCAA_FORTIFICATIONS, aa); + // rftr todo: this should really be a map... but as long as we insert mission info in the same order as the enum then we're good MissionHelpers::missionInfo.clear(); // example format // { @@ -4149,6 +4253,16 @@ void SetupInfo() {gRebelCommandSettings.iDeepDeploymentRangeEW_Bonus_Covert, gRebelCommandSettings.iDeepDeploymentRangeEW_Bonus_Scouting, gRebelCommandSettings.iDeepDeploymentRangeEW_Bonus_Stealthy, gRebelCommandSettings.iDeepDeploymentRangeEW_Bonus_Survival}, {MissionHelpers::DEEP_DEPLOYMENT_RANGE_BONUS_COVERT, MissionHelpers::DEEP_DEPLOYMENT_RANGE_BONUS_SCOUTING, MissionHelpers::DEEP_DEPLOYMENT_RANGE_BONUS_STEALTHY, MissionHelpers::DEEP_DEPLOYMENT_RANGE_BONUS_SURVIVAL} }); + //RCAM_DISRUPT_ASD + MissionHelpers::missionInfo.push_back( + { + {COVERT_NT, TECHNICIAN_NT, DEMOLITIONS_NT, NIGHT_OPS_NT}, + {-1, -1, -1, NIGHTOPS_OT}, + {gRebelCommandSettings.iDisruptAsdDuration_Bonus_Covert, gRebelCommandSettings.iDisruptAsdDuration_Bonus_Technician, gRebelCommandSettings.iDisruptAsdDuration_Bonus_Demolitions, gRebelCommandSettings.iDisruptAsdDuration_Bonus_Nightops}, + {gRebelCommandSettings.fDisruptAsdIncomeReductionModifier_Covert, gRebelCommandSettings.fDisruptAsdIncomeReductionModifier_Technician, gRebelCommandSettings.fDisruptAsdIncomeReductionModifier_Technician, gRebelCommandSettings.fDisruptAsdIncomeReductionModifier_Nightops}, + {0, 0, 0, 0}, + {0, MissionHelpers::DISRUPT_ASD_STEAL_FUEL, MissionHelpers::DISRUPT_ASD_DESTROY_RESERVES, 0} + }); //RCAM_GET_ENEMY_MOVEMENT_TARGETS MissionHelpers::missionInfo.push_back( { @@ -4207,7 +4321,7 @@ void SetupInfo() {-1, -1, -1, -1}, {gRebelCommandSettings.iSoldierBountiesKingpinDuration_Bonus_Covert, 0, 0, gRebelCommandSettings.iSoldierBountiesKingpinDuration_Bonus_Demolitions}, {gRebelCommandSettings.fSoldierBountiesKingpinPayout_Bonus_Covert, gRebelCommandSettings.fSoldierBountiesKingpinPayout_Bonus_Deputy, gRebelCommandSettings.fSoldierBountiesKingpinPayout_Bonus_Snitch, 1.f}, - {0, 0, gRebelCommandSettings.iSoldierBountiesKingpinPayout_Limit_Snitch, gRebelCommandSettings.iSoldierBountiesKingpinPayout_Limit_Demolitions}, + {0, 0, gRebelCommandSettings.iSoldierBountiesKingpinPayout_Limit_Snitch, gRebelCommandSettings.iSoldierBountiesKingpinPayout_Limit_Demolitions}, {0, MissionHelpers::SOLDIER_BOUNTIES_KINGPIN_OFFICER_PAYOUTS, 0, MissionHelpers::SOLDIER_BOUNTIES_KINGPIN_VEHICLE_PAYOUTS} }); //RCAM_TRAIN_MILITIA_ANYWHERE @@ -4220,6 +4334,30 @@ void SetupInfo() {gRebelCommandSettings.iTrainMilitiaAnywhereMaxTrainers, gRebelCommandSettings.iTrainMilitiaAnywhereMaxTrainers, gRebelCommandSettings.iTrainMilitiaAnywhereMaxTrainers_Teaching}, {0, 0, MissionHelpers::TRAIN_MILITIA_ANYWHERE_TEACHING} }); + + // cache item IDs + ItemIdCache::Clear(); + // (Item[i].usItemClass & IC_AMMO) && (Magazine[ Item[i].ubClassIndex ].ubMagType == AMMO_BOX or AMMO_CRATE?) + for (UINT16 i = 0; i < MAXITEMS; ++i) + { + if (Item[i].gascan) ItemIdCache::gasCans.push_back(i); + else if (Item[i].firstaidkit) ItemIdCache::firstAidKits.push_back(i); + else if (Item[i].medicalkit) ItemIdCache::medKits.push_back(i); + else if (Item[i].toolkit) ItemIdCache::toolKits.push_back(i); + else if (Item[i].usItemClass & IC_AMMO) + { + if (Magazine[Item[i].ubClassIndex].ubMagType == AMMO_BOX) + { + if ((gGameOptions.fGunNut || !Item[i].biggunlist) + && (gGameOptions.ubGameStyle == STYLE_SCIFI || !Item[i].scifi)) + { + // coolness runs from 1-10, so apply offset + ItemIdCache::ammo[Item[i].ubCoolness-1].push_back(i); + } + } + } + + } } void UpgradeMilitiaStats() @@ -4490,6 +4628,82 @@ INT16 GetAdditionalDeployRange(const UINT8 insertionCode) return 0; } +FLOAT GetASDIncomeModifier() +{ + if (!gGameExternalOptions.fRebelCommandEnabled) + return 1.f; + + const std::unordered_map::iterator iter = missionMap.find(RCAM_DISRUPT_ASD); + + if (iter == missionMap.end()) + return 1.f; + + MissionSecondEvent evt; + DeserialiseMissionSecondEvent(iter->second, evt); + + if (evt.isSecondEvent) + { + const MERCPROFILESTRUCT* merc = &gMercProfiles[evt.mercProfileId]; + UINT32 durationBonus; + FLOAT floatModifier; + INT16 intModifier; + int durSkill; + int floatSkill; + int intSkill; + UINT16 extraBits; + MissionHelpers::GetMissionInfo(RCAM_DISRUPT_ASD, merc, durationBonus, floatModifier, intModifier, durSkill, floatSkill, intSkill, extraBits); + + return 1.f - floatModifier; + } + + return 1.f; +} + +void ApplyAdditionalASDEffects() +{ + if (!gGameExternalOptions.fRebelCommandEnabled) + return; + + const std::unordered_map::iterator iter = missionMap.find(RCAM_DISRUPT_ASD); + + if (iter == missionMap.end()) + return; + + MissionSecondEvent evt; + DeserialiseMissionSecondEvent(iter->second, evt); + + if (evt.isSecondEvent) + { + switch (evt.extraBits) + { + case MissionHelpers::DISRUPT_ASD_STEAL_FUEL: + { + // spawn a gas can + CreateItemAtAirport(ItemIdCache::gasCans.at(ItemIdCache::gasCans.size()), 75 + Random(26)); + + // say it came from the ASD's reserves + AddStrategicAIResources(ASD_FUEL, gGameExternalOptions.gASDResource_Fuel_Jeep + Random(gGameExternalOptions.gASDResource_Fuel_Jeep)); + } + break; + + case MissionHelpers::DISRUPT_ASD_DESTROY_RESERVES: + { + // priority: tank > jeep > robots + if (GetStrategicAIResourceCount(ASD_TANK) > 0) + AddStrategicAIResources(ASD_TANK, 1 + Random(2)); + else if (GetStrategicAIResourceCount(ASD_JEEP) > 0) + AddStrategicAIResources(ASD_JEEP, 1 + Random(2)); + else if (GetStrategicAIResourceCount(ASD_ROBOT) > 0) + AddStrategicAIResources(ASD_ROBOT, 2 + Random(3)); + + // let's also try to destroy a good amount of fuel + AddStrategicAIResources(ASD_FUEL, gGameExternalOptions.gASDResource_Fuel_Tank + Random(gGameExternalOptions.gASDResource_Fuel_Tank)); + } + break; + } + } +} + INT8 GetEnemyEquipmentCoolnessModifier() { if (!gGameExternalOptions.fRebelCommandEnabled) @@ -4633,6 +4847,7 @@ void HandleStrategicEvent(const UINT32 eventParam) switch (mission) { case RCAM_DEEP_DEPLOYMENT: + case RCAM_DISRUPT_ASD: 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 4ce6e04e..690d165d 100644 --- a/Strategic/Rebel Command.h +++ b/Strategic/Rebel Command.h @@ -89,6 +89,7 @@ enum RebelCommandAgentMissions { RCAM_NONE = -1, RCAM_DEEP_DEPLOYMENT = 0, + RCAM_DISRUPT_ASD, // only available if ASD enabled RCAM_GET_ENEMY_MOVEMENT_TARGETS, // aka Strategic Intel RCAM_IMPROVE_LOCAL_SHOPS, RCAM_REDUCE_STRATEGIC_DECISION_SPEED, // aka Slower Strategic Decisions @@ -101,13 +102,12 @@ enum RebelCommandAgentMissions RCAM_NUM_MISSIONS, // ideas/unimplemented - RCAM_SEND_SUPPLIES_TO_TOWN, - RCAM_BOOST_TOWN_ADMIN_ACTIONS, + RCAM_SEND_SUPPLIES_TO_TOWN, // store agent location townid in extrabits + RCAM_BOOST_TOWN_ADMIN_ACTIONS, // store agent location townid in extrabits RCAM_PROCURE_ITEMS, RCAM_MILITIA_SKILL_TRAITS, // should override militia skill traits ini option - split into multiple (weapon spec, bodybuilding, athletic, night ops) RCAM_OBSERVE_SECTORS, // ??? competes with scouts? RCAM_PURCHASE_SUPPLIES, // increase daily supply income, decrease daily $ income - RCAM_SABOTAGE_ASD, // see ASD.cpp for things that can be played with RCAM_SABOTAGE_MINE, RCAM_REDUCE_ENEMY_POOL, // need to make sure enemy pool is not infinite // giReinforcementPool, also gfUnlimitedTroops = zDiffSetting[gGameOptions.ubDifficultyLevel].bUnlimitedPoolOfTroops; // militia/mercs get bonus vision (???) @@ -223,6 +223,7 @@ BOOLEAN CanAssignTraitsToMilitia(); BOOLEAN CanTrainMilitiaAnywhere(); UINT8 GetMaxTrainersForTrainMilitiaAnywhere(); INT16 GetAdditionalDeployRange(const UINT8 insertionCode); +FLOAT GetASDIncomeModifier(); INT8 GetEnemyEquipmentCoolnessModifier(); INT8 GetEnemyEquipmentStatusModifier(const INT8 initialStatus); UINT8 GetMerchantCoolnessBonus(); diff --git a/Utils/_ChineseText.cpp b/Utils/_ChineseText.cpp index bc67a3ce..173f0396 100644 --- a/Utils/_ChineseText.cpp +++ b/Utils/_ChineseText.cpp @@ -11948,6 +11948,9 @@ STR16 szRebelCommandText[] = L"Agent bonus:", L"Chance of success +%d%s (%s)", L"Deployment range +%d (%s)", + L"ASD Income -%2.0f%s (%s)", + L"Steal fuel; send to %s (%s)", + L"Destroy reserve units (%s)", L"Time +%2.0f%s (%s)", L"Vision -%2.0f%s (%s)", L"Gear quality -%d (%s)", @@ -12085,6 +12088,8 @@ STR16 szRebelCommandAgentMissionsText[] = { L"Deep Deployment", 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"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/_DutchText.cpp b/Utils/_DutchText.cpp index 35bbac4f..fc0ecb03 100644 --- a/Utils/_DutchText.cpp +++ b/Utils/_DutchText.cpp @@ -11958,6 +11958,9 @@ STR16 szRebelCommandText[] = // TODO.Translate L"Agent bonus:", L"Chance of success +%d%s (%s)", L"Deployment range +%d (%s)", + L"ASD Income -%2.0f%s (%s)", + L"Steal fuel; send to %s (%s)", + L"Destroy reserve units (%s)", L"Time +%2.0f%s (%s)", L"Vision -%2.0f%s (%s)", L"Gear quality -%d (%s)", @@ -12095,6 +12098,8 @@ STR16 szRebelCommandAgentMissionsText[] = { L"Deep Deployment", 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"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 331bae0d..e674df57 100644 --- a/Utils/_EnglishText.cpp +++ b/Utils/_EnglishText.cpp @@ -11948,6 +11948,9 @@ STR16 szRebelCommandText[] = L"Agent bonus:", L"Chance of success +%d%s (%s)", L"Deployment range +%d (%s)", + L"ASD Income -%2.0f%s (%s)", + L"Steal fuel; send to %s (%s)", + L"Destroy reserve units (%s)", L"Time +%2.0f%s (%s)", L"Vision -%2.0f%s (%s)", L"Gear quality -%d (%s)", @@ -12085,6 +12088,8 @@ STR16 szRebelCommandAgentMissionsText[] = { L"Deep Deployment", 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"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 a04b38db..09495aa3 100644 --- a/Utils/_FrenchText.cpp +++ b/Utils/_FrenchText.cpp @@ -11940,6 +11940,9 @@ STR16 szRebelCommandText[] = // TODO.Translate L"Agent bonus:", L"Chance of success +%d%s (%s)", L"Deployment range +%d (%s)", + L"ASD Income -%2.0f%s (%s)", + L"Steal fuel; send to %s (%s)", + L"Destroy reserve units (%s)", L"Time +%2.0f%s (%s)", L"Vision -%2.0f%s (%s)", L"Gear quality -%d (%s)", @@ -12077,6 +12080,8 @@ STR16 szRebelCommandAgentMissionsText[] = { L"Deep Deployment", 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"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 576d94cc..1d78a540 100644 --- a/Utils/_GermanText.cpp +++ b/Utils/_GermanText.cpp @@ -11862,6 +11862,9 @@ STR16 szRebelCommandText[] = // TODO.Translate L"Agent bonus:", L"Chance of success +%d%s (%s)", L"Deployment range +%d (%s)", + L"ASD Income -%2.0f%s (%s)", + L"Steal fuel; send to %s (%s)", + L"Destroy reserve units (%s)", L"Time +%2.0f%s (%s)", L"Vision -%2.0f%s (%s)", L"Gear quality -%d (%s)", @@ -11999,6 +12002,8 @@ STR16 szRebelCommandAgentMissionsText[] = { L"Deep Deployment", 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"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 321075a2..0cdff8f3 100644 --- a/Utils/_ItalianText.cpp +++ b/Utils/_ItalianText.cpp @@ -11949,6 +11949,9 @@ STR16 szRebelCommandText[] = // TODO.Translate L"Agent bonus:", L"Chance of success +%d%s (%s)", L"Deployment range +%d (%s)", + L"ASD Income -%2.0f%s (%s)", + L"Steal fuel; send to %s (%s)", + L"Destroy reserve units (%s)", L"Time +%2.0f%s (%s)", L"Vision -%2.0f%s (%s)", L"Gear quality -%d (%s)", @@ -12086,6 +12089,8 @@ STR16 szRebelCommandAgentMissionsText[] = { L"Deep Deployment", 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"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 958d425c..1ffca3ec 100644 --- a/Utils/_PolishText.cpp +++ b/Utils/_PolishText.cpp @@ -11962,6 +11962,9 @@ STR16 szRebelCommandText[] = // TODO.Translate L"Agent bonus:", L"Chance of success +%d%s (%s)", L"Deployment range +%d (%s)", + L"ASD Income -%2.0f%s (%s)", + L"Steal fuel; send to %s (%s)", + L"Destroy reserve units (%s)", L"Time +%2.0f%s (%s)", L"Vision -%2.0f%s (%s)", L"Gear quality -%d (%s)", @@ -12099,6 +12102,8 @@ STR16 szRebelCommandAgentMissionsText[] = { L"Deep Deployment", 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"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 2cc5aeec..3e2070ca 100644 --- a/Utils/_RussianText.cpp +++ b/Utils/_RussianText.cpp @@ -11943,6 +11943,9 @@ STR16 szRebelCommandText[] = // TODO.Translate L"Agent bonus:", L"Chance of success +%d%s (%s)", L"Deployment range +%d (%s)", + L"ASD Income -%2.0f%s (%s)", + L"Steal fuel; send to %s (%s)", + L"Destroy reserve units (%s)", L"Time +%2.0f%s (%s)", L"Vision -%2.0f%s (%s)", L"Gear quality -%d (%s)", @@ -12080,6 +12083,8 @@ STR16 szRebelCommandAgentMissionsText[] = { L"Deep Deployment", 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"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",