diff --git a/Assets/NaturalAptitudeIcon.png b/Assets/NaturalAptitudeIcon.png new file mode 100644 index 0000000..6454461 Binary files /dev/null and b/Assets/NaturalAptitudeIcon.png differ diff --git a/RPG/Config/StatUpgradeUI/XComUI.ini b/RPG/Config/StatUpgradeUI/XComStatUpgradeUI.ini similarity index 73% rename from RPG/Config/StatUpgradeUI/XComUI.ini rename to RPG/Config/StatUpgradeUI/XComStatUpgradeUI.ini index fd57d7d..0c62d3d 100644 --- a/RPG/Config/StatUpgradeUI/XComUI.ini +++ b/RPG/Config/StatUpgradeUI/XComStatUpgradeUI.ini @@ -29,4 +29,24 @@ HealthDeltaStrikeCostLamda = 15 DefaultStatPointsPerPromotion=15 ; Class specific stat points override DefaultStatPointsPerPromotion -; +ClassStatPointsPerPromotion=(SoldierClassTemplateName=UniversalSoldier, StatPointsPerPromotion=20) \ No newline at end of file +; +ClassStatPointsPerPromotion=(SoldierClassTemplateName=UniversalSoldier, StatPointsPerPromotion=20) + +[StatUpgradeUI.StatUIHelper] +NaturalAptitudeAboveAverageChance=50 +NaturalAptitudeThresholds[0]=50 ; 25% chance +NaturalAptitudeThresholds[1]=80 ; 15% chance +NaturalAptitudeThresholds[2]=99 ; 9.5% chance +NaturalAptitudeThresholds[3]=100 ; 0.5% chance + ++NaturalAptitudeCharacterTemplates = Soldier ++NaturalAptitudeCharacterTemplates = ReaperSoldier ++NaturalAptitudeCharacterTemplates = SkirmisherSoldier ++NaturalAptitudeCharacterTemplates = TemplarSoldier ++NaturalAptitudeCharacterTemplates = XComMecSoldier ++NaturalAptitudeCharacterTemplates = SkirmXComMecSoldier + +BaseSoldierNaturalAptitude[0]=0 +BaseSoldierNaturalAptitude[1]=5 +BaseSoldierNaturalAptitude[2]=10 +BaseSoldierNaturalAptitude[3]=15 +BaseSoldierNaturalAptitude[4]=20 \ No newline at end of file diff --git a/RPG/Config/XComEngine.ini b/RPG/Config/XComEngine.ini index dcc5f2a..e84cc9c 100644 --- a/RPG/Config/XComEngine.ini +++ b/RPG/Config/XComEngine.ini @@ -5,9 +5,9 @@ +NonNativePackages=XModBase_Lib +NonNativePackages=XCOM2RPGOverhaul +NonNativePackages=ExtendedUpgrades -+NonNativePackages=DetailedSoldierListWOTC +NonNativePackages=NewPromotionScreenbyDefault +NonNativePackages=StatUpgradeUI ++NonNativePackages=DetailedSoldierListWOTC +NonNativePackages=Debug [UnrealEd.EditorEngine] @@ -17,9 +17,9 @@ +ModEditPackages=XModBase_Core_2_0_1 +ModEditPackages=XModBase_Lib +ModEditPackages=ExtendedUpgrades -+ModEditPackages=DetailedSoldierListWOTC +ModEditPackages=NewPromotionScreenbyDefault +ModEditPackages=StatUpgradeUI ++ModEditPackages=DetailedSoldierListWOTC +ModEditPackages=Debug [Engine.Engine] diff --git a/RPG/Content/DetailedSoldierListWOTC/UILibrary_LWToolbox.upk b/RPG/Content/DetailedSoldierListWOTC/UILibrary_LWToolbox.upk index 42e296f..320932e 100644 Binary files a/RPG/Content/DetailedSoldierListWOTC/UILibrary_LWToolbox.upk and b/RPG/Content/DetailedSoldierListWOTC/UILibrary_LWToolbox.upk differ diff --git a/RPG/Localization/StatUpgradeUI.int b/RPG/Localization/StatUpgradeUI.int index e4e2320..c6b8c87 100644 --- a/RPG/Localization/StatUpgradeUI.int +++ b/RPG/Localization/StatUpgradeUI.int @@ -7,4 +7,14 @@ m_UpgradeCostHeader="SUM COSTS" m_strSoldierSPLabel="SOLDIER SP" [UIPanel_StatUI_StatLine] -PsiOffenseLabel="PSI" \ No newline at end of file +PsiOffenseLabel="PSI" + +[StatUIHelper] +NaturalAptitude="NATURAL APTITUDE" + +NaturalAptitudeLabel[0]="Mortal" +NaturalAptitudeLabel[1]="Good Genes" +NaturalAptitudeLabel[2]="Peak Human" +NaturalAptitudeLabel[3]="Super Human" +NaturalAptitudeLabel[4]="Godlike" + diff --git a/RPG/RPG.x2proj b/RPG/RPG.x2proj index c7e6e91..14486c8 100644 --- a/RPG/RPG.x2proj +++ b/RPG/RPG.x2proj @@ -62,7 +62,7 @@ tags=Gameplay, Soldier Class, Overhaul, RPG, Weapon, Item Content - + Content @@ -209,6 +209,9 @@ tags=Gameplay, Soldier Class, Overhaul, RPG, Weapon, Item Content + + Content + Content diff --git a/RPG/ReadMe.txt b/RPG/ReadMe.txt index cbb3614..5860339 100644 --- a/RPG/ReadMe.txt +++ b/RPG/ReadMe.txt @@ -127,6 +127,12 @@ Known incompatibilities: - "Hack Plus" leads to insane high hacking stats - I am the commander here + +[b]My soldier keep getting promited to basegame/other classes?[/b] +Its a strange bug cause by the config system for some people. +Use the mod Disable Any Class Wotc and disable all classes but UniversalSoldier in the ingame mod options. +https://steamcommunity.com/sharedfiles/filedetails/?id=1148535137 + [h1]A note on the beta status[/h1] This mod will change frequently. Therefor it might be needed that you rebuild you soldiers. diff --git a/RPG/Src/DetailedSoldierListWOTC/Classes/UIPersonnel_SoldierListItemDetailed.uc b/RPG/Src/DetailedSoldierListWOTC/Classes/UIPersonnel_SoldierListItemDetailed.uc index 8f74573..4ead365 100644 --- a/RPG/Src/DetailedSoldierListWOTC/Classes/UIPersonnel_SoldierListItemDetailed.uc +++ b/RPG/Src/DetailedSoldierListWOTC/Classes/UIPersonnel_SoldierListItemDetailed.uc @@ -16,9 +16,9 @@ var UIText AimValue, DefenseValue; //icons to be shown in the name area var UIImage HealthIcon, MobilityIcon, WillIcon, HackIcon, DodgeIcon, PsiIcon, PrimaryWeaponIcon, SecondaryWeaponIcon; -var UIText HealthValue, MobilityValue, WillValue, HackValue, DodgeValue, PsiValue; +var UIText HealthValue, MobilityValue, WillValue, HackValue, DodgeValue, PsiValue, SPValue; -var UIIcon APIcon; +var UIIcon APIcon, NatAptIcon; var array BadTraitIcon; @@ -541,6 +541,27 @@ function AddNameColumnIcons(XComGameState_Unit Unit, out string traitToolTip) } } + if (NatAptIcon == none) + { + NatAptIcon = Spawn(class'UIIcon', self); + NatAptIcon.bAnimateOnInit = false; + NatAptIcon.bDisableSelectionBrackets = true; + NatAptIcon.InitIcon('NaturalAptitudeIcon', "img:///UILibrary_LWToolbox.UI.NaturalAptitudeIcon", false, false); + } + IconXPos += IconXDelta; + NatAptIcon.SetScale(IconScale * 0.6); + NatAptIcon.SetPosition(IconXPos - (IconToValueOffsetX * 0.1), IconYPos); + NatAptIcon.Show(); + + if(SPValue == none) + { + SPValue = Spawn(class'UIText', self); + SPValue.bAnimateOnInit = false; + SPValue.InitText('SPValue_ListItem_LW').SetPosition(IconXPos + IconToValueOffsetX, IconYPos + IconToValueOffsetY); + } + SPValue.SetHtmlText(class'UIUtilities_Text'.static.GetColoredText(string(class'StatUpgradeUI.StatUIHelper'.static.GetSoldierSP(Unit)), eUIState_Normal)); + SPValue.Show(); + PrimaryLoadoutImage = "img:///UILibrary_RPG.loadout_icon_" $ string(X2WeaponTemplate(Unit.GetPrimaryWeapon().GetMyTemplate()).WeaponCat); SecondaryLoadoutImage = "img:///UILibrary_RPG.loadout_icon_" $ string(X2WeaponTemplate(Unit.GetSecondaryWeapon().GetMyTemplate()).WeaponCat); @@ -548,7 +569,7 @@ function AddNameColumnIcons(XComGameState_Unit Unit, out string traitToolTip) { PrimaryWeaponIcon = Spawn(class'UIImage', self); PrimaryWeaponIcon.bAnimateOnInit = false; - PrimaryWeaponIcon.InitImage('PrimaryLoadoutImage_ListItem', PrimaryLoadoutImage).SetScale(IconScale).SetPosition(IconXPos += 35, -9.0f); + PrimaryWeaponIcon.InitImage('PrimaryLoadoutImage_ListItem', PrimaryLoadoutImage).SetScale(IconScale).SetPosition(IconXPos += 35 - IconXDelta, -9.0f); } if (SecondaryWeaponIcon == none && Unit.GetSecondaryWeapon() != none) @@ -559,7 +580,7 @@ function AddNameColumnIcons(XComGameState_Unit Unit, out string traitToolTip) } - IconXPos += IconXDelta; + //IconXPos += IconXDelta; EventTemplateManager = class'X2EventListenerTemplateManager'.static.GetEventListenerTemplateManager(); @@ -674,6 +695,11 @@ simulated function UpdateItemsForFocus(bool Focussed) { APIcon.SetForegroundColor(APColours[int(Unit.ComInt)]); } + + if (NatAptIcon != none) + { + NatAptIcon.SetForegroundColor(APColours[int(class'StatUpgradeUI.StatUIHelper'.static.GetNaturalAptitude(Unit))]); + } } } diff --git a/RPG/Src/StatUpgradeUI/Classes/StatUIHelper.uc b/RPG/Src/StatUpgradeUI/Classes/StatUIHelper.uc new file mode 100644 index 0000000..7817377 --- /dev/null +++ b/RPG/Src/StatUpgradeUI/Classes/StatUIHelper.uc @@ -0,0 +1,105 @@ +class StatUIHelper extends Object config(StatUpgradeUI); + +enum ENaturalAptitude +{ + eNaturalAptitude_Standard, + eNaturalAptitude_AboveAverage, + eNaturalAptitude_Gifted, + eNaturalAptitude_Genius, + eNaturalAptitude_Savant, +}; + + +var config array NaturalAptitudeCharacterTemplates; +var config array NaturalAptitudeThresholds; +var config int NaturalAptitudeAboveAverageChance; +var config array BaseSoldierNaturalAptitude; + +var localized string NaturalAptitudeLabel[ENaturalAptitude.EnumCount]; +var localized string NaturalAptitude; + +static function OnPostCharacterTemplatesCreated() +{ + local X2CharacterTemplateManager CharacterTemplateMgr; + local X2CharacterTemplate SoldierTemplate; + local array DataTemplates; + local int ScanTemplates, ScanAdditions; + + CharacterTemplateMgr = class'X2CharacterTemplateManager'.static.GetCharacterTemplateManager(); + + for ( ScanAdditions = 0; ScanAdditions < default.NaturalAptitudeCharacterTemplates.Length; ++ScanAdditions ) + { + CharacterTemplateMgr.FindDataTemplateAllDifficulties(default.NaturalAptitudeCharacterTemplates[ScanAdditions], DataTemplates); + for (ScanTemplates = 0; ScanTemplates < DataTemplates.Length; ++ScanTemplates) + { + SoldierTemplate = X2CharacterTemplate(DataTemplates[ScanTemplates]); + if (SoldierTemplate != none) + { + SoldierTemplate.OnStatAssignmentCompleteFn = class'StatUIHelper'.static.OnStatAssignmentCompleteNaturalAptitude; + } + } + } +} + +static function OnStatAssignmentCompleteNaturalAptitude(XComGameState_Unit UnitState) +{ + local ENaturalAptitude Apt; + + Apt = RollNaturalAptitude(); + + //`LOG(default.Class @ GetFuncName() @ Apt @ float(Apt),, 'RPG'); + UnitState.SetUnitFloatValue('NaturalAptitude', float(Apt) , eCleanUp_Never); +} + +static function int GetBonusStatPointsFromNaturalAptitude(XComGameState_Unit UnitState) +{ + //`LOG(default.Class @ GetFuncName() @ default.BaseSoldierNaturalAptitude[GetNaturalAptitude(UnitState)],, 'RPG'); + return default.BaseSoldierNaturalAptitude[GetNaturalAptitude(UnitState)]; +} + +static function ENaturalAptitude GetNaturalAptitude(XComGameState_Unit UnitState) +{ + local UnitValue NaturalAptitudeValue; + + UnitState.GetUnitValue('NaturalAptitude', NaturalAptitudeValue); + + //`LOG(default.Class @ GetFuncName() @ NaturalAptitudeValue.fValue @ GetEnum(Enum'ENaturalAptitude', NaturalAptitudeValue.fValue),, 'RPG'); + + return ENaturalAptitude(NaturalAptitudeValue.fValue); +} + +static function ENaturalAptitude RollNaturalAptitude() +{ + local array Thresholds; + local int idx, NaturalAptitudeRoll; + + if (class'X2StrategyGameRulesetDataStructures'.static.Roll(default.NaturalAptitudeAboveAverageChance)) + { + Thresholds = default.NaturalAptitudeThresholds; + NaturalAptitudeRoll = `SYNC_RAND_STATIC(100); + + for (idx = 0; idx < Thresholds.Length; idx++) + { + if (NaturalAptitudeRoll < Thresholds[idx]) + { + return ENaturalAptitude(1 + idx); + break; + } + } + } + + return eNaturalAptitude_Standard; +} + +static function string GetNaturalAptitudeLabel(ENaturalAptitude NatApt) +{ + //`LOG(default.Class @ GetFuncName() @ NatApt @ default.NaturalAptitudeLabel[NatApt] @ default.NaturalAptitudeLabel[eNaturalAptitude_Standard],, 'RPGO'); + return default.NaturalAptitudeLabel[NatApt]; +} + +static function int GetSoldierSP(XComGameState_Unit UnitState) +{ + local UnitValue StatPointsValue; + UnitState.GetUnitValue('StatPoints', StatPointsValue); + return int(StatPointsValue.fValue); +} \ No newline at end of file diff --git a/RPG/Src/StatUpgradeUI/Classes/UIPanel_StatUI_StatLine.uc b/RPG/Src/StatUpgradeUI/Classes/UIPanel_StatUI_StatLine.uc index 42a2dbe..2684587 100644 --- a/RPG/Src/StatUpgradeUI/Classes/UIPanel_StatUI_StatLine.uc +++ b/RPG/Src/StatUpgradeUI/Classes/UIPanel_StatUI_StatLine.uc @@ -1,4 +1,4 @@ -class UIPanel_StatUI_StatLine extends UIPanel config (UI); +class UIPanel_StatUI_StatLine extends UIPanel config (StatUpgradeUI); struct StatCostBind { diff --git a/RPG/Src/StatUpgradeUI/Classes/UIScreen_StatUI.uc b/RPG/Src/StatUpgradeUI/Classes/UIScreen_StatUI.uc index 455e036..adb08c7 100644 --- a/RPG/Src/StatUpgradeUI/Classes/UIScreen_StatUI.uc +++ b/RPG/Src/StatUpgradeUI/Classes/UIScreen_StatUI.uc @@ -1,4 +1,4 @@ -class UIScreen_StatUI extends UIArmory config(UI); +class UIScreen_StatUI extends UIArmory config(StatUpgradeUI); var UIPanel Container; var UIBGBox PanelBG; @@ -6,7 +6,7 @@ var UIBGBox FullBG; var UIX2PanelHeader TitleHeader; var UIImage SCImage; var UIButton SaveButton; -var UIText StatPointsText, AbilityPointsText, StatNameHeader, StatValueHeader, UpgradePointsHeader, StatCostHeader, UpgradeCostHeader; +var UIText NaturalAptitudeText, StatPointsText, AbilityPointsText, StatNameHeader, StatValueHeader, UpgradePointsHeader, StatCostHeader, UpgradeCostHeader; var array StatLines; var bool bLog; @@ -54,6 +54,10 @@ function InitPanels() AbilityPointsText.SetWidth(200); AbilityPointsText.SetPosition(Container.Width - AbilityPointsText.Width - StatPointsText.Width - LeftPadding, LeftPadding); + NaturalAptitudeText = Spawn(class'UIText', Container).InitText('NaturalAptitudeText'); + NaturalAptitudeText.SetWidth(450); + NaturalAptitudeText.SetPosition(Container.Width - NaturalAptitudeText.Width - LeftPadding, LeftPadding * 2); + TitleHeader = Spawn(class'UIX2PanelHeader', Container); TitleHeader.InitPanelHeader('', "", ""); TitleHeader.SetPosition(SCImage.Width + RunningHeaderOffsetX + 10, LeftPadding); @@ -116,7 +120,6 @@ function InitStatLines() { local UIPanel_StatUI_StatLine StatLine; local int Index, OffsetX, OffsetY; - local UnitValue StatPointsValue; local bool bUseBetaStrikeHealthProgression; bUseBetaStrikeHealthProgression = UnitState.GetSoldierClassTemplateName() == 'UniversalSoldier'; @@ -162,6 +165,8 @@ function InitStatLines() function PopulateHeaderData() { + local string NaturalAptitude; + if (UnitState.GetSoldierClassTemplate() != none) { SCImage.LoadImage(UnitState.GetSoldierClassIcon()); @@ -170,6 +175,9 @@ function PopulateHeaderData() TitleHeader.SetText(UnitState.GetName(eNameType_FullNick), Caps(UnitState.IsSoldier() ? UnitState.GetSoldierClassDisplayName() : "")); TitleHeader.MC.FunctionVoid("realize"); + + NaturalAptitude = class'UIUtilities_Text'.static.AlignRight(class'UIUtilities_Text'.static.GetColoredText(class'StatUIHelper'.default.NaturalAptitude $ ":" @ Caps(class'StatUIHelper'.static.GetNaturalAptitudeLabel(class'StatUIHelper'.static.GetNaturalAptitude(UnitState))), eUIState_Normal, FontSize)); + NaturalAptitudeText.SetHtmlText(NaturalAptitude); } function PopulateSoldierPoints() @@ -179,7 +187,7 @@ function PopulateSoldierPoints() CurrentSP = Max(GetSoldierSP() - StatPointCostSum, 0); CurrentAP = GetSoldierAP() - AbilityPointCostSum - Min(GetSoldierSP() - StatPointCostSum, 0); - StatPointsText.SetHtmlText(class'UIUtilities_Text'.static.GetColoredText(m_strSoldierSPLabel @ string(CurrentSP), eUIState_Normal, FontSize)); + StatPointsText.SetHtmlText(class'UIUtilities_Text'.static.AlignRight(class'UIUtilities_Text'.static.GetColoredText(m_strSoldierSPLabel @ string(CurrentSP), eUIState_Normal, FontSize))); AbilityPointsText.SetHtmlText(class'UIUtilities_Text'.static.GetColoredText(class'UIArmory_PromotionHero'.default.m_strSoldierAPLabel @ string(CurrentAP), eUIState_Normal, FontSize)); } @@ -360,7 +368,7 @@ simulated function bool IsAllowedToCycleSoldiers() defaultproperties { - StatOffsetY=70 + StatOffsetY=90 LeftPadding=40 Padding=20 FontSize=32 diff --git a/RPG/Src/StatUpgradeUI/Classes/X2DownloadableContentInfo_StatUpgradeUI.uc b/RPG/Src/StatUpgradeUI/Classes/X2DownloadableContentInfo_StatUpgradeUI.uc index 4e92ed8..b02d2e4 100644 --- a/RPG/Src/StatUpgradeUI/Classes/X2DownloadableContentInfo_StatUpgradeUI.uc +++ b/RPG/Src/StatUpgradeUI/Classes/X2DownloadableContentInfo_StatUpgradeUI.uc @@ -1,6 +1,9 @@ class X2DownloadableContentInfo_StatUpgradeUI extends X2DownloadableContentInfo; - +static event OnPostTemplatesCreated() +{ + class'StatUIHelper'.static.OnPostCharacterTemplatesCreated(); +} exec function DebugStatUIHeader( int StatNameHeaderWidth, diff --git a/RPG/Src/StatUpgradeUI/Classes/X2EventListener_StatUI.uc b/RPG/Src/StatUpgradeUI/Classes/X2EventListener_StatUI.uc index c876e48..d98cc3b 100644 --- a/RPG/Src/StatUpgradeUI/Classes/X2EventListener_StatUI.uc +++ b/RPG/Src/StatUpgradeUI/Classes/X2EventListener_StatUI.uc @@ -1,4 +1,4 @@ -class X2EventListener_StatUI extends X2EventListener config(UI); +class X2EventListener_StatUI extends X2EventListener config(StatUpgradeUI); struct ClassStatPoints { @@ -70,7 +70,6 @@ static function CHEventListenerTemplate CreateListenerTemplate_OnCompleteRespecS static function EventListenerReturn OnCompleteRespecSoldier(Object EventData, Object EventSource, XComGameState GameState, Name Event, Object CallbackData) { local XComGameState_Unit UnitState; - local UnitValue StatPointsValue; local int SpentSoldierSP, SoldierSP; UnitState = XComGameState_Unit(EventData); @@ -90,17 +89,20 @@ static function EventListenerReturn OnUnitRankUp(Object EventData, Object EventS { local XComGameState_Unit UnitState; local UnitValue StatPointsValue; - local int StatPointsPerPromotion; + local int StatPointsPerPromotion, BonusStatPointsNaturalAptitude; UnitState = XComGameState_Unit(EventData); if (UnitState != none) { StatPointsPerPromotion = GetClassStatPointsPerPromition(UnitState); - - UnitState = XComGameState_Unit(GameState.CreateStateObject(class'XComGameState_Unit', UnitState.ObjectID)); + BonusStatPointsNaturalAptitude = class'StatUIHelper'.static.GetBonusStatPointsFromNaturalAptitude(UnitState); + UnitState = XComGameState_Unit(GameState.CreateStateObject(class'XComGameState_Unit', UnitState.ObjectID)); UnitState.GetUnitValue('StatPoints', StatPointsValue); - UnitState.SetUnitFloatValue('StatPoints', StatPointsValue.fValue + StatPointsPerPromotion, eCleanup_Never); + + `LOG(default.Class @ GetFuncName() @ "StatPointsValue" @ int(StatPointsValue.fValue) @ "StatPointsPerPromotion" @ StatPointsPerPromotion @ "BonusStatPointsNaturalAptitude" @ BonusStatPointsNaturalAptitude,, 'RPG'); + + UnitState.SetUnitFloatValue('StatPoints', StatPointsValue.fValue + StatPointsPerPromotion + BonusStatPointsNaturalAptitude, eCleanup_Never); GameState.AddStateObject(UnitState); } diff --git a/RPG/Src/XCOM2RPGOverhaul/Classes/X2TemplateHelper_RPGOverhaul.uc b/RPG/Src/XCOM2RPGOverhaul/Classes/X2TemplateHelper_RPGOverhaul.uc index b2b7819..aa08242 100644 --- a/RPG/Src/XCOM2RPGOverhaul/Classes/X2TemplateHelper_RPGOverhaul.uc +++ b/RPG/Src/XCOM2RPGOverhaul/Classes/X2TemplateHelper_RPGOverhaul.uc @@ -270,8 +270,17 @@ static function PatchAbilitiesWeaponCondition() WeaponCondition.IncludeWeaponCategories = Restriction.WeaponCategories; Template.AbilityTargetConditions.AddItem(WeaponCondition); - Template.eAbilityIconBehaviorHUD = eAbilityIconBehavior_HideSpecificErrors; - Template.HideErrors.AddItem('AA_WeaponIncompatible'); + // Hide active abilities if no weapon matches + if ( + (Template.eAbilityIconBehaviorHUD == eAbilityIconBehavior_AlwaysShow || + Template.eAbilityIconBehaviorHUD == eAbilityIconBehavior_HideSpecificErrors) && + !Template.bIsPassive && + Template.HasTrigger('X2AbilityTrigger_PlayerInput') + ) + { + Template.eAbilityIconBehaviorHUD = eAbilityIconBehavior_HideSpecificErrors; + Template.HideErrors.AddItem('AA_WeaponIncompatible'); + } } } } @@ -576,7 +585,6 @@ static function UpdateStorage() } } - static function PatchAbilityPrerequisites() { local X2AbilityTemplateManager TemplateManager;