Add "Send Supplies" mission

This commit is contained in:
rftrdev
2022-10-25 17:28:41 -07:00
parent a35d741403
commit c1b5d1719a
12 changed files with 90 additions and 27 deletions
+66 -2
View File
@@ -353,6 +353,7 @@ enum RebelCommandText // keep this synced with szRebelCommandText in the text fi
RCT_MISSION_CANT_START_LOW_LOYALTY,
RCT_MISSION_CANT_START_AGENT_UNAVAILABLE,
RCT_MISSION_CANT_START_CONTRACT_EXPIRING,
RCT_MISSION_CANT_USE_REBEL_AGENT,
RCT_MISSION_CANT_START_BATTLE_IN_PROGRESS,
RCT_MISSION_START_BUTTON,
RCT_MISSION_VIEW_ACTIVE,
@@ -414,6 +415,7 @@ enum RebelCommandAgentMissionsText // keep this synced with szRebelCommandAgentM
MISSION_TEXT(REDUCE_UNALERTED_ENEMY_VISION)
MISSION_TEXT(SABOTAGE_INFANTRY_EQUIPMENT)
MISSION_TEXT(SABOTAGE_MECHANICAL_UNITS)
MISSION_TEXT(SEND_SUPPLIES_TO_TOWN)
MISSION_TEXT(SOLDIER_BOUNTIES_KINGPIN)
MISSION_TEXT(TRAIN_MILITIA_ANYWHERE)
};
@@ -546,6 +548,8 @@ INT32 GetAdminActionCostForRegion(INT16 regionId);
INT16 GetAdminActionInRegion(INT16 regionId, RebelCommandAdminActions adminAction);
UINT8 GetRegionLoyalty(INT16 regionId);
void HandleScouting();
void SendSuppliesToTownMission();
INT16 SendSuppliesToTownDurationBonus(const MERCPROFILESTRUCT* merc);
void SetupInfo();
void UpgradeMilitiaStats();
@@ -1221,7 +1225,7 @@ void UpdateAdminActionChangeList(INT16 regionId)
BOOLEAN EnterWebsite()
{
// rftr todo: temp debugging
rebelCommandSaveInfo.availableMissions[0] = RCAM_DISRUPT_ASD;
rebelCommandSaveInfo.availableMissions[0] = RCAM_SEND_SUPPLIES_TO_TOWN;
UpdateAdminActionChangeList(iCurrentRegionId);
// make sure we have a valid directive
@@ -2229,6 +2233,7 @@ BOOLEAN SetupMissionAgentBox(UINT16 x, UINT16 y, INT8 index)
case RCAM_REDUCE_UNALERTED_ENEMY_VISION: swprintf(sText, szRebelCommandAgentMissionsText[RCAMT_REDUCE_UNALERTED_ENEMY_VISION_TITLE]); break;
case RCAM_SABOTAGE_INFANTRY_EQUIPMENT: swprintf(sText, szRebelCommandAgentMissionsText[RCAMT_SABOTAGE_INFANTRY_EQUIPMENT_TITLE]); break;
case RCAM_SABOTAGE_MECHANICAL_UNITS: swprintf(sText, szRebelCommandAgentMissionsText[RCAMT_SABOTAGE_MECHANICAL_UNITS_TITLE]); break;
case RCAM_SEND_SUPPLIES_TO_TOWN: swprintf(sText, szRebelCommandAgentMissionsText[RCAMT_SEND_SUPPLIES_TO_TOWN_TITLE]); break;
case RCAM_SOLDIER_BOUNTIES_KINGPIN: swprintf(sText, szRebelCommandAgentMissionsText[RCAMT_SOLDIER_BOUNTIES_KINGPIN_TITLE]); break;
case RCAM_TRAIN_MILITIA_ANYWHERE: swprintf(sText, szRebelCommandAgentMissionsText[RCAMT_TRAIN_MILITIA_ANYWHERE_TITLE]); break;
@@ -2248,6 +2253,7 @@ BOOLEAN SetupMissionAgentBox(UINT16 x, UINT16 y, INT8 index)
case RCAM_REDUCE_UNALERTED_ENEMY_VISION: missionDurationBase = gRebelCommandSettings.iReduceUnalertedEnemyVisionDuration; break;
case RCAM_SABOTAGE_INFANTRY_EQUIPMENT: missionDurationBase = gRebelCommandSettings.iSabotageInfantryEquipmentDuration; break;
case RCAM_SABOTAGE_MECHANICAL_UNITS: missionDurationBase = gRebelCommandSettings.iSabotageMechanicalUnitsDuration; break;
case RCAM_SEND_SUPPLIES_TO_TOWN: missionDurationBase = gRebelCommandSettings.iSendSuppliesToTownDuration; break;
case RCAM_SOLDIER_BOUNTIES_KINGPIN: missionDurationBase = gRebelCommandSettings.iSoldierBountiesKingpinDuration; break;
case RCAM_TRAIN_MILITIA_ANYWHERE: missionDurationBase = gRebelCommandSettings.iTrainMilitiaAnywhereDuration; break;
@@ -2270,6 +2276,7 @@ BOOLEAN SetupMissionAgentBox(UINT16 x, UINT16 y, INT8 index)
case RCAM_REDUCE_UNALERTED_ENEMY_VISION: missionSuccessChanceBase = gRebelCommandSettings.iReduceUnalertedEnemyVisionSuccessChance; break;
case RCAM_SABOTAGE_INFANTRY_EQUIPMENT: missionSuccessChanceBase = gRebelCommandSettings.iSabotageInfantryEquipmentSuccessChance; break;
case RCAM_SABOTAGE_MECHANICAL_UNITS: missionSuccessChanceBase = gRebelCommandSettings.iSabotageMechanicalUnitsSuccessChance; break;
case RCAM_SEND_SUPPLIES_TO_TOWN: missionSuccessChanceBase = gRebelCommandSettings.iSendSuppliesToTownSuccessChance; break;
case RCAM_SOLDIER_BOUNTIES_KINGPIN: missionSuccessChanceBase = gRebelCommandSettings.iSoldierBountiesKingpinSuccessChance; break;
case RCAM_TRAIN_MILITIA_ANYWHERE: missionSuccessChanceBase = gRebelCommandSettings.iTrainMilitiaAnywhereSuccessChance; break;
@@ -2289,6 +2296,7 @@ BOOLEAN SetupMissionAgentBox(UINT16 x, UINT16 y, INT8 index)
case RCAM_REDUCE_UNALERTED_ENEMY_VISION: swprintf(sText, szRebelCommandAgentMissionsText[RCAMT_REDUCE_UNALERTED_ENEMY_VISION_DESC]); break;
case RCAM_SABOTAGE_INFANTRY_EQUIPMENT: swprintf(sText, szRebelCommandAgentMissionsText[RCAMT_SABOTAGE_INFANTRY_EQUIPMENT_DESC]); break;
case RCAM_SABOTAGE_MECHANICAL_UNITS: swprintf(sText, szRebelCommandAgentMissionsText[RCAMT_SABOTAGE_MECHANICAL_UNITS_DESC]); break;
case RCAM_SEND_SUPPLIES_TO_TOWN: swprintf(sText, szRebelCommandAgentMissionsText[RCAMT_SEND_SUPPLIES_TO_TOWN_DESC]); break;
case RCAM_SOLDIER_BOUNTIES_KINGPIN: swprintf(sText, szRebelCommandAgentMissionsText[RCAMT_SOLDIER_BOUNTIES_KINGPIN_DESC], gRebelCommandSettings.iSoldierBountiesKingpinPayout_Limit); break;
case RCAM_TRAIN_MILITIA_ANYWHERE: swprintf(sText, szRebelCommandAgentMissionsText[RCAMT_TRAIN_MILITIA_ANYWHERE_DESC]); break;
@@ -2503,6 +2511,15 @@ BOOLEAN SetupMissionAgentBox(UINT16 x, UINT16 y, INT8 index)
}
break;
case RCAM_SEND_SUPPLIES_TO_TOWN:
{
// duration here is affected by lvl instead of a specific skill
CHAR16 durationText[100];
swprintf(durationText, szRebelCommandText[RCT_MISSION_BONUS_DURATION], SendSuppliesToTownDurationBonus(&merc), pShortAttributeStrings[5]); // "Lvl"
agentBonusText.push_back(durationText);
}
break;
case RCAM_SOLDIER_BOUNTIES_KINGPIN:
{
floatModifier = max(floatModifier, 1.f);
@@ -2578,7 +2595,7 @@ BOOLEAN SetupMissionAgentBox(UINT16 x, UINT16 y, INT8 index)
const INT32 worldMin = GetWorldTotalMin();
const INT32 remaining = endTime - worldMin;
if (townId < FIRST_TOWN || townId >= NUM_TOWNS || townLoyalty < gRebelCommandSettings.iMinLoyaltyForMission)
if ((townId < FIRST_TOWN || townId >= NUM_TOWNS || townLoyalty < gRebelCommandSettings.iMinLoyaltyForMission) && rebelCommandSaveInfo.availableMissions[index] != RCAM_SEND_SUPPLIES_TO_TOWN)
{
canStartMission = FALSE;
swprintf(sText, szRebelCommandText[RCT_MISSION_CANT_START_LOW_LOYALTY]);
@@ -2593,6 +2610,11 @@ BOOLEAN SetupMissionAgentBox(UINT16 x, UINT16 y, INT8 index)
canStartMission = FALSE;
swprintf(sText, szRebelCommandText[RCT_MISSION_CANT_START_CONTRACT_EXPIRING]);
}
else if (agentIndex[index] == mercs.size() && rebelCommandSaveInfo.availableMissions[index] == RCAM_SEND_SUPPLIES_TO_TOWN)
{
canStartMission = FALSE;
swprintf(sText, szRebelCommandText[RCT_MISSION_CANT_USE_REBEL_AGENT]);
}
if (!canStartMission)
{
@@ -2874,6 +2896,15 @@ void PrepareMission(INT8 index)
}
break;
case RCAM_SEND_SUPPLIES_TO_TOWN:
{
missionTitle = RCAMT_SEND_SUPPLIES_TO_TOWN_TITLE;
missionSuccessChance = gRebelCommandSettings.iSendSuppliesToTownSuccessChance;
missionDuration = gRebelCommandSettings.iSendSuppliesToTownDuration + SendSuppliesToTownDurationBonus(merc);
extraBits = SECTOR(merc->sSectorX, merc->sSectorY);
}
break;
case RCAM_SOLDIER_BOUNTIES_KINGPIN:
{
missionTitle = RCAMT_SOLDIER_BOUNTIES_KINGPIN_TITLE;
@@ -3909,6 +3940,9 @@ void HourlyUpdate()
{
HandleScouting();
// RCAM_SEND_SUPPLIES_TO_TOWN
SendSuppliesToTownMission();
// it's midnight! do the daily update
if (GetWorldHour() == 0)
{
@@ -4314,6 +4348,8 @@ void SetupInfo()
{gRebelCommandSettings.iSabotageMechanicalUnitsStatLoss_Covert, gRebelCommandSettings.iSabotageMechanicalUnitsStatLoss_Demolitions, gRebelCommandSettings.iSabotageMechanicalUnitsStatLoss_Heavy_Weapons},
{MissionHelpers::SABOTAGE_MECHANICAL_UNITS_COVERT, MissionHelpers::SABOTAGE_MECHANICAL_UNITS_DEMOLITIONS, MissionHelpers::SABOTAGE_MECHANICAL_UNITS_HEAVY_WEAPONS}
});
//RCAM_SEND_SUPPLIES_TO_TOWN
MissionHelpers::missionInfo.push_back({ }); // no entries necessary - no modifiers
//RCAM_SOLDIER_BOUNTIES_KINGPIN
MissionHelpers::missionInfo.push_back(
{
@@ -4854,6 +4890,7 @@ void HandleStrategicEvent(const UINT32 eventParam)
case RCAM_REDUCE_UNALERTED_ENEMY_VISION:
case RCAM_SABOTAGE_INFANTRY_EQUIPMENT:
case RCAM_SABOTAGE_MECHANICAL_UNITS:
case RCAM_SEND_SUPPLIES_TO_TOWN:
case RCAM_SOLDIER_BOUNTIES_KINGPIN:
case RCAM_TRAIN_MILITIA_ANYWHERE:
{
@@ -4948,6 +4985,33 @@ void HandleStrategicEvent(const UINT32 eventParam)
DoMessageBox(MSG_BOX_BASIC_STYLE, msgBoxText, guiCurrentScreen, MSG_BOX_FLAG_OK, NULL, NULL);
}
void SendSuppliesToTownMission()
{
if (!gGameExternalOptions.fRebelCommandEnabled)
return;
const std::unordered_map<RebelCommandAgentMissions, UINT32>::iterator iter = missionMap.find(RCAM_SEND_SUPPLIES_TO_TOWN);
if (iter == missionMap.end())
return;
if (GetWorldHour() % gRebelCommandSettings.iSendSuppliesToTownInterval != 0)
return;
MissionSecondEvent evt;
DeserialiseMissionSecondEvent(iter->second, evt);
if (evt.isSecondEvent)
{
IncrementTownLoyalty(evt.extraBits, gRebelCommandSettings.iSendSuppliesToTownLoyaltyGain);
}
}
INT16 SendSuppliesToTownDurationBonus(const MERCPROFILESTRUCT* merc)
{
return merc ? merc->bExpLevel * 8 : 0;
}
BOOLEAN ShowEnemyMovementTargets()
{
if (!gGameExternalOptions.fRebelCommandEnabled)
+3 -17
View File
@@ -15,17 +15,6 @@ namespace RebelCommand
// applies to RegionSaveInfo.actionLevels: use the MSB as the active flag since I don't expect it to be used otherwise
constexpr UINT8 ADMIN_ACTION_ACTIVE_BIT = 1 << 7;
// for rebelCommandSaveInfo.uBitMask
// requirement breakdown
// 1 bit for notification toggle
// 5 * 4 bits for random mission selection (2off, 2def) = 32 choices each
// need some bits to track mission area (friendly/hostile? num towns?)
// remaining bits to track up/downgrades?
// some should be ASD specific?
// can we not do this and just check strategic events? GetAllStrategicEventsOfType(). could be costly. iterates over event LL on each call
// can we cache in-flight events on load? no real need to save this, right?
//constexpr UINT64 AGENT_NOTIFICATION_BIT = 1 << 0;
// the FIRST and SECOND strategic events share the same type (EVENT_REBELCOMMAND - no need to have multiple types yet, I think...)
// so the 32-bit int will have to block out information for both events
// FIRST EVENT BREAKDOWN
@@ -35,8 +24,7 @@ namespace RebelCommand
// C (8 bit) - the profile number of the merc that was sent. invalid if B == 0
// D (8 bit) - the mission ID. should match up with RebelCommandAgentMissions enum
// E (8 bit) - the mission duration, in hours. if 0, mission failed.
// the rest of the bits depend on the mission?
//
// extra bits are mission-specific
// SECOND EVENT BREAKDOWN
// A####### #######B CCCCCCCC DDDDDDDD
@@ -44,7 +32,7 @@ namespace RebelCommand
// B (1 bit) - 0 if the player sent a generic rebel agent, 1 if the player sent one of their own mercs
// C (8 bit) - the profile number of the merc that was sent. invalid if B == 0
// D (8 bit) - the mission ID. should match up with RebelCommandAgentMissions enum
// extra bits are for ???????????
// extra bits are mission-specific
enum RebelCommandDirectives
{
@@ -96,19 +84,17 @@ enum RebelCommandAgentMissions
RCAM_REDUCE_UNALERTED_ENEMY_VISION, // aka Lower Readiness
RCAM_SABOTAGE_INFANTRY_EQUIPMENT, // aka Sabotage Equipment
RCAM_SABOTAGE_MECHANICAL_UNITS, // aka Sabotage Vehicles
RCAM_SEND_SUPPLIES_TO_TOWN, // ignores minimum loyalty requirement
RCAM_SOLDIER_BOUNTIES_KINGPIN,
RCAM_TRAIN_MILITIA_ANYWHERE,
RCAM_NUM_MISSIONS,
// ideas/unimplemented
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_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 (???)
// share vision with civilians?