From f4e8580534f4d63ec74658fcc3f95a9f340afa2e Mon Sep 17 00:00:00 2001 From: Xymanek Date: Mon, 10 Feb 2020 10:30:48 +0200 Subject: [PATCH 1/8] Removed old components approach to DLC CHL --- .vscode/tasks.json | 10 ------ .../DLC2CommunityHighlander.XCOM_sln | 19 ---------- .../Config/XComCHLComponents.ini | 2 -- .../DLC2CommunityHighlander.x2proj | 28 --------------- .../DLC2CommunityHighlander/ModPreview.jpg | Bin 5363 -> 0 bytes .../Classes/X2DLC2CH_CHXComGameVersion.uc | 34 ------------------ Components/README.md | 5 --- 7 files changed, 98 deletions(-) delete mode 100644 Components/DLC2CommunityHighlander/DLC2CommunityHighlander.XCOM_sln delete mode 100644 Components/DLC2CommunityHighlander/DLC2CommunityHighlander/Config/XComCHLComponents.ini delete mode 100644 Components/DLC2CommunityHighlander/DLC2CommunityHighlander/DLC2CommunityHighlander.x2proj delete mode 100644 Components/DLC2CommunityHighlander/DLC2CommunityHighlander/ModPreview.jpg delete mode 100644 Components/DLC2CommunityHighlander/DLC2CommunityHighlander/Src/DLC_2/Classes/X2DLC2CH_CHXComGameVersion.uc delete mode 100644 Components/README.md diff --git a/.vscode/tasks.json b/.vscode/tasks.json index e7837f751..fd0ac147a 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -34,16 +34,6 @@ "group": "build", "problemMatcher": [] }, - { - "label": "build-dlc2", - "type": "shell", - "command": "powershell.exe –NonInteractive –ExecutionPolicy Unrestricted -file '${workspaceRoot}\\.scripts\\build.ps1' -mod \"DLC2CommunityHighlander\" -srcDirectory '${workspaceRoot}\\Components\\DLC2CommunityHighlander' -sdkPath '${config:xcom.highlander.sdkroot}' -gamePath '${config:xcom.highlander.gameroot}'", - "group": { - "kind": "build", - "isDefault": true - }, - "problemMatcher": [] - }, { "label": "runGame", "type": "shell", diff --git a/Components/DLC2CommunityHighlander/DLC2CommunityHighlander.XCOM_sln b/Components/DLC2CommunityHighlander/DLC2CommunityHighlander.XCOM_sln deleted file mode 100644 index c5a2abf65..000000000 --- a/Components/DLC2CommunityHighlander/DLC2CommunityHighlander.XCOM_sln +++ /dev/null @@ -1,19 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# XCOM ModBuddy Solution File, Format Version 11.00 -VisualStudioVersion = 12.0.21005.1 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{5DAE07AF-E217-45C1-8DE7-FF99D6011E8A}") = "DLC2CommunityHighlander", "DLC2CommunityHighlander\DLC2CommunityHighlander.x2proj", "{83C5EFD1-5DCE-4DE7-91AF-C3FB27383F16}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Default|XCOM 2 = Default|XCOM 2 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {83C5EFD1-5DCE-4DE7-91AF-C3FB27383F16}.Default|XCOM 2.ActiveCfg = Default|XCOM 2 - {83C5EFD1-5DCE-4DE7-91AF-C3FB27383F16}.Default|XCOM 2.Build.0 = Default|XCOM 2 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/Components/DLC2CommunityHighlander/DLC2CommunityHighlander/Config/XComCHLComponents.ini b/Components/DLC2CommunityHighlander/DLC2CommunityHighlander/Config/XComCHLComponents.ini deleted file mode 100644 index 8696e924b..000000000 --- a/Components/DLC2CommunityHighlander/DLC2CommunityHighlander/Config/XComCHLComponents.ini +++ /dev/null @@ -1,2 +0,0 @@ -[X2WOTCCommunityHighlander.X2WOTCCH_Components] -DLC2ReplacementEnabled=true \ No newline at end of file diff --git a/Components/DLC2CommunityHighlander/DLC2CommunityHighlander/DLC2CommunityHighlander.x2proj b/Components/DLC2CommunityHighlander/DLC2CommunityHighlander/DLC2CommunityHighlander.x2proj deleted file mode 100644 index 5659b2ece..000000000 --- a/Components/DLC2CommunityHighlander/DLC2CommunityHighlander/DLC2CommunityHighlander.x2proj +++ /dev/null @@ -1,28 +0,0 @@ - - - - 75128cbd-0b09-46f0-b431-e0325e54ee80 - DLC2CommunityHighlander - Description of My XCOM 2 Mod. - 0 - DLC2CommunityHighlander - DLC2CommunityHighlander - {83C5EFD1-5DCE-4DE7-91AF-C3FB27383F16} - - - - - - - - - - Content - - - - Content - - - - \ No newline at end of file diff --git a/Components/DLC2CommunityHighlander/DLC2CommunityHighlander/ModPreview.jpg b/Components/DLC2CommunityHighlander/DLC2CommunityHighlander/ModPreview.jpg deleted file mode 100644 index 5bdd8d8b65d9d30ef9cea7a85bc3bbf9dd1da380..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5363 zcmex= zRY=j$kxe)-kzJ`!#HexNLJno8jR!@8E`CrkPAY2R|V^&07y2J$~}^+4C1KUw!=a z`ODXD-+%o41@ado12e>1aG#<1OAzQUCSV+}u!H=?$W#u*%z`YeiiT`Lj)Clng~Cck zjT|CQ6Blkg$f;}`^g%SK=pvVxipfLOk07sseMX$en#l4Q++zrT-D2QjW&}navmk># z!@v3$i@F#zM)7DEjHZFnG%%V5M$^D(8W>FjqiJ9?4UDFN(KIlc21e7sXc`zz1EXnR MG!4)w4g9|e04%!YWB>pF diff --git a/Components/DLC2CommunityHighlander/DLC2CommunityHighlander/Src/DLC_2/Classes/X2DLC2CH_CHXComGameVersion.uc b/Components/DLC2CommunityHighlander/DLC2CommunityHighlander/Src/DLC_2/Classes/X2DLC2CH_CHXComGameVersion.uc deleted file mode 100644 index 8f55c0b40..000000000 --- a/Components/DLC2CommunityHighlander/DLC2CommunityHighlander/Src/DLC_2/Classes/X2DLC2CH_CHXComGameVersion.uc +++ /dev/null @@ -1,34 +0,0 @@ -class X2DLC2CH_CHXComGameVersion extends X2StrategyElement; - -var int MajorVersion; -var int MinorVersion; -var int PatchVersion; -var string Commit; - -static function array CreateTemplates() -{ - local array Templates; - local X2StrategyElementTemplate XComGameVersion; - - if (class'CHXComGameVersionTemplate' != none) - { - `CREATE_X2TEMPLATE(class'CHXComGameVersionTemplate', XComGameVersion, 'CHDLC2Version'); - CHXComGameVersionTemplate(XComGameVersion).MajorVersion = default.MajorVersion; - CHXComGameVersionTemplate(XComGameVersion).MinorVersion = default.MinorVersion; - CHXComGameVersionTemplate(XComGameVersion).PatchVersion = default.PatchVersion; - CHXComGameVersionTemplate(XComGameVersion).Commit = default.Commit; - - Templates.AddItem(XComGameVersion); - } - - return Templates; -} - -// AUTO-CODEGEN: Version-Info -defaultproperties -{ - MajorVersion = 1; - MinorVersion = 20; - PatchVersion = 0; - Commit = "RC1"; -} diff --git a/Components/README.md b/Components/README.md deleted file mode 100644 index ba2d0583a..000000000 --- a/Components/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# X2WOTCCommunityHighlander Components - -Components are a way to replace DLC script packages using a separate workshop mod. -Shipping `DLC_2.u` / `DLC_3.u` / `TLE.u` could have some adverse side effects -for users without the DLC, so we ship a separate mod. \ No newline at end of file From c29b0417a499b4d999ef047cf629db57910c4014 Mon Sep 17 00:00:00 2001 From: Xymanek Date: Mon, 10 Feb 2020 10:33:06 +0200 Subject: [PATCH 2/8] Added DLC_2 alongside X2WOTCCommunityHighlander --- .../Classes/X2DLC2CH_CHXComGameVersion.uc | 38 +++++++++++++++++++ .../X2WOTCCommunityHighlander.x2proj | 7 +++- 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 X2WOTCCommunityHighlander/Src/DLC_2/Classes/X2DLC2CH_CHXComGameVersion.uc diff --git a/X2WOTCCommunityHighlander/Src/DLC_2/Classes/X2DLC2CH_CHXComGameVersion.uc b/X2WOTCCommunityHighlander/Src/DLC_2/Classes/X2DLC2CH_CHXComGameVersion.uc new file mode 100644 index 000000000..2440503cc --- /dev/null +++ b/X2WOTCCommunityHighlander/Src/DLC_2/Classes/X2DLC2CH_CHXComGameVersion.uc @@ -0,0 +1,38 @@ +class X2DLC2CH_CHXComGameVersion extends X2StrategyElement; + +var int MajorVersion; +var int MinorVersion; +var int PatchVersion; +var string Commit; + +static function array CreateTemplates() +{ + local array Templates; + local X2StrategyElementTemplate XComGameVersion; + + `log("CreateTemplates",, 'DLC2CommunityHighlander'); + + if (class'CHXComGameVersionTemplate' != none) + { + `log("Creating CHDLC2Version with version" @ default.MajorVersion $ "." $ default.MinorVersion $ "." $ default.PatchVersion,, 'DLC2CommunityHighlander'); + + `CREATE_X2TEMPLATE(class'CHXComGameVersionTemplate', XComGameVersion, 'CHDLC2Version'); + CHXComGameVersionTemplate(XComGameVersion).MajorVersion = default.MajorVersion; + CHXComGameVersionTemplate(XComGameVersion).MinorVersion = default.MinorVersion; + CHXComGameVersionTemplate(XComGameVersion).PatchVersion = default.PatchVersion; + CHXComGameVersionTemplate(XComGameVersion).Commit = default.Commit; + + Templates.AddItem(XComGameVersion); + } + + return Templates; +} + +// AUTO-CODEGEN: Version-Info +defaultproperties +{ + MajorVersion = 1; + MinorVersion = 20; + PatchVersion = 0; + Commit = "RC1"; +} diff --git a/X2WOTCCommunityHighlander/X2WOTCCommunityHighlander.x2proj b/X2WOTCCommunityHighlander/X2WOTCCommunityHighlander.x2proj index e80c2f071..bf24b0df9 100644 --- a/X2WOTCCommunityHighlander/X2WOTCCommunityHighlander.x2proj +++ b/X2WOTCCommunityHighlander/X2WOTCCommunityHighlander.x2proj @@ -13,8 +13,10 @@ + + @@ -43,6 +45,9 @@ Content + + Content + Content @@ -750,4 +755,4 @@ - + \ No newline at end of file From 2f3707171134c7ccc7ad2acdced91dc1cc28b2a5 Mon Sep 17 00:00:00 2001 From: Xymanek Date: Mon, 10 Feb 2020 10:34:22 +0200 Subject: [PATCH 3/8] Added XComGameState_AlienRulerManager --- .../XComGameState_AlienRulerManager.uc | 873 ++++++++++++++++++ .../X2WOTCCommunityHighlander.x2proj | 3 + 2 files changed, 876 insertions(+) create mode 100644 X2WOTCCommunityHighlander/Src/DLC_2/Classes/XComGameState_AlienRulerManager.uc diff --git a/X2WOTCCommunityHighlander/Src/DLC_2/Classes/XComGameState_AlienRulerManager.uc b/X2WOTCCommunityHighlander/Src/DLC_2/Classes/XComGameState_AlienRulerManager.uc new file mode 100644 index 000000000..3429b7b97 --- /dev/null +++ b/X2WOTCCommunityHighlander/Src/DLC_2/Classes/XComGameState_AlienRulerManager.uc @@ -0,0 +1,873 @@ +//--------------------------------------------------------------------------------------- +// FILE: XComGameState_AlienRulerManager.uc +// AUTHOR: Mark Nauta -- 01/28/2016 +// PURPOSE: This object represents the instance of the Alien Ruler manager +// in the XCOM 2 strategy game +// +//--------------------------------------------------------------------------------------- +// Copyright (c) 2016 Firaxis Games, Inc. All rights reserved. +//--------------------------------------------------------------------------------------- +class XComGameState_AlienRulerManager extends XComGameState_BaseObject config(GameData); + +// Ruler Tracking +var StateObjectReference RulerOnCurrentMission; +var array AllAlienRulers; +var array ActiveAlienRulers; +var array DefeatedAlienRulers; +var array EscapedAlienRulers; +var int MissionsSinceLastRuler; +var int RulerAppearRoll; // Need to store for Shadow Chamber to show ruler spawning correctly for concurrent missions +var bool bRulerEscaped; // Did a Ruler escape on the last mission? +var bool bHeardRulerEscapedVO; // Did the Ruler Escaped VO play already +var bool bRulerDefeated; // Was a Ruler defeated on the last mission? +var array AlienRulerLocations; // Used by XPack Integrated DLC to store the mission location of each ruler + +// DLC Installation Tracking +var bool bContentCheckCompleted; // Has the popup asking the player whether or not to enable DLC content been shown +var bool bContentActivated; // Is the DLC content enabled + +// Force Ruler to Appear +var StateObjectReference ForcedRulerOnNextMission; + +// Config vars +var const config array AlienRulerTemplates; +var const config array RulerMaxNumEncounters; +var const config array RulerEscapeHealthThresholds; +var const config array RulerReappearChances; +var const config int RulerLocationSpawnMaxHours; + +// Central's config data +var const config name NestCentralTemplate; +var const config array NestCentralWeaponUpgrades; + +// Localized strings +var localized string NestCentralFirstName; +var localized string NestCentralLastName; +var localized string NestCentralNickName; + +//--------------------------------------------------------------------------------------- +static function SetUpRulers(XComGameState StartState) +{ + local XComGameState_AlienRulerManager RulerMgr; + + foreach StartState.IterateByClassType(class'XComGameState_AlienRulerManager', RulerMgr) + { + break; + } + + if (RulerMgr == none) + { + RulerMgr = XComGameState_AlienRulerManager(StartState.CreateNewStateObject(class'XComGameState_AlienRulerManager')); + } + + RulerMgr.CreateAlienRulers(StartState); + RulerMgr.CreateNestCentral(StartState); +} + +//--------------------------------------------------------------------------------------- +function CreateAlienRulers(XComGameState NewGameState) +{ + local XComGameState_Unit UnitState; + local X2CharacterTemplateManager CharMgr; + local X2CharacterTemplate CharTemplate; + local int idx; + + CharMgr = class'X2CharacterTemplateManager'.static.GetCharacterTemplateManager(); + + for(idx = 0; idx < default.AlienRulerTemplates.Length; idx++) + { + CharTemplate = CharMgr.FindCharacterTemplate(default.AlienRulerTemplates[idx].AlienRulerTemplateName); + UnitState = CharTemplate.CreateInstanceFromTemplate(NewGameState); + UnitState.SetUnitFloatValue('NumEscapes', 0.0f, eCleanup_Never); + UnitState.SetUnitFloatValue('NumAppearances', 0.0f, eCleanup_Never); + UnitState.bIsSpecial = true; + UnitState.RemoveStateFromPlay(); // Do not process the ruler states in tactical + UnitState.ApplyFirstTimeStatModifiers(); // Update the Ruler HP values to work with Beta Strike + AllAlienRulers.AddItem(UnitState.GetReference()); + class'X2Helpers_DLC_Day60'.static.UpdateRulerEscapeHealth(UnitState); + } +} + +//--------------------------------------------------------------------------------------- +function CreateNestCentral(XComGameState NewGameState) +{ + local XComGameState_Unit UnitState; + local X2ItemTemplateManager ItemTemplateMgr; + local X2CharacterTemplateManager CharMgr; + local X2CharacterTemplate CharTemplate; + local XComGameState_Item CentralRifle; + local X2WeaponUpgradeTemplate UpgradeTemplate; + local name WeaponUpgradeName; + + CharMgr = class'X2CharacterTemplateManager'.static.GetCharacterTemplateManager(); + CharTemplate = CharMgr.FindCharacterTemplate(default.NestCentralTemplate); + UnitState = CharTemplate.CreateInstanceFromTemplate(NewGameState); + + UnitState.SetCharacterName(default.NestCentralFirstName, default.NestCentralLastName, default.NestCentralNickName); + UnitState.SetCountry(CharTemplate.DefaultAppearance.nmFlag); + UnitState.RankUpSoldier(NewGameState, 'CentralOfficer'); + UnitState.ApplyInventoryLoadout(NewGameState, CharTemplate.DefaultLoadout); + UnitState.StartingRank = 1; + UnitState.SetXPForRank(1); + + ItemTemplateMgr = class'X2ItemTemplateManager'.static.GetItemTemplateManager(); + CentralRifle = UnitState.GetPrimaryWeapon(); + foreach default.NestCentralWeaponUpgrades(WeaponUpgradeName) + { + UpgradeTemplate = X2WeaponUpgradeTemplate(ItemTemplateMgr.FindItemTemplate(WeaponUpgradeName)); + if (UpgradeTemplate != none) + { + CentralRifle.ApplyWeaponUpgradeTemplate(UpgradeTemplate); + } + } +} + +//--------------------------------------------------------------------------------------- +static function PreMissionUpdate(XComGameState NewGameState, XComGameState_MissionSite MissionState) +{ + local XComGameStateHistory History; + local XComGameState_AlienRulerManager RulerMgr; + local XComGameState_Unit UnitState; + + History = `XCOMHISTORY; + RulerMgr = XComGameState_AlienRulerManager(History.GetSingleGameStateObjectForClass(class'XComGameState_AlienRulerManager')); + RulerMgr = XComGameState_AlienRulerManager(NewGameState.ModifyStateObject(class'XComGameState_AlienRulerManager', RulerMgr.ObjectID)); + + // Do a hard check for the Nest mission here, in case the Shadow Chamber is up we still need the Ruler Update before that mission + if (MissionState.SelectedMissionData.SelectedMissionScheduleName == '' || MissionState.Source == 'MissionSource_AlienNest') + { + RulerMgr.UpdateRulerSpawningData(NewGameState, MissionState); + } + + // Only update NumAppearances of the Ruler here when actually going into the mission + if(RulerMgr.RulerOnCurrentMission.ObjectID != 0) + { + UnitState = XComGameState_Unit(NewGameState.ModifyStateObject(class'XComGameState_Unit', RulerMgr.RulerOnCurrentMission.ObjectID)); + class'X2Helpers_DLC_Day60'.static.IncrementRulerNumAppearances(UnitState); + } +} + +//--------------------------------------------------------------------------------------- +private function AddRulerAdditionalTacticalTags(XComGameState_HeadquartersXCom XComHQ, int NumAppearances, AlienRulerData RulerData) +{ + local int idx, MaxNumAppearances, MaxAppearanceIndex; + + if(RulerData.AdditionalTags.Length == 0) + { + return; + } + + MaxNumAppearances = 0; + MaxAppearanceIndex = 0; + + for(idx = 0; idx < RulerData.AdditionalTags.Length; idx++) + { + if(NumAppearances == RulerData.AdditionalTags[idx].NumTimesAppeared) + { + XComHQ.TacticalGameplayTags.AddItem(RulerData.AdditionalTags[idx].TacticalTag); + return; + } + + if(RulerData.AdditionalTags[idx].NumTimesAppeared > MaxNumAppearances) + { + MaxNumAppearances = RulerData.AdditionalTags[idx].NumTimesAppeared; + MaxAppearanceIndex = idx; + } + } + + if(NumAppearances >= MaxNumAppearances) + { + XComHQ.TacticalGameplayTags.AddItem(RulerData.AdditionalTags[MaxAppearanceIndex].TacticalTag); + } +} + +//--------------------------------------------------------------------------------------- +/*private*/ function int GetRulerAppearChance(XComGameState_Unit UnitState) +{ + local array AppearChances; + local RulerReappearChance MaxAppearChance; + local int idx, CampaignDifficulty, NumAppearances; + + CampaignDifficulty = `TacticalDifficultySetting; + NumAppearances = class'X2Helpers_DLC_Day60'.static.GetRulerNumAppearances(UnitState); + + if(NumAppearances == 0) + { + return 100; + } + + for(idx = 0; idx < default.RulerReappearChances.Length; idx++) + { + if(default.RulerReappearChances[idx].Difficulty == CampaignDifficulty) + { + AppearChances.AddItem(default.RulerReappearChances[idx]); + + if(AppearChances.Length == 1 || default.RulerReappearChances[idx].MissionCount > MaxAppearChance.MissionCount) + { + MaxAppearChance = default.RulerReappearChances[idx]; + } + } + } + + if(AppearChances.Length == 0) + { + return 100; + } + + for(idx = 0; idx < AppearChances.Length; idx++) + { + if(MissionsSinceLastRuler == AppearChances[idx].MissionCount) + { + return AppearChances[idx].PercentChance; + } + } + + return MaxAppearChance.PercentChance; +} + +//--------------------------------------------------------------------------------------- +function OnEndTacticalPlay(XComGameState NewGameState) +{ + local XComGameStateHistory History; + local XComGameState_HeadquartersXCom XComHQ; + local XComGameState_Unit RulerState, UnitState; + local StateObjectReference EmptyRef; + local XComGameState_AIPlayerData AIPlayerData; + local XComGameState_AIGroup AIGroup; + local int GroupIndex, UnitIndex, RulerIndex, LocationIndex; + + super.OnEndTacticalPlay(NewGameState); + + History = `XCOMHISTORY; + + bRulerDefeated = false; + bRulerEscaped = false; + + // Update Active and Defeated Rulers + if (RulerOnCurrentMission.ObjectID != 0) + { + XComHQ = XComGameState_HeadquartersXCom(History.GetSingleGameStateObjectForClass(class'XComGameState_HeadquartersXCom')); + XComHQ = XComGameState_HeadquartersXCom(NewGameState.ModifyStateObject(class'XComGameState_HeadquartersXCom', XComHQ.ObjectID)); + + RulerState = XComGameState_Unit(NewGameState.GetGameStateForObjectID(RulerOnCurrentMission.ObjectID)); + if (RulerState == none) + { + RulerState = XComGameState_Unit(NewGameState.ModifyStateObject(class'XComGameState_Unit', RulerOnCurrentMission.ObjectID)); + } + + // Grab the ruler unit actually used in this tactical mission and check if they died + AIPlayerData = XComGameState_AIPlayerData(History.GetSingleGameStateObjectForClass(class'XComGameState_AIPlayerData')); + + for (GroupIndex = 0; GroupIndex < AIPlayerData.GroupList.Length; GroupIndex++) + { + if (bRulerDefeated) + { + break; + } + + AIGroup = XComGameState_AIGroup(History.GetGameStateForObjectID(AIPlayerData.GroupList[GroupIndex].ObjectID)); + if (AIGroup != none) + { + for (UnitIndex = 0; UnitIndex < AIGroup.m_arrMembers.Length; UnitIndex++) + { + UnitState = XComGameState_Unit(History.GetGameStateForObjectID(AIGroup.m_arrMembers[UnitIndex].ObjectID)); + + if (UnitState != none && UnitState.GetMyTemplateName() == RulerState.GetMyTemplateName()) + { + RulerState.SetCurrentStat(eStat_HP, UnitState.GetCurrentStat(eStat_HP)); + RulerState.SetCurrentStat(eStat_ArmorMitigation, max(UnitState.GetCurrentStat(eStat_ArmorMitigation) - UnitState.Shredded, 0)); + + if (UnitState.IsDead()) + { + DefeatedAlienRulers.AddItem(RulerOnCurrentMission); + ActiveAlienRulers.RemoveItem(RulerOnCurrentMission); + EscapedAlienRulers.RemoveItem(RulerOnCurrentMission); // Safety check + RulerIndex = default.AlienRulerTemplates.Find('AlienRulerTemplateName', RulerState.GetMyTemplateName()); + XComHQ.TacticalGameplayTags.AddItem(default.AlienRulerTemplates[RulerIndex].DeadTacticalTag); + bRulerDefeated = true; + break; + } + else if (class'X2Helpers_DLC_Day60'.static.GetRulerNumAppearances(UnitState) >= `ScaleStrategyArrayInt(default.RulerMaxNumEncounters)) + { + EscapedAlienRulers.AddItem(RulerOnCurrentMission); + ActiveAlienRulers.RemoveItem(RulerOnCurrentMission); + break; + } + else + { + // If the ruler escaped for the first time, check to see if it was on a specific location + LocationIndex = AlienRulerLocations.Find('RulerRef', RulerOnCurrentMission); + if (LocationIndex != INDEX_NONE) + { + // Remove the specific location for the ruler so it can start spawning on any mission + AlienRulerLocations.Remove(LocationIndex, 1); + } + } + } + } + } + } + + if (!bRulerDefeated) + { + // If not defeated, then they escaped + class'X2Helpers_DLC_Day60'.static.IncrementRulerNumEscapes(RulerState); + class'X2Helpers_DLC_Day60'.static.UpdateRulerEscapeHealth(RulerState); + bRulerEscaped = true; + } + + // Reset current mission ruler and mission counter + ClearActiveRulerTags(XComHQ); + RulerOnCurrentMission = EmptyRef; + ForcedRulerOnNextMission = EmptyRef; + MissionsSinceLastRuler = 0; + } + + // Increment mission counter here and store appearance roll + MissionsSinceLastRuler++; + RulerAppearRoll = `SYNC_RAND_STATIC(100); +} + +//--------------------------------------------------------------------------------------- +static function PostMissionUpdate(XComGameState NewGameState) +{ + local XComGameStateHistory History; + local XComGameState_AlienRulerManager RulerMgr; + local XComGameState_BattleData BattleData; + + History = `XCOMHISTORY; + RulerMgr = XComGameState_AlienRulerManager(History.GetSingleGameStateObjectForClass(class'XComGameState_AlienRulerManager')); + + BattleData = XComGameState_BattleData(History.GetSingleGameStateObjectForClass(class'XComGameState_BattleData')); + BattleData = XComGameState_BattleData(NewGameState.ModifyStateObject(class'XComGameState_BattleData', BattleData.ObjectID)); + BattleData.bRulerEscaped = false; + if (RulerMgr.bRulerEscaped) + { + RulerMgr.bRulerEscaped = false; // Reset the flag in the manager + if (!RulerMgr.bHeardRulerEscapedVO) + { + BattleData.bRulerEscaped = true; // Set in Battle Data to trigger VO on after action walkup + RulerMgr.bHeardRulerEscapedVO = true; // and set the VO as heard + } + } + + if (RulerMgr.bRulerDefeated) + { + RulerMgr = XComGameState_AlienRulerManager(NewGameState.ModifyStateObject(class'XComGameState_AlienRulerManager', RulerMgr.ObjectID)); + RulerMgr.bRulerDefeated = false; + + class'XComGameState_HeadquartersResistance'.static.RecordResistanceActivity(NewGameState, 'ResAct_AlienRulersKilled'); + } +} + +//--------------------------------------------------------------------------------------- +function StateObjectReference GetAlienRulerReference(name TemplateName) +{ + local XComGameStateHistory History; + local XComGameState_Unit UnitState; + local StateObjectReference EmptyRef; + local int idx; + + History = `XCOMHISTORY; + + for(idx = 0; idx < AllAlienRulers.Length; idx++) + { + UnitState = XComGameState_Unit(History.GetGameStateForObjectID(AllAlienRulers[idx].ObjectID)); + + if(UnitState != none && UnitState.GetMyTemplateName() == TemplateName) + { + return UnitState.GetReference(); + } + } + + return EmptyRef; +} + +//--------------------------------------------------------------------------------------- +function ClearActiveRulerTags(XComGameState_HeadquartersXCom XComHQ) +{ + local int idx, i; + + for(idx = 0; idx < default.AlienRulerTemplates.Length; idx++) + { + // Remove the active tag + XComHQ.TacticalGameplayTags.RemoveItem(default.AlienRulerTemplates[idx].ActiveTacticalTag); + + // Remove any additional tags + for(i = 0; i < default.AlienRulerTemplates[idx].AdditionalTags.Length; i++) + { + XComHQ.TacticalGameplayTags.RemoveItem(default.AlienRulerTemplates[idx].AdditionalTags[i].TacticalTag); + } + } +} + +//--------------------------------------------------------------------------------------- +function UpdateRulerSpawningData(XComGameState NewGameState, XComGameState_MissionSite MissionState) +{ + local XComGameStateHistory History; + local XComGameState_HeadquartersXCom XComHQ; + local XComGameState_Unit UnitState; + local StateObjectReference EmptyRef, ViperKingRef, RulerRef; + + History = `XCOMHISTORY; + XComHQ = XComGameState_HeadquartersXCom(History.GetSingleGameStateObjectForClass(class'XComGameState_HeadquartersXCom')); + XComHQ = XComGameState_HeadquartersXCom(NewGameState.ModifyStateObject(class'XComGameState_HeadquartersXCom', XComHQ.ObjectID)); + + // Clear out active ruler tags + ClearActiveRulerTags(XComHQ); + + // Handle case where this is the nest mission + if(MissionState.Source == 'MissionSource_AlienNest') + { + ViperKingRef = GetAlienRulerReference('ViperKing'); + if (ActiveAlienRulers.Find('ObjectID', ViperKingRef.ObjectID) == INDEX_NONE) + { + // Only add the Viper King to the active rulers list if it isn't already included + ActiveAlienRulers.AddItem(ViperKingRef); + } + RulerOnCurrentMission = ViperKingRef; + return; + } + + // Handle Integrated DLC and Cheat Case where ruler is forced + ForcedRulerOnNextMission = GetRulerLocatedAtMission(MissionState); + if(ForcedRulerOnNextMission.ObjectID != 0) + { + if(ActiveAlienRulers.Find('ObjectID', ForcedRulerOnNextMission.ObjectID) == INDEX_NONE) + { + ActiveAlienRulers.AddItem(ForcedRulerOnNextMission); + } + + if(ChosenOnMission(MissionState)) + { + RemoveChosenFromMission(NewGameState, MissionState, XComHQ); + } + + UnitState = XComGameState_Unit(History.GetGameStateForObjectID(ForcedRulerOnNextMission.ObjectID)); + SetRulerOnCurrentMission(NewGameState, UnitState, XComHQ); + return; + } + + // Only add Rulers to missions if the Nest is complete (or optional narrative content is disabled) + if (AreAlienRulersAllowedToSpawn()) + { + // Update Active Rulers based on force level + UpdateActiveAlienRulers(); + + // Determine if a Ruler is on the current mission + if (ActiveAlienRulers.Length != 0 && CanRulerAppearOnMission(MissionState)) + { + foreach ActiveAlienRulers(RulerRef) + { + // Make sure that the ruler is not waiting at a specific location + if (AlienRulerLocations.Find('RulerRef', RulerRef) == INDEX_NONE) + { + // If the ruler is active and not at a specific location, it can appear on normal missions + UnitState = XComGameState_Unit(History.GetGameStateForObjectID(RulerRef.ObjectID)); + if (RulerAppearRoll < GetRulerAppearChance(UnitState)) + { + SetRulerOnCurrentMission(NewGameState, UnitState, XComHQ); + return; + } + } + } + } + } + + RulerOnCurrentMission = EmptyRef; +} + +//--------------------------------------------------------------------------------------- +// Check to see if the mission has any chosen tags active +private function bool ChosenOnMission(XComGameState_MissionSite MissionState) +{ + local array TacTags; + + TacTags = MissionState.TacticalGameplayTags; + + if(TacTags.Length == 0) + { + return false; + } + + return (TacTags.Find('Chosen_AssassinActive') != INDEX_NONE || TacTags.Find('Chosen_AssassinActiveM2') != INDEX_NONE || + TacTags.Find('Chosen_AssassinActiveM3') != INDEX_NONE || TacTags.Find('Chosen_AssassinActiveM4') != INDEX_NONE || + TacTags.Find('Chosen_SniperActive') != INDEX_NONE || TacTags.Find('Chosen_SniperActiveM2') != INDEX_NONE || + TacTags.Find('Chosen_SniperActiveM3') != INDEX_NONE || TacTags.Find('Chosen_SniperActiveM4') != INDEX_NONE || + TacTags.Find('Chosen_WarlockActive') != INDEX_NONE || TacTags.Find('Chosen_WarlockActiveM2') != INDEX_NONE || + TacTags.Find('Chosen_WarlockActiveM3') != INDEX_NONE || TacTags.Find('Chosen_WarlockActiveM4') != INDEX_NONE); +} + +//--------------------------------------------------------------------------------------- +// If the Ruler is forced on the mission, we need to remove the Chosen +private function RemoveChosenFromMission(XComGameState NewGameState, XComGameState_MissionSite MissionState, XComGameState_HeadquartersXCom XComHQ) +{ + MissionState = XComGameState_MissionSite(NewGameState.ModifyStateObject(class'XComGameState_MissionSite', MissionState.ObjectID)); + + MissionState.TacticalGameplayTags.RemoveItem('Chosen_AssassinActive'); + MissionState.TacticalGameplayTags.RemoveItem('Chosen_AssassinActiveM2'); + MissionState.TacticalGameplayTags.RemoveItem('Chosen_AssassinActiveM3'); + MissionState.TacticalGameplayTags.RemoveItem('Chosen_AssassinActiveM4'); + MissionState.TacticalGameplayTags.RemoveItem('Chosen_SniperActive'); + MissionState.TacticalGameplayTags.RemoveItem('Chosen_SniperActiveM2'); + MissionState.TacticalGameplayTags.RemoveItem('Chosen_SniperActiveM3'); + MissionState.TacticalGameplayTags.RemoveItem('Chosen_SniperActiveM4'); + MissionState.TacticalGameplayTags.RemoveItem('Chosen_WarlockActive'); + MissionState.TacticalGameplayTags.RemoveItem('Chosen_WarlockActiveM2'); + MissionState.TacticalGameplayTags.RemoveItem('Chosen_WarlockActiveM3'); + MissionState.TacticalGameplayTags.RemoveItem('Chosen_WarlockActiveM4'); + + XComHQ.TacticalGameplayTags.RemoveItem('Chosen_AssassinActive'); + XComHQ.TacticalGameplayTags.RemoveItem('Chosen_AssassinActiveM2'); + XComHQ.TacticalGameplayTags.RemoveItem('Chosen_AssassinActiveM3'); + XComHQ.TacticalGameplayTags.RemoveItem('Chosen_AssassinActiveM4'); + XComHQ.TacticalGameplayTags.RemoveItem('Chosen_SniperActive'); + XComHQ.TacticalGameplayTags.RemoveItem('Chosen_SniperActiveM2'); + XComHQ.TacticalGameplayTags.RemoveItem('Chosen_SniperActiveM3'); + XComHQ.TacticalGameplayTags.RemoveItem('Chosen_SniperActiveM4'); + XComHQ.TacticalGameplayTags.RemoveItem('Chosen_WarlockActive'); + XComHQ.TacticalGameplayTags.RemoveItem('Chosen_WarlockActiveM2'); + XComHQ.TacticalGameplayTags.RemoveItem('Chosen_WarlockActiveM3'); + XComHQ.TacticalGameplayTags.RemoveItem('Chosen_WarlockActiveM4'); +} + +//--------------------------------------------------------------------------------------- +private function bool MissionSitrepsBanRulers(XComGameState_MissionSite MissionState) +{ + local X2SitRepTemplateManager SitRepMgr; + local X2SitRepTemplate SitRepTemplate; + local name SitRepTemplateName; + local array TacTags; + + SitRepMgr = class'X2SitRepTemplateManager'.static.GetSitRepTemplateManager(); + + foreach MissionState.GeneratedMission.SitReps(SitRepTemplateName) + { + SitRepTemplate = SitRepMgr.FindSitRepTemplate(SitRepTemplateName); + TacTags = SitRepTemplate.ExcludeGameplayTags; + + if(TacTags.Length == 0) + { + continue; + } + + if(TacTags.Find('Ruler_ViperKingActive') != INDEX_NONE || TacTags.Find('Ruler_ViperKing_02') != INDEX_NONE || + TacTags.Find('Ruler_ViperKing_03') != INDEX_NONE || TacTags.Find('Ruler_ViperKing_04') != INDEX_NONE || + TacTags.Find('Ruler_BerserkerQueenActive') != INDEX_NONE || TacTags.Find('Ruler_BerserkerQueen_02') != INDEX_NONE || + TacTags.Find('Ruler_BerserkerQueen_03') != INDEX_NONE || TacTags.Find('Ruler_BerserkerQueen_04') != INDEX_NONE || + TacTags.Find('Ruler_ArchonKingActive') != INDEX_NONE || TacTags.Find('Ruler_ArchonKing_02') != INDEX_NONE || + TacTags.Find('Ruler_ArchonKing_03') != INDEX_NONE || TacTags.Find('Ruler_ArchonKing_04') != INDEX_NONE) + { + return true; + } + } + + return false; +} + +//--------------------------------------------------------------------------------------- +private function bool CanRulerAppearOnMission(XComGameState_MissionSite MissionState) +{ + return (!ChosenOnMission(MissionState) && !MissionSitrepsBanRulers(MissionState)); +} + +//--------------------------------------------------------------------------------------- +// Updates which Rulers are currently active +private function UpdateActiveAlienRulers() +{ + local XComGameStateHistory History; + local XComGameState_HeadquartersAlien AlienHQ; + local XComGameState_Unit UnitState; + local int idx, RulerIndex, ForceLevel; + local bool bXpackIntegrated; + + History = `XCOMHISTORY; + AlienHQ = XComGameState_HeadquartersAlien(History.GetSingleGameStateObjectForClass(class'XComGameState_HeadquartersAlien')); + ForceLevel = AlienHQ.GetForceLevel(); + bXpackIntegrated = class'X2Helpers_DLC_Day60'.static.IsXPackIntegrationEnabled(); + + for (idx = 0; idx < AllAlienRulers.Length; idx++) + { + UnitState = XComGameState_Unit(History.GetGameStateForObjectID(AllAlienRulers[idx].ObjectID)); + + if (UnitState != none) + { + RulerIndex = default.AlienRulerTemplates.Find('AlienRulerTemplateName', UnitState.GetMyTemplateName()); + + // Rulers can only appear naturally if DLC is not integrated with the XPack. Otherwise they appear on Alien Facilities. + if (!bXpackIntegrated && CanRulerBeActivated(RulerIndex, AllAlienRulers[idx], ForceLevel)) + { + ActiveAlienRulers.AddItem(AllAlienRulers[idx]); + } + else if (EscapedAlienRulers.Find('ObjectID', AllAlienRulers[idx].ObjectID) != INDEX_NONE) + { + // Only allow escaped rulers to reappear if ALL of the rulers have escaped or been killed + if ((DefeatedAlienRulers.Length + EscapedAlienRulers.Length) >= AllAlienRulers.Length) + { + EscapedAlienRulers.RemoveItem(AllAlienRulers[idx]); + ActiveAlienRulers.AddItem(AllAlienRulers[idx]); + } + } + } + } +} + +//--------------------------------------------------------------------------------------- +private function bool CanRulerBeActivated(int RulerIndex, StateObjectReference RulerRef, int ForceLevel) +{ + // Only allow new rulers to spawn if they: + // 1) Are at the appropriate force level + // 2) Are not already marked as active, escaped, or defeated + // 3) Does not have a specific location where it is waiting to spawn + if (RulerIndex != INDEX_NONE && + ForceLevel >= default.AlienRulerTemplates[RulerIndex].ForceLevel && + ActiveAlienRulers.Find('ObjectID', RulerRef.ObjectID) == INDEX_NONE && + EscapedAlienRulers.Find('ObjectID', RulerRef.ObjectID) == INDEX_NONE && + DefeatedAlienRulers.Find('ObjectID', RulerRef.ObjectID) == INDEX_NONE && + AlienRulerLocations.Find('RulerRef', RulerRef) == INDEX_NONE) + { + return true; + } + + return false; +} + +//--------------------------------------------------------------------------------------- +private function SetRulerOnCurrentMission(XComGameState NewGameState, XComGameState_Unit UnitState, XComGameState_HeadquartersXCom XComHQ) +{ + local int RulerIndex; + + RulerOnCurrentMission = UnitState.GetReference(); + RulerIndex = default.AlienRulerTemplates.Find('AlienRulerTemplateName', UnitState.GetMyTemplateName()); + XComHQ.TacticalGameplayTags.AddItem(default.AlienRulerTemplates[RulerIndex].ActiveTacticalTag); + AddRulerAdditionalTacticalTags(XComHQ, (class'X2Helpers_DLC_Day60'.static.GetRulerNumAppearances(UnitState) + 1), default.AlienRulerTemplates[RulerIndex]); +} + +//--------------------------------------------------------------------------------------- +private function bool AreAlienRulersAllowedToSpawn() +{ + local XComGameStateHistory History; + local XComGameState_CampaignSettings CampaignSettings; + + History = `XCOMHISTORY; + CampaignSettings = XComGameState_CampaignSettings(History.GetSingleGameStateObjectForClass(class'XComGameState_CampaignSettings')); + + if (CampaignSettings.HasIntegratedDLCEnabled()) + { + return true; // Rulers are always available if Integrated XPack DLC is enabled + } + else if (!CampaignSettings.HasOptionalNarrativeDLCEnabled(name(class'X2DownloadableContentInfo_DLC_Day60'.default.DLCIdentifier))) + { + return true; + } + + return class'XComGameState_HeadquartersXCom'.static.IsObjectiveCompleted('DLC_AlienNestMissionComplete'); +} + +//--------------------------------------------------------------------------------------- +function UpdateRulerStatsForDifficulty(XComGameState NewGameState) +{ + local X2CharacterTemplateManager CharMgr; + local X2CharacterTemplate CharTemplate; + local XComGameState_Unit UnitState; + local int idx; + + CharMgr = class'X2CharacterTemplateManager'.static.GetCharacterTemplateManager(); + + for (idx = 0; idx < AllAlienRulers.Length; idx++) + { + UnitState = XComGameState_Unit(`XCOMHISTORY.GetGameStateForObjectID(AllAlienRulers[idx].ObjectID)); + + // If the ruler has not yet been encountered by the player, reset their stats using the template from the new difficulty + if (class'X2Helpers_DLC_Day60'.static.GetRulerNumAppearances(UnitState) == 0) + { + UnitState = XComGameState_Unit(NewGameState.ModifyStateObject(class'XComGameState_Unit', UnitState.ObjectID)); + CharTemplate = CharMgr.FindCharacterTemplate(UnitState.GetMyTemplateName()); + UnitState.OnCreation(CharTemplate); // Reset their stat values to match the new difficulty template + } + + // Update all of the rulers escape health to reflect any health changes + // Also accounts for Nest edge case where Viper King is listed as having 1 appearance, even though it may not have been encountered yet + class'X2Helpers_DLC_Day60'.static.UpdateRulerEscapeHealth(UnitState); + } +} + +// ####################################################################################### +// ---------------------- XPACK INTEGRATION ---------------------------------------------- +// ####################################################################################### + +//--------------------------------------------------------------------------------------- +private function StateObjectReference GetRulerLocatedAtMission(XComGameState_MissionSite MissionState) +{ + local AlienRulerLocation RulerLocation; + + // If DLC is integrated with the XPack, rulers only appear for the first time on specific missions + if (class'X2Helpers_DLC_Day60'.static.IsXPackIntegrationEnabled()) + { + // Check to see if the ruler is located at this mission site + foreach AlienRulerLocations(RulerLocation) + { + if (RulerLocation.MissionRef.ObjectID == MissionState.ObjectID) + { + return RulerLocation.RulerRef; + } + } + } +} + +//--------------------------------------------------------------------------------------- +// Activates new rulers which will spawn at specific location. +// Only called when integrated DLC is on. +function bool ActivateRulerLocations() +{ + local XComGameStateHistory History; + local XComGameState_HeadquartersAlien AlienHQ; + local XComGameState_Unit UnitState; + local AlienRulerLocation RulerLocation; + local TDateTime ActivationTime; + local int idx, RulerIndex, ForceLevel; + local bool bUpdated; + + History = `XCOMHISTORY; + AlienHQ = XComGameState_HeadquartersAlien(History.GetSingleGameStateObjectForClass(class'XComGameState_HeadquartersAlien')); + ForceLevel = AlienHQ.GetForceLevel(); + + for (idx = 0; idx < AllAlienRulers.Length; idx++) + { + UnitState = XComGameState_Unit(History.GetGameStateForObjectID(AllAlienRulers[idx].ObjectID)); + + if (UnitState != none) + { + RulerIndex = default.AlienRulerTemplates.Find('AlienRulerTemplateName', UnitState.GetMyTemplateName()); + + // If a ruler can activate, calculate and set their activation timer + if (CanRulerBeActivated(RulerIndex, AllAlienRulers[idx], ForceLevel)) + { + ActivationTime = `STRATEGYRULES.GameTime; + class'X2StrategyGameRulesetDataStructures'.static.AddHours(ActivationTime, `SYNC_RAND(default.RulerLocationSpawnMaxHours + 1)); + + RulerLocation.RulerRef = AllAlienRulers[idx]; + RulerLocation.MissionRef.ObjectID = 0; + RulerLocation.ActivationTime = ActivationTime; + RulerLocation.bActivated = false; + RulerLocation.bNeedsPopup = false; + AlienRulerLocations.AddItem(RulerLocation); + bUpdated = true; + } + } + } + + return bUpdated; +} + +//--------------------------------------------------------------------------------------- +// Check activated ruler timers, and spawn them on alien facilities if they are completed. +// Only called when integrated DLC is on. +function bool UpdateRulerLocations() +{ + local XComGameStateHistory History; + local XComGameState_MissionSite MissionState; + local AlienRulerLocation RulerLocation; + local StateObjectReference BestMissionRef; + local int idx, MinLinksToResNetwork, NewLinkCount; + + if (AlienRulerLocations.Length > 0) + { + History = `XCOMHISTORY; + + foreach AlienRulerLocations(RulerLocation, idx) + { + if (!RulerLocation.bActivated && class'X2StrategyGameRulesetDataStructures'.static.LessThan(RulerLocation.ActivationTime, `STRATEGYRULES.GameTime)) + { + AlienRulerLocations[idx].bActivated = true; // The ruler is now activated, whether or not we find a mission to place it on + + foreach History.IterateByClassType(class'XComGameState_MissionSite', MissionState) + { + // Find the Alien Facility mission closest to the player Res Network which does not already have a Ruler + if (MissionState.Source == 'MissionSource_AlienNetwork' && MissionState.Available && AlienRulerLocations.Find('MissionRef', MissionState.GetReference()) == INDEX_NONE) + { + NewLinkCount = MissionState.GetWorldRegion().GetLinkCountToMinResistanceLevel(eResLevel_Contact); + if (NewLinkCount < MinLinksToResNetwork || BestMissionRef.ObjectID == 0) + { + BestMissionRef = MissionState.GetReference(); // Save the mission ref + MinLinksToResNetwork = NewLinkCount; // and update the link counter to the new min + } + } + } + + if (BestMissionRef.ObjectID != 0) + { + AlienRulerLocations[idx].MissionRef = BestMissionRef; // Save the mission ref + AlienRulerLocations[idx].bNeedsPopup = true; // Activate the popup since we found a mission + } + + // Don't need to iterate again for other rulers, because if we didn't find an Alien Facility the first time we won't on further iterations + // Always return true if a ruler activated, even if a mission location was not found, to save state change + return true; + } + } + } + + return false; +} + +//--------------------------------------------------------------------------------------- +// Attempt to spawn an activated ruler at a specific mission location +// Only called when integrated DLC is on. +function bool PlaceRulerAtLocation(StateObjectReference MissionRef) +{ + local AlienRulerLocation RulerLocation; + local int idx; + + if (AlienRulerLocations.Length > 0) + { + foreach AlienRulerLocations(RulerLocation, idx) + { + if (RulerLocation.bActivated && RulerLocation.MissionRef.ObjectID == 0) + { + // There was an activated ruler with no location, so set it at the new one and flag it to trigger a popup + AlienRulerLocations[idx].MissionRef = MissionRef; + AlienRulerLocations[idx].bNeedsPopup = true; + return true; + } + } + } + + return false; +} + +//--------------------------------------------------------------------------------------- +// Trigger any ruler alerts which have been queued +// Only called when integrated DLC is on. +function DisplayRulerPopup() +{ + local XComGameState NewGameState; + local XComGameState_AlienRulerManager RulerMgr; + local AlienRulerLocation RulerLocation; + local int idx; + + RulerMgr = XComGameState_AlienRulerManager(`XCOMHISTORY.GetGameStateForObjectID(ObjectID)); + + if (RulerMgr.AlienRulerLocations.Length > 0) + { + foreach RulerMgr.AlienRulerLocations(RulerLocation, idx) + { + if (RulerLocation.bNeedsPopup) + { + NewGameState = class'XComGameStateContext_ChangeContainer'.static.CreateChangeState("Display Ruler Popup"); + RulerMgr = XComGameState_AlienRulerManager(NewGameState.ModifyStateObject(class'XComGameState_AlienRulerManager', ObjectID)); + RulerMgr.AlienRulerLocations[idx].bNeedsPopup = false; + `XCOMGAME.GameRuleset.SubmitGameState(NewGameState); + + class'X2Helpers_DLC_Day60'.static.ShowRulerGuardingFacilityPopup(RulerLocation.MissionRef); + break; // Only display one popup at a time + } + } + } + +} + +//--------------------------------------------------------------------------------------- +DefaultProperties +{ +} \ No newline at end of file diff --git a/X2WOTCCommunityHighlander/X2WOTCCommunityHighlander.x2proj b/X2WOTCCommunityHighlander/X2WOTCCommunityHighlander.x2proj index bf24b0df9..5b46f734d 100644 --- a/X2WOTCCommunityHighlander/X2WOTCCommunityHighlander.x2proj +++ b/X2WOTCCommunityHighlander/X2WOTCCommunityHighlander.x2proj @@ -48,6 +48,9 @@ Content + + Content + Content From 64c8db92056db0fb4902f140064a669a1ee79e19 Mon Sep 17 00:00:00 2001 From: Xymanek Date: Mon, 10 Feb 2020 10:45:20 +0200 Subject: [PATCH 4/8] Implemented #771 --- .../Src/DLC_2/Classes/XComGameState_AlienRulerManager.uc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/X2WOTCCommunityHighlander/Src/DLC_2/Classes/XComGameState_AlienRulerManager.uc b/X2WOTCCommunityHighlander/Src/DLC_2/Classes/XComGameState_AlienRulerManager.uc index 3429b7b97..2484de61b 100644 --- a/X2WOTCCommunityHighlander/Src/DLC_2/Classes/XComGameState_AlienRulerManager.uc +++ b/X2WOTCCommunityHighlander/Src/DLC_2/Classes/XComGameState_AlienRulerManager.uc @@ -702,8 +702,9 @@ private function StateObjectReference GetRulerLocatedAtMission(XComGameState_Mis local AlienRulerLocation RulerLocation; // If DLC is integrated with the XPack, rulers only appear for the first time on specific missions - if (class'X2Helpers_DLC_Day60'.static.IsXPackIntegrationEnabled()) - { + // Issue #771 - removed this check. It's useless anyway as without the xpack integration enabled AlienRulerLocations will never be populated + //if (class'X2Helpers_DLC_Day60'.static.IsXPackIntegrationEnabled()) + //{ // Check to see if the ruler is located at this mission site foreach AlienRulerLocations(RulerLocation) { @@ -712,7 +713,7 @@ private function StateObjectReference GetRulerLocatedAtMission(XComGameState_Mis return RulerLocation.RulerRef; } } - } + //} } //--------------------------------------------------------------------------------------- From bd402ec0e5d26785d187547c0e37e49cafbfb3be Mon Sep 17 00:00:00 2001 From: Xymanek Date: Mon, 10 Feb 2020 10:51:43 +0200 Subject: [PATCH 5/8] Fix useless warnings --- .../Src/DLC_2/Classes/XComGameState_AlienRulerManager.uc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/X2WOTCCommunityHighlander/Src/DLC_2/Classes/XComGameState_AlienRulerManager.uc b/X2WOTCCommunityHighlander/Src/DLC_2/Classes/XComGameState_AlienRulerManager.uc index 2484de61b..e1deb7b5e 100644 --- a/X2WOTCCommunityHighlander/Src/DLC_2/Classes/XComGameState_AlienRulerManager.uc +++ b/X2WOTCCommunityHighlander/Src/DLC_2/Classes/XComGameState_AlienRulerManager.uc @@ -700,6 +700,7 @@ function UpdateRulerStatsForDifficulty(XComGameState NewGameState) private function StateObjectReference GetRulerLocatedAtMission(XComGameState_MissionSite MissionState) { local AlienRulerLocation RulerLocation; + local StateObjectReference EmptyRef; // CHL: warning fix // If DLC is integrated with the XPack, rulers only appear for the first time on specific missions // Issue #771 - removed this check. It's useless anyway as without the xpack integration enabled AlienRulerLocations will never be populated @@ -714,6 +715,9 @@ private function StateObjectReference GetRulerLocatedAtMission(XComGameState_Mis } } //} + + // CHL: warning fix + return EmptyRef; } //--------------------------------------------------------------------------------------- From faf51933c9011cc98b2529f16635f47563ff017b Mon Sep 17 00:00:00 2001 From: Xymanek Date: Sat, 29 Feb 2020 14:52:29 +0200 Subject: [PATCH 6/8] Remove un-privatisation that I did locally and by accident included in the PR --- .../Src/DLC_2/Classes/XComGameState_AlienRulerManager.uc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/X2WOTCCommunityHighlander/Src/DLC_2/Classes/XComGameState_AlienRulerManager.uc b/X2WOTCCommunityHighlander/Src/DLC_2/Classes/XComGameState_AlienRulerManager.uc index e1deb7b5e..34421806a 100644 --- a/X2WOTCCommunityHighlander/Src/DLC_2/Classes/XComGameState_AlienRulerManager.uc +++ b/X2WOTCCommunityHighlander/Src/DLC_2/Classes/XComGameState_AlienRulerManager.uc @@ -182,7 +182,7 @@ private function AddRulerAdditionalTacticalTags(XComGameState_HeadquartersXCom X } //--------------------------------------------------------------------------------------- -/*private*/ function int GetRulerAppearChance(XComGameState_Unit UnitState) +private function int GetRulerAppearChance(XComGameState_Unit UnitState) { local array AppearChances; local RulerReappearChance MaxAppearChance; From 76e1497ee8dd651e433fe6abf8b85280ef9ba40c Mon Sep 17 00:00:00 2001 From: Xymanek Date: Mon, 2 Mar 2020 14:27:27 +0200 Subject: [PATCH 7/8] Added DLC_2 version info (using approach from #765) --- .../Src/DLC_2/Classes/CHVersion_DLC2.uc | 15 ++ .../Classes/X2DLC2CH_CHXComGameVersion.uc | 38 ----- .../Classes/CHVersion_X2WOTCCH.uc | 15 ++ .../Classes/X2WOTCCH_Components.uc | 144 +++++++++++++++++- .../X2WOTCCommunityHighlander.x2proj | 5 +- 5 files changed, 172 insertions(+), 45 deletions(-) create mode 100644 X2WOTCCommunityHighlander/Src/DLC_2/Classes/CHVersion_DLC2.uc delete mode 100644 X2WOTCCommunityHighlander/Src/DLC_2/Classes/X2DLC2CH_CHXComGameVersion.uc create mode 100644 X2WOTCCommunityHighlander/Src/X2WOTCCommunityHighlander/Classes/CHVersion_X2WOTCCH.uc diff --git a/X2WOTCCommunityHighlander/Src/DLC_2/Classes/CHVersion_DLC2.uc b/X2WOTCCommunityHighlander/Src/DLC_2/Classes/CHVersion_DLC2.uc new file mode 100644 index 000000000..a8c369ddc --- /dev/null +++ b/X2WOTCCommunityHighlander/Src/DLC_2/Classes/CHVersion_DLC2.uc @@ -0,0 +1,15 @@ +class CHVersion_DLC2 extends Object; + +var int MajorVersion; +var int MinorVersion; +var int PatchVersion; +var string Commit; + +// AUTO-CODEGEN: Version-Info +defaultproperties +{ + MajorVersion = 1; + MinorVersion = 20; + PatchVersion = 0; + Commit = "%COMMIT%"; +} diff --git a/X2WOTCCommunityHighlander/Src/DLC_2/Classes/X2DLC2CH_CHXComGameVersion.uc b/X2WOTCCommunityHighlander/Src/DLC_2/Classes/X2DLC2CH_CHXComGameVersion.uc deleted file mode 100644 index 2440503cc..000000000 --- a/X2WOTCCommunityHighlander/Src/DLC_2/Classes/X2DLC2CH_CHXComGameVersion.uc +++ /dev/null @@ -1,38 +0,0 @@ -class X2DLC2CH_CHXComGameVersion extends X2StrategyElement; - -var int MajorVersion; -var int MinorVersion; -var int PatchVersion; -var string Commit; - -static function array CreateTemplates() -{ - local array Templates; - local X2StrategyElementTemplate XComGameVersion; - - `log("CreateTemplates",, 'DLC2CommunityHighlander'); - - if (class'CHXComGameVersionTemplate' != none) - { - `log("Creating CHDLC2Version with version" @ default.MajorVersion $ "." $ default.MinorVersion $ "." $ default.PatchVersion,, 'DLC2CommunityHighlander'); - - `CREATE_X2TEMPLATE(class'CHXComGameVersionTemplate', XComGameVersion, 'CHDLC2Version'); - CHXComGameVersionTemplate(XComGameVersion).MajorVersion = default.MajorVersion; - CHXComGameVersionTemplate(XComGameVersion).MinorVersion = default.MinorVersion; - CHXComGameVersionTemplate(XComGameVersion).PatchVersion = default.PatchVersion; - CHXComGameVersionTemplate(XComGameVersion).Commit = default.Commit; - - Templates.AddItem(XComGameVersion); - } - - return Templates; -} - -// AUTO-CODEGEN: Version-Info -defaultproperties -{ - MajorVersion = 1; - MinorVersion = 20; - PatchVersion = 0; - Commit = "RC1"; -} diff --git a/X2WOTCCommunityHighlander/Src/X2WOTCCommunityHighlander/Classes/CHVersion_X2WOTCCH.uc b/X2WOTCCommunityHighlander/Src/X2WOTCCommunityHighlander/Classes/CHVersion_X2WOTCCH.uc new file mode 100644 index 000000000..dd71aff23 --- /dev/null +++ b/X2WOTCCommunityHighlander/Src/X2WOTCCommunityHighlander/Classes/CHVersion_X2WOTCCH.uc @@ -0,0 +1,15 @@ +class CHVersion_X2WOTCCH extends Object; + +var int MajorVersion; +var int MinorVersion; +var int PatchVersion; +var string Commit; + +// AUTO-CODEGEN: Version-Info +defaultproperties +{ + MajorVersion = 1; + MinorVersion = 20; + PatchVersion = 0; + Commit = "%COMMIT%"; +} diff --git a/X2WOTCCommunityHighlander/Src/X2WOTCCommunityHighlander/Classes/X2WOTCCH_Components.uc b/X2WOTCCommunityHighlander/Src/X2WOTCCommunityHighlander/Classes/X2WOTCCH_Components.uc index fdcf5739b..9b73b4ccb 100644 --- a/X2WOTCCommunityHighlander/Src/X2WOTCCommunityHighlander/Classes/X2WOTCCH_Components.uc +++ b/X2WOTCCommunityHighlander/Src/X2WOTCCommunityHighlander/Classes/X2WOTCCH_Components.uc @@ -19,7 +19,21 @@ struct CHLComponent var CHLComponentStatus CompStatus; }; -//var config bool DLC2ReplacementEnabled; +struct CHLComponentVersion +{ + var int MajorVersion; + var int MinorVersion; + var int PatchVersion; + var string Commit; + + structdefaultproperties + { + MajorVersion = -1 + MinorVersion = -1 + PatchVersion = -1 + } +}; + //var config bool DLC3ReplacementEnabled; var localized string VersionFormat; @@ -31,27 +45,29 @@ var localized string VersionMismatches; var localized string WarningsLabel; var localized string ErrorsLabel; +delegate bool VersionInfoFetcher (out CHLComponentVersion VersionInfo); + static function array GetComponentInfo() { local X2StrategyElementTemplateManager Manager; local X2StrategyElementTemplate SelfVersion; - // local array DLCNames; + local CHLComponentVersion SelfVersionNew; + local array DLCNames; local array Comps; Manager = class'X2StrategyElementTemplateManager'.static.GetStrategyElementTemplateManager(); - // DLCNames = class'Helpers'.static.GetInstalledDLCNames(); + DLCNames = class'Helpers'.static.GetInstalledDLCNames(); SelfVersion = Manager.FindStrategyElementTemplate('CHWOTCVersion'); Comps.AddItem(BuildComponent(SelfVersion, none, "X2WOTCCommunityHighlander", true, true)); Comps.AddItem(BuildComponent(Manager.FindStrategyElementTemplate('CHEngineVersion'), SelfVersion, "Engine", true, true)); Comps.AddItem(BuildComponent(Manager.FindStrategyElementTemplate('CHXComGameVersion'), SelfVersion, "XComGame", true, true)); - /* FIXME: Uncomment when a DLC 2 Highlander is added if (DLCNames.Find("DLC_2") != INDEX_NONE) { - Comps.AddItem(BuildComponent(Manager.FindStrategyElementTemplate('CHDLC2Version'), SelfVersion, "DLC_2", false, default.DLC2ReplacementEnabled)); + CompanionVersionInfoFetcher(SelfVersionNew); + Comps.AddItem(BuildComponentNew(DLC2VersionInfoFetcher, "DLC_2", true, true, SelfVersionNew)); } - */ /* FIXME: Uncomment when a DLC_3 Highlander is added if (DLCNames.Find("DLC_3") != INDEX_NONE) @@ -111,6 +127,55 @@ static function CHLComponent BuildComponent(X2StrategyElementTemplate Template, return Comp; } +static function CHLComponent BuildComponentNew (delegate VersionFn, string ComponentName, bool Required, bool Expected, optional CHLComponentVersion CompareVersion) +{ + local CHLComponentVersion VersionInfo; + local CHLComponent Comp; + + Comp.DisplayName = ComponentName; + + if (GetCDO().CallVersionInfoFetcher(VersionFn, VersionInfo)) + { + Comp.DisplayVersion = FormatVersionNew(VersionInfo); + + if (CompareVersion.MajorVersion > -1) + { + if (GetVersionNumber(VersionInfo) == GetVersionNumber(CompareVersion)) + { + Comp.CompStatus = eCHLCS_OK; + } + else + { + Comp.CompStatus = eCHLCS_VersionMismatch; + } + } + else + { + Comp.CompStatus = eCHLCS_OK; + } + } + else + { + if (Required) + { + Comp.DisplayVersion = default.RequiredNotFound; + Comp.CompStatus = eCHLCS_RequiredNotFound; + } + else if (Expected) + { + Comp.DisplayVersion = default.ExpectedNotFound; + Comp.CompStatus = eCHLCS_ExpectedNotFound; + } + else + { + Comp.DisplayVersion = default.NotExpectedNotFound; + Comp.CompStatus = eCHLCS_NotExpectedNotFound; + } + } + + return Comp; +} + static function CHLComponentStatus FindHighestErrorLevel(const out array Components) { local CHLComponentStatus WorstStatus; @@ -143,4 +208,71 @@ static function string FormatVersion(X2StrategyElementTemplate Version) } return Ret; +} + +static function string FormatVersionNew (CHLComponentVersion Version) +{ + local string Ret; + + Ret = default.VersionFormat; + Ret = Repl(Ret, "%MAJOR", Version.MajorVersion); + Ret = Repl(Ret, "%MINOR", Version.MinorVersion); + Ret = Repl(Ret, "%PATCH", Version.PatchVersion); + + if (Version.Commit != "") + { + Ret @= "(" $ Version.Commit $ ")"; + } + + return Ret; +} + +//////////////////////// +/// Version fetchers /// +//////////////////////// +// Used by the new (non-template) version info system (see #765) + +static protected function bool DLC2VersionInfoFetcher (out CHLComponentVersion VersionInfo) +{ + if (class'CHVersion_DLC2' == none) return false; + + VersionInfo.MajorVersion = class'CHVersion_DLC2'.default.MajorVersion; + VersionInfo.MinorVersion = class'CHVersion_DLC2'.default.MinorVersion; + VersionInfo.PatchVersion = class'CHVersion_DLC2'.default.PatchVersion; + VersionInfo.Commit = class'CHVersion_DLC2'.default.Commit; + + return true; +} + +static protected function bool CompanionVersionInfoFetcher (out CHLComponentVersion VersionInfo) +{ + VersionInfo.MajorVersion = class'CHVersion_X2WOTCCH'.default.MajorVersion; + VersionInfo.MinorVersion = class'CHVersion_X2WOTCCH'.default.MinorVersion; + VersionInfo.PatchVersion = class'CHVersion_X2WOTCCH'.default.PatchVersion; + VersionInfo.Commit = class'CHVersion_X2WOTCCH'.default.Commit; + + return true; +} + +/////////////// +/// Helpers /// +/////////////// + +static protected function int GetVersionNumber (CHLComponentVersion VersionInfo) +{ + return (VersionInfo.MajorVersion * 100000000) + (VersionInfo.MinorVersion * 10000) + (VersionInfo.PatchVersion); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// Hack to workaround "Error, Can't call instance functions from within static functions" for delegates /// +//////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static function X2WOTCCH_Components GetCDO () +{ + return X2WOTCCH_Components(class'XComEngine'.static.GetClassDefaultObjectByName(default.Class.Name)); +} + +protected function bool CallVersionInfoFetcher (delegate VersionFn, out CHLComponentVersion VersionInfo) +{ + return VersionFn(VersionInfo); } \ No newline at end of file diff --git a/X2WOTCCommunityHighlander/X2WOTCCommunityHighlander.x2proj b/X2WOTCCommunityHighlander/X2WOTCCommunityHighlander.x2proj index 5b46f734d..8b1f360fc 100644 --- a/X2WOTCCommunityHighlander/X2WOTCCommunityHighlander.x2proj +++ b/X2WOTCCommunityHighlander/X2WOTCCommunityHighlander.x2proj @@ -45,7 +45,7 @@ Content - + Content @@ -60,6 +60,9 @@ Content + + Content + Content From b6d5b4657576de0d0c8039c8be0d44dd84c7fe19 Mon Sep 17 00:00:00 2001 From: Xymanek Date: Mon, 2 Mar 2020 21:39:07 +0200 Subject: [PATCH 8/8] Added docs --- .../XComGameState_AlienRulerManager.uc | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/X2WOTCCommunityHighlander/Src/DLC_2/Classes/XComGameState_AlienRulerManager.uc b/X2WOTCCommunityHighlander/Src/DLC_2/Classes/XComGameState_AlienRulerManager.uc index 34421806a..9a38b8486 100644 --- a/X2WOTCCommunityHighlander/Src/DLC_2/Classes/XComGameState_AlienRulerManager.uc +++ b/X2WOTCCommunityHighlander/Src/DLC_2/Classes/XComGameState_AlienRulerManager.uc @@ -704,6 +704,26 @@ private function StateObjectReference GetRulerLocatedAtMission(XComGameState_Mis // If DLC is integrated with the XPack, rulers only appear for the first time on specific missions // Issue #771 - removed this check. It's useless anyway as without the xpack integration enabled AlienRulerLocations will never be populated + /// HL-Docs: feature:NonIntegratedAlienRulerLocations; issue:771; tags:strategy + /// Mods can force a specific ruler to be present on a specific mission using XComGameState_AlienRulerManager::AlienRulerLocations - + /// the same mechanism that XPACK integration uses/introduces to make rulers wait in specific alien facilities. + /// + /// This could be done even without the CHL patch, but it wouldn't work if DLC is not run in the integrated mode. + /// With this CHL patch, you can use that mechanism safely in both integrated and non-integrated mode. + /// Note that when the non-integrated mode is enabled, the AlienRulerLocations array is not populated by the DLC + /// + /// Example usage: + /// ```unreascript + /// local XComGameState_AlienRulerManager RulerManager; + /// local AlienRulerLocation RulerLocation; + /// + /// RulerLocation.RulerRef = RulerManager.GetAlienRulerReference('ViperKing'); + /// RulerLocation.MissionRef = MissionRef; + /// RulerLocation.bActivated = true; + /// RulerLocation.bNeedsPopup = false; + /// + /// RulerManager.AlienRulerLocations.AddItem(RulerLocation); + /// ``` //if (class'X2Helpers_DLC_Day60'.static.IsXPackIntegrationEnabled()) //{ // Check to see if the ruler is located at this mission site