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 5bdd8d8b6..000000000
Binary files a/Components/DLC2CommunityHighlander/DLC2CommunityHighlander/ModPreview.jpg and /dev/null differ
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
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/XComGameState_AlienRulerManager.uc b/X2WOTCCommunityHighlander/Src/DLC_2/Classes/XComGameState_AlienRulerManager.uc
new file mode 100644
index 000000000..9a38b8486
--- /dev/null
+++ b/X2WOTCCommunityHighlander/Src/DLC_2/Classes/XComGameState_AlienRulerManager.uc
@@ -0,0 +1,898 @@
+//---------------------------------------------------------------------------------------
+// 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;
+ 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
+ /// 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
+ foreach AlienRulerLocations(RulerLocation)
+ {
+ if (RulerLocation.MissionRef.ObjectID == MissionState.ObjectID)
+ {
+ return RulerLocation.RulerRef;
+ }
+ }
+ //}
+
+ // CHL: warning fix
+ return EmptyRef;
+}
+
+//---------------------------------------------------------------------------------------
+// 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/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 e80c2f071..8b1f360fc 100644
--- a/X2WOTCCommunityHighlander/X2WOTCCommunityHighlander.x2proj
+++ b/X2WOTCCommunityHighlander/X2WOTCCommunityHighlander.x2proj
@@ -13,8 +13,10 @@
+
+
@@ -43,6 +45,12 @@
Content
+
+ Content
+
+
+ Content
+
Content
@@ -52,6 +60,9 @@
Content
+
+ Content
+
Content
@@ -750,4 +761,4 @@
-
+
\ No newline at end of file