From 7ea3e2754cee38df3a0e5fb277c32e1244ae0692 Mon Sep 17 00:00:00 2001 From: robojumper Date: Thu, 5 Mar 2020 20:43:28 +0100 Subject: [PATCH 01/10] UI Docs: UIAvengerShortcuts_ShowCQResistanceOrders, Geoscape_ResInfoButtonVisible, GetCovertActionEvents_Settings, UIStrategyPolicy_ScreenInit, UIStrategyPolicy_ShowCovertActionsOnClose, OverrideImageForItemAvaliable, UIScanButtonOnMouseEvent --- CHANGELOG.md | 7 ------ .../Src/XComGame/Classes/UIAlert.uc | 12 ++++++++++ .../XComGame/Classes/UIAvengerShortcuts.uc | 11 +++++++++- .../Src/XComGame/Classes/UIScanButton.uc | 4 ++++ .../Src/XComGame/Classes/UIStrategyMap_HUD.uc | 9 ++++++++ .../Src/XComGame/Classes/UIStrategyPolicy.uc | 22 +++++++++++++++++++ .../Classes/XComGameState_HeadquartersXCom.uc | 13 +++++++++++ 7 files changed, 70 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 40e9595f0..c323463d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,18 +50,13 @@ RunPriorityGroup=RUN_STANDARD - Triggers the events `OverrideUIArmoryScale`, `OverrideUIVIPScale`, and `OverrideCharCustomizationScale` for strategy unit scaling (#229) - Triggers the event `RegionOutpostBuildStart` to add a strategy reward similar to the 'Resistance Network' resistance order, but for Radio Relays instead of Network Contacts. (#279) - Triggers the event `GeoscapeFlightModeUpdate` to allow mods to respond to geoscape mode change (#358) -- Triggers the event `UIAvengerShortcuts_ShowCQResistanceOrders` to allow to override the presence of Resistance Orders button in `UIAvengerShortcuts` (#368) -- Triggers the event `Geoscape_ResInfoButtonVisible` to allow to override the visibility of resistance orders button in `UIStrategyMap_HUD` (#365) - Triggers the event `NumCovertActionsToAdd` to allow mods to modfiy number of Covert Actions (#373) - Triggers the event `CompleteRespecSoldier` when a training center soldier respec was completed. (#339) - Triggers the events `UIArmory_WeaponUpgrade_SlotsUpdated` and `UIArmory_WeaponUpgrade_NavHelpUpdated` in `UIArmory_WeaponUpgrade` (#417) -- Triggers the event `GetCovertActionEvents_Settings` to allow showing all covert actions in the correct order in the event queue (#391) - Triggers the event `CovertActionRisk_AlterChanceModifier` when calculated covert action risks. (#434) - Triggers the event `AllowDarkEventRisk` during XComGameState_CovertAction::EnableDarkEventRisk to allow alterations of standard logic (#434) - Triggers the event `AllowDarkEventRisk` during XComGameState_CovertAction::CreateRisks to allow alterations of standard logic (#692) -- Triggers the event `UIStrategyPolicy_ScreenInit` at the end of UIStrategyPolicy::InitScreen (#440) -- Triggers the event `UIStrategyPolicy_ShowCovertActionsOnClose` on UIStrategyPolicy::CloseScreen call (#440) - Triggers the event `CovertAction_ShouldBeVisible` on XComGameState_CovertAction::ShouldBeVisible call (#438) - Triggers the event `CovertAction_CanInteract` on XComGameState_CovertAction::CanInteract call (#438) - Triggers the event `CovertAction_ActionSelectedOverride` on XComGameState_CovertAction::DisplaySelectionPrompt call (#438) @@ -70,7 +65,6 @@ RunPriorityGroup=RUN_STANDARD - Triggers the event `CovertAction_ModifyNarrativeParamTag` on XComGameState_CovertAction::GetNarrative call (#438) - Triggers the event `ShouldCleanupCovertAction` to allow mod control over Covert Action deletion. (#435) - Triggers the event `BlackMarketGoodsReset` when the Black Market goods are reset (#473) -- Triggers the event `OverrideImageForItemAvaliable` to allow mods to override the image shown in eAlert_ItemAvailable (#491) - Triggers the event `OverrideCurrentDoom` to allow mods to override doom amount for doom updates (#550) - Triggers the event `PreEndOfMonth` to notify mods that the game is about to start its end-of-month processing (#539) - Triggers the event `ProcessNegativeIncome` to allow mods to do their own processing when XCOM's income at the @@ -132,7 +126,6 @@ RunPriorityGroup=RUN_STANDARD ### Modding Exposures - Allows mods to add custom items to the Avenger Shortcuts (#163) -- UIScanButton now calls OnMouseEventDelegate (#483). Note: DO NOT call ProcessMouseEvents, just set the delegate directly - Remove `private` from `X2AIBTBehaviorTree.Behaviors` so that mods can change the behavior trees without overwriting all the necessary entries (#410) - Removed `protectedwrite` from `AcquiredTraits`, `PendingTraits`, and `CuredTraits` in `XComGameState_Unit`, allowing Traits to be modified by external sources (#681) diff --git a/X2WOTCCommunityHighlander/Src/XComGame/Classes/UIAlert.uc b/X2WOTCCommunityHighlander/Src/XComGame/Classes/UIAlert.uc index 7bfeed70c..dc6bb6928 100644 --- a/X2WOTCCommunityHighlander/Src/XComGame/Classes/UIAlert.uc +++ b/X2WOTCCommunityHighlander/Src/XComGame/Classes/UIAlert.uc @@ -3415,6 +3415,18 @@ simulated function BuildItemAvailableAlert() } // Start issue #491 +/// HL-Docs: feature:OverrideImageForItemAvaliable; issue:491; tags:strategy,ui +/// Allows overriding the image shown for an item in the `eAlert_ItemAvailable` alert. +/// +/// This alert is triggered when a tech completes and makes available a new item for building, but, if it happens +/// to target a singular weapon (rather than the upgrade schematic), shows a weapon without +/// attachments (as specified in the Template's `strImage`). This event gives mods a chance to fix it. +/// +/// ```unrealscript +/// ID: OverrideImageForItemAvaliable, +/// Data: [inout string ImagePath, in X2ItemTemplate ItemTemplate], +/// Source: UIAlert +/// ``` simulated function string GetImageForItemAvaliable(X2ItemTemplate ItemTemplate) { local XComLWTuple Tuple; diff --git a/X2WOTCCommunityHighlander/Src/XComGame/Classes/UIAvengerShortcuts.uc b/X2WOTCCommunityHighlander/Src/XComGame/Classes/UIAvengerShortcuts.uc index a036afd65..f53055813 100644 --- a/X2WOTCCommunityHighlander/Src/XComGame/Classes/UIAvengerShortcuts.uc +++ b/X2WOTCCommunityHighlander/Src/XComGame/Classes/UIAvengerShortcuts.uc @@ -1126,7 +1126,16 @@ reliable client function array GetCommandersQuartersMe return Messages; } - // Start issue #368 +// Start issue #368 +/// HL-Docs: feature:UIAvengerShortcuts_ShowCQResistanceOrders; issue:368; tags:strategy,ui +/// Allows overriding whether the resistance orders button should be shown in `UIAvengerShortcuts`. +/// Default: After the first month if any faction met. +/// +/// ```unrealscript +/// ID: UIAvengerShortcuts_ShowCQResistanceOrders, +/// Data: [inout bool ShouldShow], +/// Source: UIAvengerShortcuts +/// ``` simulated protected function bool ShouldShowResistanceOrders() { local XComGameState_HeadquartersResistance ResHQ; diff --git a/X2WOTCCommunityHighlander/Src/XComGame/Classes/UIScanButton.uc b/X2WOTCCommunityHighlander/Src/XComGame/Classes/UIScanButton.uc index 22e87d41b..41b16d113 100644 --- a/X2WOTCCommunityHighlander/Src/XComGame/Classes/UIScanButton.uc +++ b/X2WOTCCommunityHighlander/Src/XComGame/Classes/UIScanButton.uc @@ -286,6 +286,10 @@ simulated function OnMouseEvent(int cmd, array args) } // Start issue #483. Note: DO NOT call ProcessMouseEvents, just set the delegate directly + /// HL-Docs: feature:UIScanButtonOnMouseEvent; issue:483; tags:strategy,ui + /// `UIScanButton` now triggers its `OnMouseEventDelegate` if set. Do not + /// call `ProcessMouseEvents`, do not pass go, do not collect $200, just set + /// the delegate directly. if (OnMouseEventDelegate != none) { OnMouseEventDelegate(self, cmd); diff --git a/X2WOTCCommunityHighlander/Src/XComGame/Classes/UIStrategyMap_HUD.uc b/X2WOTCCommunityHighlander/Src/XComGame/Classes/UIStrategyMap_HUD.uc index 9f3201e12..5569e1e18 100644 --- a/X2WOTCCommunityHighlander/Src/XComGame/Classes/UIStrategyMap_HUD.uc +++ b/X2WOTCCommunityHighlander/Src/XComGame/Classes/UIStrategyMap_HUD.uc @@ -282,6 +282,15 @@ simulated function UpdateData() } // Start issue #365 +/// HL-Docs: feature:Geoscape_ResInfoButtonVisible; issue:365; tags:strategy,ui +/// Allows overriding whether the resistance info button should be visible. +/// Default: After the first month if any faction met and not in flight. +/// +/// ```unrealscript +/// ID: Geoscape_ResInfoButtonVisible, +/// Data: [inout bool ShouldShow, in bool InFlight], +/// Source: UIStrategyMap_HUD +/// ``` simulated protected function bool ShouldShowResInfoButton(XComGameState_HeadquartersResistance ResHQ) { local XComLWTuple Tuple; diff --git a/X2WOTCCommunityHighlander/Src/XComGame/Classes/UIStrategyPolicy.uc b/X2WOTCCommunityHighlander/Src/XComGame/Classes/UIStrategyPolicy.uc index 3084fd915..3c47cd4d7 100644 --- a/X2WOTCCommunityHighlander/Src/XComGame/Classes/UIStrategyPolicy.uc +++ b/X2WOTCCommunityHighlander/Src/XComGame/Classes/UIStrategyPolicy.uc @@ -83,6 +83,15 @@ simulated function InitScreen(XComPlayerController InitController, UIMovie InitM UpdateNavHelp(); //bsg-crobinson (5.12.17): Update navhelp when screen is inited // Issue #440 + /// HL-Docs: feature:UIStrategyPolicy_ScreenInit; issue:440; tags:strategy,ui + /// Triggers the event `UIStrategyPolicy_ScreenInit` immediately after opening the + /// `UIStrategyPolicy` screen, before it has fully initialized. Can be used to make + /// modifications to camera transition behavior that would be too late in a ScreenListener. + /// + /// ```unrealscript + /// ID: UIStrategyPolicy_ScreenInit, + /// Source: UIStrategyPolicy + /// ``` `XEVENTMGR.TriggerEvent('UIStrategyPolicy_ScreenInit', , self); } @@ -1846,6 +1855,19 @@ simulated function CloseScreen() ResHQ = XComGameState_HeadquartersResistance(`XCOMHISTORY.GetSingleGameStateObjectForClass(class'XComGameState_HeadquartersResistance')); // Issue #440 Start + + /// HL-Docs: feature:UIStrategyPolicy_ShowCovertActionsOnClose; issue:365; tags:strategy,ui + /// Allows overriding whether to show the `UICovertActions` screen after closing + /// the `UIStrategyPolicy` screen. + /// + /// Default: Show if `UIStrategyPolicy` was created as part of the end-of-month report + /// and no covert actions are in progress. + /// + /// ```unrealscript + /// ID: UIStrategyPolicy_ShowCovertActionsOnClose, + /// Data: [inout bool ShouldShow], + /// Source: UIStrategyPolicy + /// ``` Tuple = new class'XComLWTuple'; Tuple.Id = 'UIStrategyPolicy_ShowCovertActionsOnClose'; Tuple.Data.Add(1); diff --git a/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComGameState_HeadquartersXCom.uc b/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComGameState_HeadquartersXCom.uc index 96e49ba4d..80374230c 100644 --- a/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComGameState_HeadquartersXCom.uc +++ b/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComGameState_HeadquartersXCom.uc @@ -7987,6 +7987,19 @@ function GetResistanceEvents(out array arrEvents) //--------------------------------------------------------------------------------------- // chl issue #518 start: added tuple & event 'ForceNoCovertActionNagFirstMonth' + +/// HL-Docs: feature:GetCovertActionEvents_Settings; issue:391; tags:strategy,ui +/// Allows configuring the behavior of covert actions in the event queue. +/// `AddAll` allows multiple covert actions, `InsertSorted` inserts them into position +/// based on time remaining. +/// +/// Default: Only one covert action is added at the end. +/// +/// ```unrealscript +/// ID: GetCovertActionEvents_Settings, +/// Data: [out bool AddAll, out bool InsertSorted], +/// Source: XCGS_HeadquartersXCom +/// ``` function GetCovertActionEvents(out array arrEvents) { local XComGameStateHistory History; From 82139cdb9adb605c3c89df1907e86176c95ae9f7 Mon Sep 17 00:00:00 2001 From: robojumper Date: Mon, 20 Apr 2020 16:34:12 +0200 Subject: [PATCH 02/10] Document SoundCueNarrativeMoments --- CHANGELOG.md | 2 -- .../Src/Engine/Classes/AudioComponent.uc | 26 +++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 40e9595f0..5190c57bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -389,8 +389,6 @@ RunPriorityGroup=RUN_STANDARD - Added Inventory Slots `eInvSlot_Wings` and `eInvSlot_ExtraBackpack`. (#678) ### Fixes -- Fixes game terminating SoundCue narrative moments after three seconds because - it assumes they didn't play at all. (#66) - Fixes UIPanels animating in with a huge delay when they are direct child panels of UIScreen (#341) - Appearances now update correctly when a part change differs only by material override (#354) diff --git a/X2WOTCCommunityHighlander/Src/Engine/Classes/AudioComponent.uc b/X2WOTCCommunityHighlander/Src/Engine/Classes/AudioComponent.uc index 379e1d614..b8cd59cf6 100644 --- a/X2WOTCCommunityHighlander/Src/Engine/Classes/AudioComponent.uc +++ b/X2WOTCCommunityHighlander/Src/Engine/Classes/AudioComponent.uc @@ -249,6 +249,32 @@ event OcclusionChanged(bool bNowOccluded) } /** called from native code when Wwise knows the duration of the currently playing event */ +/// HL-Docs: feature:SoundCueNarrativeMoments; issue:66; tags:strategy,tactical +/// Allows mods to add their own voiceover using narrative moments (top-right corner comms box). +/// +/// Narrative moments in the base game are realized using the WWise middleware. The middleware +/// runs in a background thread, so if audio (spuriously) fails to play, the middleware may take +/// a few frames to figure this out. If audio does fail to play, there must be a callback in order +/// to not deadlock the entire narrative moment system due to the audio never successfully finishing. +/// However, mods have to use `SoundCue` sounds instead, and the system considers every `SoundCue` +/// as failed to play. This ends every mod-added narrative moment prematurely after about three seconds. +/// +/// This fix simply triggers the callback only when WWise is involved and silently eats the callback +/// if a `SoundCue` is involved. +/// +/// ## Mini-tutorial on mod VO +/// +/// This isn't strictly Highlander-related, but this is the best place to put it. +/// +/// * Create a Speaker template (see `X2Character_DefaultCharacters.uc`) +/// * `Templates.AddItem(CreateSpeakerTemplate('Firebrand', "Firebrand", "img:///UILibrary_Common.Head_Firebrand", eGender_Female));` +/// * Compile the mod +/// * Import the `SoundNodeWave` +/// * Create a `SoundCue`, and create an `XComConversationNode` between the speaker and the `SoundNodeWave` +/// * Set the `SpokenText` and choose the `SpeakerTemplate` in the `SoundNodeWave` +/// * Create an `XComNarrativeMoment` archetype and reference the `SoundCue` in its `Conversations` +/// +/// ![Editor Screenshot](https://i.imgur.com/goUwFkJ.png) event AkCallbackSetDuration(float fSeconds) { // Start Issue #66 -- those events are explicitely Ak WWise-related From 7c77df640ee0c38f52085b685ab0ea374bbfbfa1 Mon Sep 17 00:00:00 2001 From: robojumper Date: Mon, 20 Apr 2020 15:53:25 +0200 Subject: [PATCH 03/10] Document BodyPartTemplateNames --- CHANGELOG.md | 5 -- .../Classes/X2BodyPartTemplateManager.uc | 53 +++++++++++++++++++ .../Classes/XComCharacterCustomization.uc | 1 + 3 files changed, 54 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 40e9595f0..2ced616dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -154,11 +154,6 @@ RunPriorityGroup=RUN_STANDARD - Class mods adding an eight rank will now interact better with classes with seven ranks (#1) - Allow `XComGameState_WorldRegion::DestinationReached` to use any XCGS_GeoscapeEntity class (#443) - Add AmbushMissionSource name property to XComGameState_CovertAction; mods can now specify the ambush mission on creation of Action GameState (#485) -- Customization localizations now picked up for Torso/Legs/Arms. If the TemplateName already - contains the parttype name (ie Torso/Legs/Arms), then the object name in the localization file - matches as for other parts (in particular this means Anarchy's Children localizations which already exist in the files - are picked up automatically). Otherwise, "_Torso"/"_Legs"/"_Arms" is appended to the template name - to create the unique object name. (#328) ### Fixes - Fix an issue in base game where strategy X2EventListenerTemplates only diff --git a/X2WOTCCommunityHighlander/Src/XComGame/Classes/X2BodyPartTemplateManager.uc b/X2WOTCCommunityHighlander/Src/XComGame/Classes/X2BodyPartTemplateManager.uc index 4f67203ed..c65f6df62 100644 --- a/X2WOTCCommunityHighlander/Src/XComGame/Classes/X2BodyPartTemplateManager.uc +++ b/X2WOTCCommunityHighlander/Src/XComGame/Classes/X2BodyPartTemplateManager.uc @@ -62,6 +62,59 @@ protected event InitTemplatesInternal() case "Arms": case "Legs": // Begin issue #328 - Check if the TemplateName indentifies the Part Type. + /// HL-Docs: feature:BodyPartTemplateNames; issue:328; tags:customization + /// Allows Torso, Arms and Legs customization pieces to be uniquely localized. + /// + /// For templates, localization (i.e. providing strings for in-game display like names + /// or descriptions) is handled using the object name that is the same as the template name. + /// For example, given a template name of `'Female_LongStraight'`, the template is created + /// by giving the `X2BodyPartTemplate` that name: + /// + /// ```unrealscript + /// // Object name -------vvvvvvvvvvvvvvvvvvv + /// Template = new(None, "Female_LongStraight") class'X2BodyPartTemplate'; + /// Template.SetTemplateName('Female_LongStraight'); + /// // Template name ---------^^^^^^^^^^^^^^^^^^^ + /// ``` + /// + /// On the localization side, the object name is used to localize the `DisplayName`: + /// + /// ```ini + /// ;vvvvvvvvvvvvvvvvvvv--- Object name + /// [Female_LongStraight X2BodyPartTemplate] + /// DisplayName="Long Straight" + /// ``` + /// + /// Body part templates are different from normal templates in that templates for different + /// customization categories are allowed to have the same name. In vanilla, there are collisions + /// for `Torso`, `Arms` and `Legs` so there is a Conventional Medium Male Torso, an Arms piece, + /// and a Legs piece with the name `CnvMed_Std_A_M`. + /// However, in order for localization to work, there must be no object name collisions. + /// As a result, the game opts to not assign any object name to Torsos, Arms, and Legs, and instead + /// simply shows them as "Torso 1", "Torso 2" and so on. + /// + /// Because mods may want to localize their pieces, this Highlander change gives all armor pieces a unique object name. + /// This happens using the following algorithm for every `BodyPartTemplateConfig` entry: + /// + /// 1. If the `PartType` is not `"Torso"`, `"Arms"`, `"Legs"`, the object name and the template name are + /// taken from `TemplateName` in the config entry (vanilla behavior). + /// 2. If the `PartType` is `"Torso"`, `"Arms"`, or `"Legs"`: + /// 1. If `TemplateName` contains that part type, then the object name and the template name are + /// taken from `TemplateName` in the config entry. + /// 2. If `TemplateName` does not contain that part type, then the template name is taken from + /// `TemplateName`, and the object name is created by appending an underscore and the part type + /// to the template name. + /// + /// Additionally, the UI is changed to use the `DisplayName` for Torso/Arms/Legs, and fall back to numbered vanilla display + /// if no `DisplayName` is provided. + /// + /// A table with some examples: + /// + /// | Config `PartType` | Config `TemplateName` | Resulting Template Name | Resulting Object Name | + /// | ------------------ | --------------------- | ----------------------- | ------------------------ | + /// | `"Torso"` | `"CnvMed_Std_A_M"` | `'CnvMed_Std_A_M'` | `"CnvMed_Std_A_M_Torso"` | + /// | `"Helmets"` | `"Reaper_Hood_A_M"` | `'Reaper_Hood_A_M'` | `"Reaper_Hood_A_M"` | + /// | `"Torso"` | `"DLC_30_Torso_M"` | `'DLC_30_Torso_M'` | `"DLC_30_Torso_M"` | if(InStr(PartInfo.TemplateName, PartInfo.PartType,, true)==INDEX_NONE) { // Instead of giving up, decorate TemplateName to get unique Object Name diff --git a/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComCharacterCustomization.uc b/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComCharacterCustomization.uc index 3d3ca5beb..6a1c5f438 100644 --- a/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComCharacterCustomization.uc +++ b/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComCharacterCustomization.uc @@ -1105,6 +1105,7 @@ function string GetCategoryDisplayName( string BodyPart, name PartToMatch, deleg if( PartToMatch == BodyParts[PartIndex].DataName ) { //Begin Issue #328 + /// HL-Docs: ref:BodyPartTemplateNames DisplayName = BodyParts[PartIndex].DisplayName; if (DisplayName == "") { From 4336da4e7a7b353508c4f0229aa39bd139ccb3df Mon Sep 17 00:00:00 2001 From: robojumper Date: Sun, 24 May 2020 20:06:08 +0200 Subject: [PATCH 04/10] We have `Core.upk` now --- CookCommunityHighlander.bat | 12 ++++++++++++ README.md | 8 +++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/CookCommunityHighlander.bat b/CookCommunityHighlander.bat index 7980c993b..1a7760506 100644 --- a/CookCommunityHighlander.bat +++ b/CookCommunityHighlander.bat @@ -90,12 +90,24 @@ echo Copying Engine.upk to SDK Highlander mod folder... copy /Y "%SDKLocation%\XComGame\Published\CookedPCConsole\Engine.upk" "%SDKLocation%\XComGame\Mods\X2WOTCCommunityHighlander\CookedPCConsole\Engine.upk" copy /Y "%SDKLocation%\XComGame\Published\CookedPCConsole\Engine.upk.uncompressed_size" "%SDKLocation%\XComGame\Mods\X2WOTCCommunityHighlander\CookedPCConsole\Engine.upk.uncompressed_size" +echo. +echo Copying Core.upk to local Highlander mod folder... +copy /Y "%SDKLocation%\XComGame\Published\CookedPCConsole\Core.upk" "%GameLocation%\XComGame\Mods\X2WOTCCommunityHighlander\CookedPCConsole\Core.upk" +copy /Y "%SDKLocation%\XComGame\Published\CookedPCConsole\Core.upk.uncompressed_size" "%GameLocation%\XComGame\Mods\X2WOTCCommunityHighlander\CookedPCConsole\Core.upk.uncompressed_size" + +echo. +echo Copying Core.upk to SDK Highlander mod folder... +copy /Y "%SDKLocation%\XComGame\Published\CookedPCConsole\Core.upk" "%SDKLocation%\XComGame\Mods\X2WOTCCommunityHighlander\CookedPCConsole\Core.upk" +copy /Y "%SDKLocation%\XComGame\Published\CookedPCConsole\Core.upk.uncompressed_size" "%SDKLocation%\XComGame\Mods\X2WOTCCommunityHighlander\CookedPCConsole\Core.upk.uncompressed_size" + echo. echo Cleaning up... if exist "%GameLocation%\XComGame\Mods\X2WOTCCommunityHighlander\Script\XComGame.u" del "%GameLocation%\XComGame\Mods\X2WOTCCommunityHighlander\Script\XComGame.u" if exist "%SDKLocation%\XComGame\Mods\X2WOTCCommunityHighlander\Script\XComGame.u" del "%SDKLocation%\XComGame\Mods\X2WOTCCommunityHighlander\Script\XComGame.u" if exist "%GameLocation%\XComGame\Mods\X2WOTCCommunityHighlander\Script\Engine.u" del "%GameLocation%\XComGame\Mods\X2WOTCCommunityHighlander\Script\Engine.u" if exist "%SDKLocation%\XComGame\Mods\X2WOTCCommunityHighlander\Script\Engine.u" del "%SDKLocation%\XComGame\Mods\X2WOTCCommunityHighlander\Script\Engine.u" +if exist "%GameLocation%\XComGame\Mods\X2WOTCCommunityHighlander\Script\Core.u" del "%GameLocation%\XComGame\Mods\X2WOTCCommunityHighlander\Script\Core.u" +if exist "%SDKLocation%\XComGame\Mods\X2WOTCCommunityHighlander\Script\Core.u" del "%SDKLocation%\XComGame\Mods\X2WOTCCommunityHighlander\Script\Core.u" echo. echo. diff --git a/README.md b/README.md index ab6ab6c5c..7dcfa9e0b 100644 --- a/README.md +++ b/README.md @@ -153,18 +153,20 @@ Start by building the mod through ModBuddy, as you normally would. Then, enter t If a message like "Scripts are outdated. Would you like to rebuild now?" pops up, click "No". -The commands above create cooked files for your `XComGame` and `Engine` package replacements in +The commands above create cooked files for your `XComGame`, `Engine`, and `Core` package replacements in `%STEAMLIBRARY%\steamapps\common\XCOM 2 War of the Chosen SDK\XComGame\Published\CookedPCConsole`: ``` XComGame.upk XComGame.upk.uncompressed_size Engine.upk Engine.upk.uncompressed_size +Core.upk +Core.upk.uncompressed_size ``` Copy those files into a folder called `CookedPCConsole` inside the mod's output -folder. You will need to delete `Script\XComGame.u` and `Script\Engine.u`, now that we've put the -cooked script file in it's place. +folder. You will need to delete `Script\XComGame.u`, `Script\Engine.u` and `Script\Core.u`, +now that we've put the cooked script file in it's place. Once you've done all that, the mod should now run in vanilla XCOM. Note that all logging statements will be stripped from the Cooked version, so don't expect to From 4e3577be742db4bf2708a730c75d9aba9e550d51 Mon Sep 17 00:00:00 2001 From: robojumper Date: Tue, 9 Jun 2020 15:35:44 +0200 Subject: [PATCH 05/10] Use GITHUB_TOKEN for docs deployment --- .github/workflows/docs.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 324803a86..50b565780 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -34,10 +34,9 @@ jobs: name: docs-html path: target - name: Deploy - uses: crazy-max/ghaction-github-pages@v1 + uses: crazy-max/ghaction-github-pages@v2 with: target_branch: gh-pages build_dir: target # The folder the action should deploy. - committer_name: X2CommunityCore-Docs-Bot env: - GITHUB_PAT: ${{ secrets.ACCESS_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From ab9d7363d6764b235f4a7b4314971a0227a28a0f Mon Sep 17 00:00:00 2001 From: robojumper Date: Fri, 17 Jul 2020 01:45:06 +0200 Subject: [PATCH 06/10] docs: optimize, report duplicate feature definitions --- .scripts/make_docs.py | 63 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 9 deletions(-) diff --git a/.scripts/make_docs.py b/.scripts/make_docs.py index 247f46dd7..b4bfc9fc9 100644 --- a/.scripts/make_docs.py +++ b/.scripts/make_docs.py @@ -4,7 +4,7 @@ import shutil from enum import Enum -from typing import List, Optional +from typing import List, Optional, Iterable HL_DOCS_KEYWORD = "HL-Docs:" HL_INCLUDE_FOLLOWING = "HL-Include:" @@ -195,8 +195,6 @@ def parse_file(self, file, filename): doc_items = [] - generate_builtin_features(doc_items) - parser = Parser(doc_items) with open(file, errors='replace') as infile: parser.parse_file(infile, file) @@ -204,9 +202,50 @@ def parse_file(self, file, filename): return doc_items -def merge_doc_refs(doc_items: List[dict]) -> List[dict]: - items = dict((i["feature"], i) for i in doc_items if not "ref" in i) - refs = [i for i in doc_items if "ref" in i] +def partition_items(doc_items: List[dict]) -> int: + """ + Partition the array and check for duplicates, returning the start index + of the refs (where features end) + """ + def cmp_doc_item(doc_item: dict) -> (bool, str): + is_feat = "feature" in doc_item + return (not is_feat, + doc_item["feature"] if is_feat else doc_item["ref"]) + + doc_items.sort(key=lambda i: cmp_doc_item(i)) + + first_def = None + seen = False + for idx, it in enumerate(doc_items): + if not "feature" in it: + break + + def make_loc(it: dict) -> str: + if "texts" in it and len(it["texts"]) > 0: + return "at %s:%s" % (it["texts"][0]["file"], + it["texts"][0]["span"][0] + 1) + else: + return "due to builtin feature" + + if first_def != None and it["feature"] == first_def["feature"]: + # Report duplicate feature definition + if not seen: + err("duplicate feature definition `%s`" % (it["feature"]), + False) + print("note: first definition %s" % (make_loc(first_def))) + seen = True + print("note: this definition %s" % (make_loc(it))) + + else: + first_def = it + seen = False + + return idx + + +def merge_doc_refs(doc_items: List[dict], refs_start: int) -> Iterable[dict]: + items = dict((i["feature"], i) for i in doc_items[:refs_start]) + refs = doc_items[refs_start:] for ref in refs: if ref["ref"] in items: @@ -254,7 +293,9 @@ def render_bugfix_page(item: dict, outdir: str): def render_full_feature_page(item: dict, outdir: str): if not "tags" in item: - err("Feature '%s' does not have a 'tags' key/annotation" % (item["feature"]), False) + err( + "Feature '%s' does not have a 'tags' key/annotation" % + (item["feature"]), False) return if "strategy" in item["tags"] and not "tactical" in item["tags"]: @@ -322,7 +363,7 @@ def render_tag_page(tag: str, items: List[dict], outdir: str): file.write("\n") -def render_docs(doc_items: List[dict], outdir: str): +def render_docs(doc_items: Iterable[dict], outdir: str): ensure_dir(outdir) outdir = os.path.join(outdir, "docs") @@ -366,7 +407,10 @@ def main(): global exit_code indirs, outdir, docsdir = parse_args() copytree(docsdir, outdir) + doc_items = [] + generate_builtin_features(doc_items) + for docdir in indirs: for root, subdirs, files in os.walk(docdir): for file in files: @@ -376,7 +420,8 @@ def main(): if ext in known_exts: doc_items.extend(process_file(infile, known_exts[ext])) - doc_items = merge_doc_refs(doc_items) + refs_start = partition_items(doc_items) + doc_items = merge_doc_refs(doc_items, refs_start) if outdir != None: render_docs(doc_items, outdir) From 36e21d16d1a04aa232706a6e6cb36352b3272cbc Mon Sep 17 00:00:00 2001 From: robojumper Date: Wed, 4 Mar 2020 12:54:25 +0100 Subject: [PATCH 07/10] Document GetStatModifiersFixed --- CHANGELOG.md | 2 -- .../Classes/X2AbilityToHitCalc_StandardAim.uc | 2 ++ .../XComGame/Classes/XComGameState_Unit.uc | 34 +++++++++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 40e9595f0..970a7b2ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -271,8 +271,6 @@ RunPriorityGroup=RUN_STANDARD - Allow aliens and other teams to properly register non-XCOM unit locations to adjust their positions accordingly (#619) ### Fixes -- Fixed XCGS_Unit::GetStatModifiers() as XCGS_Unit::GetStatModifiersFixed(), - X2AbilityToHitCalc_StandardAim, the only vanilla user of this method, changed to match(#313) - Allow abilities that deal damage without a source weapon to still display their damage with psi flyovers (Psi Bomb, mod abilities) (#326) - Make disorient reapply to disoriented units so that things like flashbangs can diff --git a/X2WOTCCommunityHighlander/Src/XComGame/Classes/X2AbilityToHitCalc_StandardAim.uc b/X2WOTCCommunityHighlander/Src/XComGame/Classes/X2AbilityToHitCalc_StandardAim.uc index b9586b0bc..c8bb1ed78 100644 --- a/X2WOTCCommunityHighlander/Src/XComGame/Classes/X2AbilityToHitCalc_StandardAim.uc +++ b/X2WOTCCommunityHighlander/Src/XComGame/Classes/X2AbilityToHitCalc_StandardAim.uc @@ -374,6 +374,7 @@ protected function int GetHitChance(XComGameState_Ability kAbility, AvailableTar // Add basic offense and defense values AddModifier(UnitState.GetBaseStat(eStat_Offense), class'XLocalizedData'.default.OffenseStat, m_ShotBreakdown, eHit_Success, bDebugLog); // Single Line Change for Issue #313 + /// HL-Docs: ref:GetStatModifiersFixed UnitState.GetStatModifiersFixed(eStat_Offense, StatMods, StatModValues); for (i = 0; i < StatMods.Length; ++i) { @@ -534,6 +535,7 @@ protected function int GetHitChance(XComGameState_Ability kAbility, AvailableTar { AddModifier(UnitState.GetBaseStat(eStat_CritChance), class'XLocalizedData'.default.CharCritChance, m_ShotBreakdown, eHit_Crit, bDebugLog); // Single Line Change for Issue #313 + /// HL-Docs: ref:GetStatModifiersFixed UnitState.GetStatModifiersFixed(eStat_CritChance, StatMods, StatModValues); for (i = 0; i < StatMods.Length; ++i) { diff --git a/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComGameState_Unit.uc b/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComGameState_Unit.uc index a6e32f160..cfcca7925 100644 --- a/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComGameState_Unit.uc +++ b/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComGameState_Unit.uc @@ -6884,6 +6884,40 @@ native function SetCurrentStat( ECharStatType Stat, float NewValue ); native function GetStatModifiers(ECharStatType Stat, out array Mods, out array ModValues, optional XComGameStateHistory GameStateHistoryObject); // Begin Issue #313 +/// HL-Docs: feature:GetStatModifiersFixed; issue:313; tags:tactical,compatibility +/// The base game provides a function +/// +/// ```unrealscript +/// native function GetStatModifiers(ECharStatType Stat, out array Mods, out array ModValues, optional XComGameStateHistory GameStateHistoryObject); +/// ``` +/// that can be used to identify how much different effects contribute to the calculated stat total. +/// For example, `X2AbilityToHitCalc_StandardAim` wants to show how many percentage points to-hit or to-crit +/// different effects provide or diminish. +/// +/// However, the function is subtly broken in the presence of +/// multiplicative modifiers (`MODOP_Multiplication` or `MODOP_PostMultiplication`), where it doesn't +/// return the correct contribution but instead simply returns `MultiplicationMod * BaseStat`. This +/// makes multiplicative modifiers unusable for `eStat_Offense` and `eStat_CritChance`. +/// +/// The Highlander function `GetStatModifiersFixed` wraps the broken function and fixes the numbers. +/// Additionally, `X2AbilityToHitCalc_StandardAim` is changed to call this modified function. +/// +/// ## Compatibility +/// +/// Mods that override/replace `X2AbilityToHitCalc_StandardAim:GetHitChance` may undo the Highlander's +/// changes and use the broken function. In particular, XModBase is [known to undo this fix](https://github.com/RossM/XModBase/issues/1). +/// It is recommended that affected mods check whether `GetStatModifiersFixed` exists and call it instead: +/// +/// ```unrealscript +/// if (Function'XComGame.XComGameState_Unit.GetStatModifiersFixed' != none) +/// { +/// // call GetStatModifiersFixed +/// } +/// else +/// { +/// // call GetStatModifiers +/// } +/// ``` function GetStatModifiersFixed(ECharStatType Stat, out array Mods, out array ModValues, optional XComGameStateHistory GameStateHistoryObject, optional bool RoundTotals=true) { local array MultMods; From fa0ce981a673dd7b6d5829031a06298ab0e16302 Mon Sep 17 00:00:00 2001 From: robojumper Date: Wed, 4 Mar 2020 13:40:05 +0100 Subject: [PATCH 08/10] Document ScreenStackSubClasses --- CHANGELOG.md | 4 -- .../Src/XComGame/Classes/UIScreenStack.uc | 53 ++++++++++++++----- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 970a7b2ef..c85aef19a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -379,10 +379,6 @@ RunPriorityGroup=RUN_STANDARD flag on `XComGameState_Unit`. This behavior is gated behind the new `CHHelpers.PreserveProxyUnitData` config variable. (#465) - Adds CustomDeathAnimationName property to X2Action_Death that allows overriding the default death animations (#488) -- Change `GetScreen()` and `IsCurrentClass()` on `UIScreenStack` to take into account subclasses - by default. This is a breaking change but fixes a lot of problems with vanilla and mod code that - mistakenly ignores subclasses of screens, particularly those provided by mod. The original behavior - can still be accessed via new `GetScreen_CH()` and `IsCurrentClass_CH()`. (#290) - Allow PCS granting PsiOffense to be equiped by other classes than PsiOperative (#602) - Added Inventory Slots `eInvSlot_Wings` and `eInvSlot_ExtraBackpack`. (#678) diff --git a/X2WOTCCommunityHighlander/Src/XComGame/Classes/UIScreenStack.uc b/X2WOTCCommunityHighlander/Src/XComGame/Classes/UIScreenStack.uc index 90a03f2cc..4bd27202a 100644 --- a/X2WOTCCommunityHighlander/Src/XComGame/Classes/UIScreenStack.uc +++ b/X2WOTCCommunityHighlander/Src/XComGame/Classes/UIScreenStack.uc @@ -635,12 +635,44 @@ simulated function PopIncludingClass( class ClassToRemove, optional bo // Start Issue #290 // // Lots of code in the base game and mods seems to use `GetScreen()` when -// it should be using `GetFirstInstanceOf()`. This change means that -// `GetScreen()` will also return any screen that's a subclass of the -// specified one. -// -// If any code wants to ignore subclasses, then it can use the new -// `GetScreen_CH()` method instead. +// it should be using `GetFirstInstanceOf()`. + +/// HL-Docs: feature:ScreenStackSubClasses; issue:290; tags:compatibility +/// A number of functions in `UIScreenStack` operate on classes, but fail +/// to consider subclasses. This causes subtle bugs in base game and mod +/// code that fails to consider the possibility that a given class can +/// be subclassed/overridden. For example, `UIArmory` does something like this: +/// +/// ```unrealscript +/// // Don't allow jumping to the geoscape from the armory when coming from squad select +/// if (!`ScreenStack.IsInStack(class'UISquadSelect')) +/// { +/// NavHelp.AddGeoscapeButton(); +/// } +/// ``` +/// +/// However, if `UISquadSelect` is being overridden or replaced, *this can cause the +/// campaign to permanently deadlock* because `UIArmory` fails to find the changed +/// squad select screen. The proper fix would be using `HasInstanceOf`, but this error +/// is extremely common in base game and mod code. As a result, it was decided that +/// the best fix is to change all functions in `UIScreenStack` to always consider +/// subclasses. A full list of affected functions: +/// +/// * `GetScreen` +/// * `IsCurrentClass` +/// * `IsInStack` +/// * `IsNotInStack` +/// +/// ## Compatibility +/// +/// If you legitimately want to *not* consider subclasses, you can use the functions +/// +/// ``` unrealscript +/// function UIScreen GetScreen_CH(class ScreenClass, bool IncludeSubTypes); +/// function bool IsCurrentClass_CH(class ScreenClass, bool IncludeSubTypes); +/// ``` +/// +/// and rewrite `IsInStack`/`IsNotInStack` in terms of `GetScreen_CH(...) !=/== none`. // Returns the first instance of a Screen of the target class type (or a subclass). simulated function UIScreen GetScreen( class ScreenClass ) @@ -721,14 +753,7 @@ simulated function bool HasInstanceOf( class ScreenClass ) // Start Issue #290 // // A lot of code seems to assume that certain screen classes will never have -// subclasses, which is rubbish in the context of mods. So this method will -// now return `true` if the current screen is also a subclass of the given -// class. However, the reverse will not work, i.e. if the given screen class -// is a subclass of the current screen class, then this method will return -// `false`. -// -// If you want to exclude subclasses, then use the new `IsCurrentClass_CH()` -// method. +// subclasses, which is rubbish in the context of mods. simulated function bool IsCurrentClass( class ScreenClass ) { return IsCurrentClass_CH(ScreenClass, true); From 94843598dd0fad0838a345396ff9b156eceaa91b Mon Sep 17 00:00:00 2001 From: robojumper Date: Mon, 20 Jul 2020 17:40:54 +0200 Subject: [PATCH 09/10] XModBase 2.0.2 no longer breaks GetStatModifiersFixed --- .../Src/XComGame/Classes/XComGameState_Unit.uc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComGameState_Unit.uc b/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComGameState_Unit.uc index cfcca7925..8b0587578 100644 --- a/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComGameState_Unit.uc +++ b/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComGameState_Unit.uc @@ -6905,8 +6905,10 @@ native function GetStatModifiers(ECharStatType Stat, out array Date: Thu, 5 Mar 2020 21:24:49 +0100 Subject: [PATCH 10/10] UI Docs: OverridePromotionUIClasses, OverrideMissionImage, UIResistanceReport_ShowCouncil, DynamicSoldierClassDisplay, DynamicSoldierRankDisplay --- CHANGELOG.md | 13 ----- .../XComGame/Classes/UIResistanceReport.uc | 10 ++++ .../Src/XComGame/Classes/UIUtilities_Image.uc | 10 ++++ .../Classes/XComGameState_MissionSite.uc | 8 +++ .../XComGame/Classes/XComGameState_Unit.uc | 51 +++++++++++++++++++ .../Classes/XComHQPresentationLayer.uc | 47 ++++++++++++----- 6 files changed, 114 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c323463d0..7f72e10f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -104,17 +104,12 @@ RunPriorityGroup=RUN_STANDARD - Triggers the event `CovertActionAllowCheckForProjectOverlap` to allow mods to forbid the "de-bunching" logic on CA start (#584) - Triggers the event `AllowActionToSpawnRandomly` to allow mods to prevent certain CAs from being randomly spawned (#594) -- Triggers the event `OverridePromotionUIClasses` to allow mods to override the UI classes used for the - three different promotion screens (#600) - Triggers the event `OverrideRespecSoldierProjectPoints` to allow mods to customize how long it should take to respec a given soldier (#624) - Triggers the event `OverrideScienceScore` to allow mods to override the XCOM HQ science score, for example to add their own bonuses or to remove scientists that are engaged in other activities. - Triggers the event `CanTechBeInspired` to allow mods to block techs from being inspired, even if they meet the vanilla game's conditions for it (#633) -- Triggers the event `OverrideMissionImage` to allow mods to customize mission's image (used in UIMission and subclasses) (#635) -- Triggers the event `UIResistanceReport_ShowCouncil` to allow mods to override whether the council guy (and his remarks) - is shown on the end-of-month report or not (#663) - Triggers the event `OverrideNextRetaliationDisplay` to allow mods to customize and/or enable/disable "next retaliation" display in `UIAdventOperations` (#667) - Triggers the event `ItemAddedToSlot` & `ItemRemovedFromSlot` to allow mods to change Items that have been Equipped/Unequipped during runtime(#694) @@ -300,18 +295,10 @@ RunPriorityGroup=RUN_STANDARD - `AbilityTagExpandHandler_CH` expands vanilla AbilityTagExpandHandler to allow reflection ### Event Hooks -- Triggers the events `SoldierClassIcon`, `SoldierClassDisplayName`, - `SoldierClassSummary` that allow replacement of the class icon/display - name/summary dynamically e.g. depending on UnitState or Soldier Loadout, - and adds accessor functions for those to XComGameState_Unit. (#106) -- `GetPCSImageTuple` added to allow customising PCS Image string (#110) - Triggers the event `OverrideHasHeavyWeapon` that allows to override the result of `XComGameState_Unit.HasHeavyWeapon` (#172) - `OverrideItemMinEquipped` added to allow mods to override the min number of equipped items in a slot (#171) - `AddConversation` added to allow mods to change narrative behavior before they are played (#204) - `OverrideRandomizeAppearance` added to allow mods to block updating appearance when switching armors (#299) -- `XComGameState_Unit` triggers `SoldierRankName`, `SoldierShortRankName` and - `SoldierRankIcon` events that allow listeners to override the those particular - properties of a soldier's rank, i.e. rank name, short name and icon (#408) ### Configuration - Able to list classes as excluded from AWC Skill Rolling, so they can still diff --git a/X2WOTCCommunityHighlander/Src/XComGame/Classes/UIResistanceReport.uc b/X2WOTCCommunityHighlander/Src/XComGame/Classes/UIResistanceReport.uc index c9e7336e1..196b6d181 100644 --- a/X2WOTCCommunityHighlander/Src/XComGame/Classes/UIResistanceReport.uc +++ b/X2WOTCCommunityHighlander/Src/XComGame/Classes/UIResistanceReport.uc @@ -54,6 +54,16 @@ simulated function InitScreen(XComPlayerController InitController, UIMovie InitM } // Start issue #663 +/// HL-Docs: feature:UIResistanceReport_ShowCouncil; issue:663; tags:strategy,ui +/// Allows overriding whether to show the council guy and his remarks in the background +/// at the end of month. +/// +/// +/// ```unrealscript +/// ID: UIResistanceReport_ShowCouncil, +/// Data: [inout bool ShouldShow], +/// Source: UIResistanceReport +/// ``` protected simulated function bool TriggerShouldShowCouncil () { local XComLWTuple Tuple; diff --git a/X2WOTCCommunityHighlander/Src/XComGame/Classes/UIUtilities_Image.uc b/X2WOTCCommunityHighlander/Src/XComGame/Classes/UIUtilities_Image.uc index c09a07362..51ee6eae2 100644 --- a/X2WOTCCommunityHighlander/Src/XComGame/Classes/UIUtilities_Image.uc +++ b/X2WOTCCommunityHighlander/Src/XComGame/Classes/UIUtilities_Image.uc @@ -838,6 +838,16 @@ simulated static function string GetPCSImage(XComGameState_Item Item) StatType = class'UIUtilities_Strategy'.static.GetStatBoost(Item).StatType; // Start Issue #110: OnGetPCSImage Event + /// HL-Docs: feature:OnGetPCSImage; issue:110; tags:strategy,ui + /// Allows overriding the UI image for a PCS. The base game switches on the + /// stat being boosted, which precludes custom PCS from having a custom icon. + /// Note that for historical reasons, the tuple ID is `GetPCSImageTuple` while + /// the event ID is `OnGetPCSImage`. + /// + /// ```unrealscript + /// ID: OnGetPCSImage, + /// Data: [in XComGameState_Item ItemState, out string ImagePath], + /// ``` Tuple = new class'XComLWTuple'; Tuple.id = 'GetPCSImageTuple'; Tuple.Data.Add(2); diff --git a/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComGameState_MissionSite.uc b/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComGameState_MissionSite.uc index 2375cd81b..8d1e0b34e 100644 --- a/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComGameState_MissionSite.uc +++ b/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComGameState_MissionSite.uc @@ -1928,6 +1928,14 @@ simulated function TriggerOverrideMissionSiteIconImage(out string ImagePath) // End Issue #537 // Start issue #635 +/// HL-Docs: feature:OverrideMissionImage; issue:635; tags:strategy,ui +/// Allows overriding the image shown for a mission in the `UIMission` screen. +/// +/// ```unrealscript +/// ID: OverrideMissionImage, +/// Data: [inout string ImagePath], +/// Source: XCGS_MissionSite +/// ``` function string GetMissionImage () { local XComLWTuple Tuple; diff --git a/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComGameState_Unit.uc b/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComGameState_Unit.uc index 1ef529da0..3e840d5e6 100644 --- a/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComGameState_Unit.uc +++ b/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComGameState_Unit.uc @@ -14744,6 +14744,31 @@ function bool UnitIsValidForPhotobooth() } // Start Issue #106 +/// HL-Docs: feature:DynamicSoldierClassDisplay; issue:106; tags:strategy,ui +/// Mods may want to manipulate the way a soldier's class is displayed (in terms +/// of icon/name/description) in more dynamic ways. For example, *RPGOverhaul* +/// has a single soldier class and the way it is displayed depends on selected +/// skills and loadouts. There are three events with mostly self-explanatory names: +/// ```unrealscript +/// ID: SoldierClassIcon, +/// Data: [inout string IconImagePath], +/// Source: XCGS_Unit +/// ``` +/// +/// ```unrealscript +/// ID: SoldierClassDisplayName, +/// Data: [inout string DisplayName], +/// Source: XCGS_Unit +/// ``` +/// +/// ```unrealscript +/// ID: SoldierClassSummary, +/// Data: [inout string DisplaySummary], +/// Source: XCGS_Unit +/// ``` +/// +/// There is a sister feature [`DynamicSoldierRankDisplay`](./DynamicSoldierRankDisplay.md) +/// that extends this to rank icon/name. function String GetSoldierClassIcon() { local XComLWTuple Tuple; @@ -14808,6 +14833,32 @@ function String GetSoldierClassSummary() // unit's current rank. If this is -1, then the current rank is // returned as usual. // +/// HL-Docs: feature:DynamicSoldierRankDisplay; issue:408; tags:strategy,ui +/// Mods may want to manipulate the way a soldier's rank is displayed (in terms +/// of icon/name/description) in more dynamic ways. For example, *LWOTC* +/// shows officer ranks for units with special officer abilities. +/// There are three events with mostly self-explanatory names: +/// +/// ```unrealscript +/// ID: SoldierRankName, +/// Data: [in int Rank, inout string DisplayRankName], +/// Source: XCGS_Unit +/// ``` +/// +/// ```unrealscript +/// ID: SoldierShortRankName, +/// Data: [in int Rank, inout string DisplayShortRankName], +/// Source: XCGS_Unit +/// ``` +/// +/// ```unrealscript +/// ID: SoldierRankIcon, +/// Data: [in int Rank, inout string IconImagePath], +/// Source: XCGS_Unit +/// ``` +/// +/// There is a sister feature [`DynamicSoldierClassDisplay`](./DynamicSoldierClassDisplay.md) +/// that extends this to class icon/name. function string GetSoldierRankName(optional int Rank = -1) { local XComLWTuple OverrideTuple; diff --git a/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComHQPresentationLayer.uc b/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComHQPresentationLayer.uc index 2495fe121..fa714b118 100644 --- a/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComHQPresentationLayer.uc +++ b/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComHQPresentationLayer.uc @@ -1,12 +1,15 @@ class XComHQPresentationLayer extends XComPresentationLayerBase; // Start Issue #600 +/// HL-Docs: ref:OverridePromotionUIClass +/// HL-Include: enum CHLPromotionScreenType { eCHLPST_Standard, eCHLPST_Hero, eCHLPST_PsiOp }; +/// // End Issue #600 var XGHQCamera m_kCamera; @@ -1511,18 +1514,38 @@ function ShowPromotionUI(StateObjectReference UnitRef, optional bool bInstantTra // Start Issue #600 // -// Fires an 'OverridePromotionUIClass' event that allows mods to override -// the UI class used for a given promotion screen. Note that any class -// provided by a mod must be UIArmory_Promotion or a subclass of it. -// -// The event itself takes the form: -// -// { -// ID: OverridePromotionUIClass, -// Data: [in int PromotionScreenType, inout class PromotionUIClass], -// Source: self (XComHQPresentationLayer) -// } -// +/// HL-Docs: feature:OverridePromotionUIClass; issue:600; tags:strategy,ui +/// Fires an event that allows mods to override +/// the UI class used for a given promotion screen. Note that any class +/// provided by a mod must be UIArmory_Promotion or a subclass of it. +/// +/// ```unrealscript +/// ID: OverridePromotionUIClass, +/// Data: [in int PromotionScreenType, inout class PromotionUIClass], +/// Source: XComHQPresentationLayer +/// ``` +/// +/// The following simplified example is taken from [Community Promotion Screen](https://github.com/X2CommunityCore/X2CommunityPromotionScreen): +/// +/// ```unrealscript +/// local XComLWTuple Tuple; +/// local CHLPromotionScreenType ScreenType; +/// +/// Tuple = XComLWTuple(EventData); +/// +/// ScreenType = CHLPromotionScreenType(Tuple.Data[0].i); +/// +/// if ((ScreenType == eCHLPST_PsiOp && ShouldOverridePsiPromotionScreen()) || +/// (ScreenType == eCHLPST_Hero && ShouldOverrideHeroPromotionScreen()) || +/// (ScreenType == eCHLPST_Standard && ShouldOverrideStandardPromotionScreen())) +/// { +/// Tuple.Data[1].o = class'NPSBDP_UIArmory_PromotionHero'; +/// } +/// +/// return ELR_NoInterrupt; +/// ``` +/// +/// The integer values of `PromotionScreenType` correspond to the `CHLPromotionScreenType` enum. function class TriggerOverridePromotionUIClass(CHLPromotionScreenType ScreenType) { local XComLWTuple Tuple;