Interface UPK mods Enhanced Perk Tree - XCOM:EU 2012
Contents
- 1 Overview
- 2 Programs and Tools
- 3 Details
- 4 File Changes
- 4.1 XGStrategySoldier.m_iEnergy Default Value
- 4.2 XGFacility_Barracks.HealAndRest
- 4.3 XGStrategySoldier.HasPerk
- 4.4 UISoldierPromotion.CheckForAutoAssignPerk
- 4.5 XGSoldierUI.OnAcceptPromotion
- 4.6 XGStrategySoldier.PerkLockedOut
- 4.7 XGStrategySoldier.HasAvailablePerksToAssign
- 4.8 XGSoldierUI.ShouldAutoAssignPerk
- 4.9 UISoldierPromotion.UpdateAbilityData
- 5 References
Overview
This page deals with the UPK file changes necessary to implement the Enhanced Perk Tree mod
These changes only deal with altering the behavior of the Perk/Abilities/Psi Abilities interface. UPK changes to implement the perks are implemented here:
All of these changes are applied to XComStrategyGame.upk
Programs and Tools
- UE Explorer
- HxD Hex Editor
See Modding Tools - XCOM:EU 2012 for descriptions and links.
Details
There are nine distinct hex changes necessary to implement this portion of the Enhanced Perk Tree mod.
One of the changes requires an identical search/replace in three separate locations, bringing the total number of separate hex changes to eleven.
The upk interface code refers variously to 'rows', 'options', 'branches', and 'columns'
- Row corresponds with 'option', and relates to the number of ability icons displayed per rank
- Both 'row' and 'option' are indexed starting at 0
- Column corresponds with 'branch', and relates to the soldier rank
- 'column' is indexed starting from 0, but 'branch' is indexed starting from 1
- Change the default value of XGStrategySoldier.m_iEnergy from 100 to 0
- Three distinct but identical changes in XGFacility_Barracks.HealAndRest to prevent m_iEnergy from being updated
- Rewrite XGStrategySoldier.HasPerk to check only bit 0 of aUpgrades[]
- Rewrite UISoldierPromotion.CheckForAutoAssignPerk to advance the promotion rank if no valid perks are available at the current rank
- Rewrite XGSoldierUI.OnAcceptPromotion to mark the promotion flag in m_iEnergy upon accepting a promotion
- Rewrite XGStrategySoldier.PerkLockedOut to remove check to see if another perk at the current rank is already granted
- Rewrite XGStrategySoldier.HasAvailablePerksToAssign to check only the flags in m_iEnergy to see if a promotion is available
- Rewrite XGSoldierUI.ShouldAutoAssignPerk to check for any selectable perks, and mark m_iEnergy flags if none available
- Rewrite UISoldierPromotion.UpdateAbilityData -- this is the primary interface to the actionscript functions
File Changes
XGStrategySoldier.m_iEnergy Default Value
This changes the default value of XGStrategySoldier.m_iEnergy from 100 to 0
Hex Change
In XcomStrategyGame, at offset 0x3BE3D9, change the value from 0x64 to 0x00
Decompiled Code
Original Code
defaultproperties { ... m_iEnergy=100 ... }
New Code
defaultproperties { ... m_iEnergy=0 ... }
XGFacility_Barracks.HealAndRest
This change prevents the assignment of a value to m_iEnergy in HealAndRest. This search/replace will occur three times. All three occurences must be changed.
Hex Change
original: | 0F 19 00 49 28 00 00 09 00 E9 44 00 00 00 01 E9 44 00 00 2C 64 |
new: | 0B 19 00 49 28 00 00 09 00 E9 44 00 00 00 01 E9 44 00 00 2C 64 |
Decompiled Code
Original Code
kSoldier.m_iEnergy = 100;
New Code
kSoldier.m_iEnergy 100
XGStrategySoldier.HasPerk
This change alters the HasPerk function from:
- returning true if aUpgrades[perk] > 0
to
- returning true if bit 0 of aUpgrades[perk] is 1.
This change was made for future support of equippable items that granting perks, and not preventing selection of perks from the perk tree based upon equipped items.
Hex Change
original: | 98 45 00 00 AB 1F 00 00 00 00 00 00 96 45 00 00 00 00 00 00 00 00 00 00 98 45 00 00 00 00 00 00 84 04 00 00 1A 78 00 00 35 00 00 00 21 00 00 00 04 97 1A 00 98 45 00 00 35 A7 FB FF FF 7E FA FF FF 00 00 01 ED 44 00 00 25 16 04 3A 97 45 00 00 53 |
new: | 98 45 00 00 AB 1F 00 00 00 00 00 00 96 45 00 00 00 00 00 00 00 00 00 00 98 45 00 00 00 00 00 00 84 04 00 00 1A 78 00 00 31 00 00 00 21 00 00 00 04 9A 9C 1A 00 98 45 00 00 35 A7 FB FF FF 7E FA FF FF 00 00 01 ED 44 00 00 26 16 26 16 04 0B 0B 53 |
Decompiled Code
Original Code
function bool HasPerk(int iPerk) { return m_kChar.aUpgrades[iPerk] > 0; //return ReturnValue; }
New Code
function bool HasPerk(int iPerk) { return (m_kChar.aUpgrades[iPerk] & 1) == 1; }
UISoldierPromotion.CheckForAutoAssignPerk
This change alters the response to ShouldAutoAssignPerk returning true. The function now simply refreshes the perk tree UI window.
Hex Change
original: | CF 15 00 00 AB 1F 00 00 00 00 00 00 CE 15 00 00 00 00 00 00 00 00 00 00 CF 15 00 00 00 00 00 00 90 00 00 00 27 11 00 00 EE 00 00 00 CE 00 00 00 07 EB 00 82 84 81 19 1B 91 0F 00 00 00 00 00 00 4A 16 0A 00 96 00 00 00 00 1B 3D 14 00 00 00 00 00 00 16 16 18 3C 00 97 19 19 1B 91 0F 00 00 00 00 00 00 4A 16 0A 00 9C 00 00 00 00 1B 4C 0E 00 00 00 00 00 00 16 0B 00 66 41 00 00 00 1B D1 0F 00 00 00 00 00 00 4A 16 26 16 16 18 2B 00 19 1B 91 0F 00 00 00 00 00 00 4A 16 13 00 C0 3F 00 00 00 1B 7E 24 00 00 00 00 00 00 00 CF 15 00 00 16 16 19 1B 91 0F 00 00 00 00 00 00 4A 16 13 00 00 00 00 00 00 1B A4 23 00 00 00 00 00 00 00 CF 15 00 00 16 19 1B 91 0F 00 00 00 00 00 00 4A 16 0B 00 00 00 00 00 00 1B A5 23 00 00 00 00 00 00 25 16 1B 6E 00 00 00 00 00 00 00 16 04 0B 53 |
new: | CF 15 00 00 AB 1F 00 00 00 00 00 00 CE 15 00 00 00 00 00 00 00 00 00 00 CF 15 00 00 00 00 00 00 90 00 00 00 27 11 00 00 E2 00 00 00 CE 00 00 00 07 72 00 82 19 01 AE 15 00 00 14 00 12 45 00 00 00 1B 05 11 00 00 00 00 00 00 2D 01 AF 15 00 00 16 18 2A 00 19 1B 91 0F 00 00 00 00 00 00 4A 16 13 00 C0 3F 00 00 00 1B 7E 24 00 00 00 00 00 00 00 CF 15 00 00 16 16 1B 0A 13 00 00 00 00 00 00 16 1B 8F 2B 00 00 00 00 00 00 16 06 00 00 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 04 0B 53 |
Decompiled Code
Original Code
simulated function CheckForAutoAssignPerk() { local int iBranch; // End:0xEB if((!GetMgr().ISCONTROLLED() || GetMgr().Game().GetNumMissionsTaken() > 1) && GetMgr().ShouldAutoAssignPerk(iBranch)) { GetMgr().SetAbilityTreeBranch(iBranch); GetMgr().SetAbilityTreeOption(0); AcceptDialogue(); } //return; }
New Code
simulated function CheckForAutoAssignPerk() { local int iBranch; // End:0xEB if(m_kSoldier.HasAvailablePerksToAssign(m_bPsiPromotion) && GetMgr().ShouldAutoAssignPerk(iBranch)) { InitializeTree(); UpdateAbilityData(); // continue Loop goto 0x00; } //return; }
XGSoldierUI.OnAcceptPromotion
This change alters OnAcceptPromotion to set the appropriate flag in m_iEnergy when a valid promotion is accepted.
Hex Change
original: | AE 3F 00 00 AB 1F 00 00 00 00 00 00 AC 3F 00 00 00 00 00 00 00 00 00 00 AE 3F 00 00 00 00 00 00 1E 02 00 00 C2 35 00 00 86 01 00 00 2A 01 00 00 0F 00 AD 3F 00 00 1B F2 0F 00 00 00 00 00 00 35 30 FF FF FF 7D FA FF FF 00 00 35 B4 F9 FF FF 74 FA FF FF 00 00 19 01 79 3F 00 00 09 00 EC 44 00 00 00 01 EC 44 00 00 1B 6F 0E 00 00 00 00 00 00 16 1B 70 0E 00 00 00 00 00 00 16 9A 01 7E 08 00 00 2C 02 16 16 07 BD 00 19 01 79 3F 00 00 2A 00 17 45 00 00 00 1B AD 21 00 00 00 00 00 00 00 AD 3F 00 00 1B 6F 0E 00 00 00 00 00 00 16 9A 01 7E 08 00 00 2C 02 16 16 04 28 07 6F 01 82 81 19 01 79 3F 00 00 13 00 97 45 00 00 00 1B 1B 11 00 00 00 00 00 00 00 AD 3F 00 00 16 16 18 0D 00 81 1B 14 22 00 00 00 00 00 00 16 16 16 19 01 79 3F 00 00 13 00 00 00 00 00 00 1B D3 10 00 00 00 00 00 00 00 AD 3F 00 00 16 19 1B 86 26 00 00 00 00 00 00 16 29 00 00 00 00 00 00 1B E1 21 00 00 00 00 00 00 19 1B 66 26 00 00 00 00 00 00 16 09 00 CB FA FF FF 00 01 CB FA FF FF 16 1B 29 2C 00 00 00 00 00 00 16 06 79 01 1B C3 21 00 00 00 00 00 00 16 04 27 04 3A AE 3F 00 00 53 |
new: | AE 3F 00 00 AB 1F 00 00 00 00 00 00 AC 3F 00 00 00 00 00 00 00 00 00 00 AE 3F 00 00 00 00 00 00 1E 02 00 00 C2 35 00 00 8E 01 00 00 2A 01 00 00 0F 00 AD 3F 00 00 1B F2 0F 00 00 00 00 00 00 35 30 FF FF FF 7D FA FF FF 00 00 35 B4 F9 FF FF 74 FA FF FF 00 00 19 01 79 3F 00 00 09 00 EC 44 00 00 00 01 EC 44 00 00 1B 6F 0E 00 00 00 00 00 00 16 1B 70 0E 00 00 00 00 00 00 16 9A 01 7E 08 00 00 2C 02 16 16 07 80 01 81 19 01 79 3F 00 00 13 00 97 45 00 00 00 1B 1B 11 00 00 00 00 00 00 00 AD 3F 00 00 16 16 19 01 79 3F 00 00 13 00 00 00 00 00 00 1B D3 10 00 00 00 00 00 00 00 AD 3F 00 00 16 19 1B 86 26 00 00 00 00 00 00 16 29 00 00 00 00 00 00 1B E1 21 00 00 00 00 00 00 19 1B 66 26 00 00 00 00 00 00 16 09 00 CB FA FF FF 00 01 CB FA FF FF 16 1B 29 2C 00 00 00 00 00 00 16 0F 19 01 79 3F 00 00 09 00 E9 44 00 00 00 01 E9 44 00 00 9E 19 01 79 3F 00 00 09 00 E9 44 00 00 00 01 E9 44 00 00 94 26 92 93 1B 6F 0E 00 00 00 00 00 00 16 26 16 45 9A 01 7E 08 00 00 2C 02 16 02 00 2C 10 01 00 25 16 16 16 06 8A 01 1B C3 21 00 00 00 00 00 00 16 04 27 0B 53 |
Decompiled Code
Original Code
function bool OnAcceptPromotion() { local int perk; perk = GetPerkInTree(m_kSoldier.m_kSoldier.kClass.eType, GetAbilityTreeBranch(), GetAbilityTreeOption(), m_iCurrentView == 2); // End:0xBD if(m_kSoldier.PerkLockedOut(perk, GetAbilityTreeBranch(), m_iCurrentView == 2)) { return false; } // End:0x16F if(!m_kSoldier.HasPerk(perk) && !PreviousPerksToAssign()) { m_kSoldier.GivePerk(perk); Sound().PlaySFX(SNDLIB().SFX_UI_ChoosePromotion); UpdateView(); } // End:0x179 else { PlayBadSound(); } return true; //return ReturnValue; }
New Code
function bool OnAcceptPromotion() { local int perk; perk = GetPerkInTree(m_kSoldier.m_kSoldier.kClass.eType, GetAbilityTreeBranch(), GetAbilityTreeOption(), m_iCurrentView == 2); // removed redundant check to PerkLockedOut if(!m_kSoldier.HasPerk(perk) && !PreviousPerksToAssign()) { m_kSoldier.GivePerk(perk); Sound().PlaySFX(SNDLIB().SFX_UI_ChoosePromotion); UpdateView(); //set flag indicating soldier has chosen ability at this rank m_kSoldier.m_iEnergy = m_kSoldier.m_iEnergy | (1 << (GetAbilityTreeBranch() + (m_iCurrentView == 2 ? 16 : 0))); } else { PlayBadSound(); } return true; //return ReturnValue; }
XGStrategySoldier.PerkLockedOut
This changes the behavior of PerkLockedOut, removing the prior check testing if any other perk available at the current branch was already granted to a soldier, and replacing it with a check against the m_iEnergy flag.
Hex Change
original: | 1A 45 00 00 AB 1F 00 00 00 00 00 00 14 45 00 00 00 00 00 00 00 00 00 00 1A 45 00 00 00 00 00 00 21 01 00 00 D7 21 00 00 1E 01 00 00 D6 00 00 00 49 02 00 28 15 07 2F 00 2D 00 18 45 00 00 07 2C 00 97 00 19 45 00 00 1B 05 10 00 00 00 00 00 00 16 16 04 27 06 5B 00 07 49 00 97 00 19 45 00 00 1B 10 10 00 00 00 00 00 00 16 16 04 27 07 5B 00 9A 1B 10 10 00 00 00 00 00 00 16 25 16 04 27 0F 00 16 45 00 00 25 07 11 01 96 00 16 45 00 00 2C 02 16 0F 00 15 45 00 00 19 1B AE 21 00 00 00 00 00 00 16 55 00 4F FC FF FF 00 1B F2 0F 00 00 00 00 00 00 35 30 FF FF FF 7D FA FF FF 00 00 35 B4 F9 FF FF 74 FA FF FF 00 00 01 EC 44 00 00 00 19 45 00 00 00 16 45 00 00 2D 00 18 45 00 00 16 07 03 01 1B 1B 11 00 00 00 00 00 00 00 15 45 00 00 16 04 27 A5 00 16 45 00 00 16 06 66 00 04 28 04 3A 17 45 00 00 53 |
new: | 1A 45 00 00 AB 1F 00 00 00 00 00 00 14 45 00 00 00 00 00 00 00 00 00 00 1A 45 00 00 00 00 00 00 21 01 00 00 D7 21 00 00 F2 00 00 00 D6 00 00 00 49 02 00 28 15 07 2F 00 2D 00 18 45 00 00 07 2C 00 97 00 19 45 00 00 1B 05 10 00 00 00 00 00 00 16 16 04 27 06 5B 00 07 49 00 97 00 19 45 00 00 1B 10 10 00 00 00 00 00 00 16 16 04 27 07 5B 00 9A 1B 10 10 00 00 00 00 00 00 16 25 16 04 27 07 91 00 97 9C 01 E9 44 00 00 94 26 92 93 00 19 45 00 00 26 16 45 2D 00 18 45 00 00 02 00 2C 10 01 00 25 16 16 16 25 16 04 27 04 28 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 04 3A 17 45 00 00 53 |
Decompiled Code
Original Code
function bool PerkLockedOut(int perk, int branch, optional bool isPsiPerk) { local int iOptions, iPerk; isPsiPerk = false; // End:0x2F if(isPsiPerk) { // End:0x2C if(branch > (GetPsiRank())) { return true; } } // End:0x5B else { // End:0x49 if(branch > (GetRank())) { return true; } // End:0x5B if((GetRank()) == 0) { return true; } } iOptions = 0; J0x66: // End:0x111 [Loop If] if(iOptions < 2) { iPerk = perkMgr().GetPerkInTree(m_kSoldier.kClass.eType, branch, iOptions, isPsiPerk); // End:0x103 if(HasPerk(iPerk)) { return true; } ++ iOptions; // [Loop Continue] goto J0x66; } return false; //return ReturnValue; }
New Code
function bool PerkLockedOut(int perk, int branch, optional bool isPsiPerk) { local int iOptions, iPerk; isPsiPerk = false; // End:0x2F if(isPsiPerk) { // End:0x2C if(branch > (GetPsiRank())) { return true; } } // End:0x5B else { // End:0x49 if(branch > (GetRank())) { return true; } // End:0x5B if((GetRank()) == 0) { return true; } } if((m_iEnergy & (1 << ((branch-1) + (isPsiPerk ? 16 : 0)))) > 0) { return true; } return false; //return ReturnValue; }
XGStrategySoldier.HasAvailablePerksToAssign
This changes the function HasAvailablePerksToAssign so that it checks the flags in m_iEnergy instead of looking at perks assigned to a soldier.
It also adds support for future mod extensions that will allow the use of perks defined in branches 8-11.
Hex Change
original: | 13 45 00 00 AB 1F 00 00 00 00 00 00 0E 45 00 00 00 00 00 00 00 00 00 00 13 45 00 00 00 00 00 00 EF 00 00 00 70 1D 00 00 2A 02 00 00 B6 01 00 00 49 02 00 28 15 07 29 00 82 9A 1B 10 10 00 00 00 00 00 00 16 25 16 18 0E 00 9A 1B 05 10 00 00 00 00 00 00 16 25 16 16 04 28 07 3B 01 2D 00 13 45 00 00 07 38 01 1B 1F 11 00 00 00 00 00 00 16 0F 00 11 45 00 00 26 07 38 01 96 00 11 45 00 00 92 1B 05 10 00 00 00 00 00 00 16 26 16 16 07 7C 00 99 00 11 45 00 00 2C 04 16 06 2A 01 0F 00 10 45 00 00 25 07 2A 01 96 00 10 45 00 00 2C 02 16 0F 00 0F 45 00 00 19 1B AE 21 00 00 00 00 00 00 16 27 00 4F FC FF FF 00 1B F2 0F 00 00 00 00 00 00 1B B5 0E 00 00 00 00 00 00 16 00 11 45 00 00 00 10 45 00 00 27 16 07 1C 01 82 81 1B AD 21 00 00 00 00 00 00 00 0F 45 00 00 00 11 45 00 00 27 16 16 18 16 00 81 1B 1B 11 00 00 00 00 00 00 00 0F 45 00 00 16 16 16 04 27 A5 00 10 45 00 00 16 06 87 00 A5 00 11 45 00 00 16 06 4E 00 06 1D 02 0F 00 11 45 00 00 26 07 1D 02 96 00 11 45 00 00 92 1B 10 10 00 00 00 00 00 00 16 26 16 16 0F 00 10 45 00 00 25 07 0F 02 96 00 10 45 00 00 2C 02 16 0F 00 0F 45 00 00 19 1B AE 21 00 00 00 00 00 00 16 27 00 4F FC FF FF 00 1B F2 0F 00 00 00 00 00 00 1B B5 0E 00 00 00 00 00 00 16 00 11 45 00 00 00 10 45 00 00 4A 16 07 01 02 82 81 1B AD 21 00 00 00 00 00 00 00 0F 45 00 00 00 11 45 00 00 4A 16 16 18 16 00 81 1B 1B 11 00 00 00 00 00 00 00 0F 45 00 00 16 16 16 04 27 A5 00 10 45 00 00 16 06 6C 01 A5 00 11 45 00 00 16 06 46 01 04 28 04 3A 12 45 00 00 53 |
new: | 13 45 00 00 AB 1F 00 00 00 00 00 00 0E 45 00 00 00 00 00 00 00 00 00 00 13 45 00 00 00 00 00 00 EF 00 00 00 70 1D 00 00 F2 01 00 00 B6 01 00 00 49 02 00 28 15 07 17 01 2D 00 13 45 00 00 07 6C 00 1B 1F 11 00 00 00 00 00 00 16 0F 00 11 45 00 00 26 07 6C 00 98 00 11 45 00 00 1B 05 10 00 00 00 00 00 00 16 16 07 5E 00 81 1B AD 21 00 00 00 00 00 00 26 00 11 45 00 00 27 16 16 04 27 A5 00 11 45 00 00 16 06 2A 00 0F 00 10 45 00 00 1B 10 10 00 00 00 00 00 00 16 07 A5 00 99 00 10 45 00 00 2C 01 16 07 A5 00 81 1B AD 21 00 00 00 00 00 00 26 2C 08 27 16 16 04 27 07 CA 00 99 00 10 45 00 00 2C 03 16 07 CA 00 81 1B AD 21 00 00 00 00 00 00 26 2C 09 27 16 16 04 27 07 EF 00 99 00 10 45 00 00 2C 04 16 07 EF 00 81 1B AD 21 00 00 00 00 00 00 26 2C 0A 27 16 16 04 27 07 14 01 99 00 10 45 00 00 2C 05 16 07 14 01 81 1B AD 21 00 00 00 00 00 00 26 2C 0B 27 16 16 04 27 06 64 01 0F 00 11 45 00 00 26 07 64 01 98 00 11 45 00 00 1B 10 10 00 00 00 00 00 00 16 16 07 56 01 81 1B AD 21 00 00 00 00 00 00 26 00 11 45 00 00 4A 16 16 04 27 A5 00 11 45 00 00 16 06 22 01 04 28 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 04 3A 12 45 00 00 53 |
Decompiled Code
Original Code
function bool HasAvailablePerksToAssign(optional bool CheckForPsiPromotion) { local int iIndex, jIndex, iPerk; CheckForPsiPromotion = false; // End:0x29 if(((GetRank()) == 0) && (GetPsiRank()) == 0) { return false; } // End:0x13B if(CheckForPsiPromotion) { // End:0x138 if(HasPsiGift()) { iIndex = 1; J0x4E: // End:0x138 [Loop If] if(iIndex < ((GetPsiRank()) + 1)) { // End:0x7C if(iIndex >= 4) { } // End:0x12A else { jIndex = 0; J0x87: // End:0x12A [Loop If] if(jIndex < 2) { iPerk = perkMgr().GetPerkInTree(GetClass(), iIndex, jIndex, true); // End:0x11C if(!PerkLockedOut(iPerk, iIndex, true) && !HasPerk(iPerk)) { return true; } ++ jIndex; // [Loop Continue] goto J0x87; } } ++ iIndex; // [Loop Continue] goto J0x4E; } } } // End:0x21D else { iIndex = 1; J0x146: // End:0x21D [Loop If] if(iIndex < ((GetRank()) + 1)) { jIndex = 0; J0x16C: // End:0x20F [Loop If] if(jIndex < 2) { iPerk = perkMgr().GetPerkInTree(GetClass(), iIndex, jIndex); // End:0x201 if(!PerkLockedOut(iPerk, iIndex) && !HasPerk(iPerk)) { return true; } ++ jIndex; // [Loop Continue] goto J0x16C; } ++ iIndex; // [Loop Continue] goto J0x146; } } return false; //return ReturnValue; }
New Code
function bool HasAvailablePerksToAssign(optional bool CheckForPsiPromotion) { local int iIndex, jIndex, iPerk; CheckForPsiPromotion = false; if(CheckForPsiPromotion) { // End:0x138 if(HasPsiGift()) { iIndex = 1; J0x4E: // End:0x138 [Loop If] if(iIndex <= GetPsiRank()) { if(!PerkLockedOut(1, iIndex, true)) { return true; } ++ iIndex; // [Loop Continue] goto J0x4E; } } // non-psi gift increases, put in Psi tree UI jIndex = GetRank(); if(jIndex >= 1) // first ability increase at level 1 { if(!PerkLockedOut(1,8,false) //check if bit 8 has been set { return true; } } if(jIndex >= 3) // second ability increase at level 3 { if(!PerkLockedOut(1,9,false) //check if bit 9 has been set { return true; } } if(jIndex >= 4) // third ability increase at level 4 { if(!PerkLockedOut(1,10,false) //check if bit 10 has been set { return true; } } if(jIndex >= 6) // fourth ability increase at level 6 { if(!PerkLockedOut(1,11,false) //check if bit 11 has been set { return true; } } } // End:0x21D else { iIndex = 1; J0x146: // End:0x21D [Loop If] if(iIndex <= GetRank()) { // explicit check to see if this level is promotable if(!PerkLockedOut(1, iIndex, true)) { return true; } ++ iIndex; // [Loop Continue] goto J0x146; } } return false; //return ReturnValue; }
XGSoldierUI.ShouldAutoAssignPerk
This changes the test for auto-assigning a perk. It no longer tests whether row0 = row1. Instead it loops over all perks in the current branch, searching for a valid (non-zero) perk that the soldier does not already have. If it finds no valid perks then it marks the bit flag in m_iEnergy to 1 for the current branch and returns true.
Hex Change
original: | C1 3F 00 00 AB 1F 00 00 00 00 00 00 BC 3F 00 00 00 00 00 00 00 00 00 00 C1 3F 00 00 00 00 00 00 8C 02 00 00 22 3F 00 00 86 01 00 00 0E 01 00 00 0F 00 BF 3F 00 00 1B 6F 0E 00 00 00 00 00 00 16 0F 00 BE 3F 00 00 19 1B AE 21 00 00 00 00 00 00 16 65 00 4F FC FF FF 00 1B F2 0F 00 00 00 00 00 00 35 30 FF FF FF 7D FA FF FF 00 00 35 B4 F9 FF FF 74 FA FF FF 00 00 19 01 79 3F 00 00 09 00 EC 44 00 00 00 01 EC 44 00 00 00 BF 3F 00 00 25 9A 01 7E 08 00 00 2C 02 16 16 0F 00 BD 3F 00 00 19 1B AE 21 00 00 00 00 00 00 16 65 00 4F FC FF FF 00 1B F2 0F 00 00 00 00 00 00 35 30 FF FF FF 7D FA FF FF 00 00 35 B4 F9 FF FF 74 FA FF FF 00 00 19 01 79 3F 00 00 09 00 EC 44 00 00 00 01 EC 44 00 00 00 BF 3F 00 00 26 9A 01 7E 08 00 00 2C 02 16 16 07 6A 01 82 82 9A 00 BE 3F 00 00 00 BD 3F 00 00 16 18 0D 00 99 00 BE 3F 00 00 25 16 16 18 0B 00 1B 1D 05 00 00 00 00 00 00 16 16 0F 48 C1 3F 00 00 00 BF 3F 00 00 04 27 0F 48 C1 3F 00 00 1D FF FF FF FF 04 28 04 3A C0 3F 00 00 53 |
new: | C1 3F 00 00 AB 1F 00 00 00 00 00 00 BC 3F 00 00 00 00 00 00 00 00 00 00 C1 3F 00 00 00 00 00 00 8C 02 00 00 22 3F 00 00 82 01 00 00 0E 01 00 00 0F 00 BF 3F 00 00 1B 6F 0E 00 00 00 00 00 00 16 0F 00 BE 3F 00 00 25 07 09 01 96 00 BE 3F 00 00 2C 03 16 0F 00 BD 3F 00 00 19 1B AE 21 00 00 00 00 00 00 16 65 00 4F FC FF FF 00 1B F2 0F 00 00 00 00 00 00 35 30 FF FF FF 7D FA FF FF 00 00 35 B4 F9 FF FF 74 FA FF FF 00 00 19 01 79 3F 00 00 09 00 EC 44 00 00 00 01 EC 44 00 00 00 BF 3F 00 00 00 BE 3F 00 00 9A 01 7E 08 00 00 2C 02 16 16 07 FA 00 97 00 BD 3F 00 00 25 16 07 FA 00 81 19 01 79 3F 00 00 13 00 97 45 00 00 00 1B 1B 11 00 00 00 00 00 00 00 BD 3F 00 00 16 16 04 28 A1 00 BE 3F 00 00 26 16 06 1F 00 0F 19 01 79 3F 00 00 09 00 E9 44 00 00 00 01 E9 44 00 00 9E 19 01 79 3F 00 00 09 00 E9 44 00 00 00 01 E9 44 00 00 94 26 92 93 00 BF 3F 00 00 26 16 45 9A 01 7E 08 00 00 2C 02 16 02 00 2C 10 01 00 25 16 16 16 04 27 0B 0B 0B 0B 0B 0B 0B 04 3A C0 3F 00 00 53 |
Decompiled Code
Original Code
function bool ShouldAutoAssignPerk(out int iBranchToAssign) { local int iBranch, perkA, perkB; iBranch = GetAbilityTreeBranch(); perkA = perkMgr().GetPerkInTree(m_kSoldier.m_kSoldier.kClass.eType, iBranch, 0, m_iCurrentView == 2); perkB = perkMgr().GetPerkInTree(m_kSoldier.m_kSoldier.kClass.eType, iBranch, 1, m_iCurrentView == 2); // End:0x16A if(((perkA == perkB) && perkA >= 0) && CanPromote()) { iBranchToAssign = iBranch; return true; } iBranchToAssign = -1; return false; //return ReturnValue; }
New Code
function bool ShouldAutoAssignPerk(out int iBranchToAssign) { local int iBranch, perkA, perkB; iBranch = GetAbilityTreeBranch(); perkA = 0; // use as loop counter if(perkA < 3) { perkB = perkMgr().GetPerkInTree(m_kSoldier.m_kSoldier.kClass.eType, iBranch, perkA, m_iCurrentView == 2) if(perkB > 0) { if(!m_kSoldier.HasPerk(perkB)) { return false; } } } m_kSoldier.m_iEnergy = m_kSoldier.m_iEnergy | (1 << (iBranch - 1 + (m_iCurrentView == 2 ? 16 : 0))); iBranchToAssign = -1; return true; //return ReturnValue; }
UISoldierPromotion.UpdateAbilityData
This function has been extensively rewritten. It is the primary interface to the actionscript that implements the perk tree UI.
This new function does the following:
- Allows display of up to 3 ability icons
- Suppresses display of ability icons above the soldier's current rank
- Suppresses display of ability icons that GetPerkInTree returns 0 for
- Sets the Column mode:
- mode = 0 : already promoted - cyan border, icons are highlighted if soldier HasPerk, dimmed if !HasPerk (shows previously selected perks)
- mode = 1 : current promotion - yellow border, icons are highlighted if soldier !HasPerk, dimmed if soldier HasPerk (shows perks that can be selected)
- mode = 2 : future promotion - dimmed yellow border, icons are invisible (shows soldier has reached rank, but cannot select perks until previous selection is made)
- mode = 3 : above rank - border and icons invisible (if soldier has not reached the rank necessary)
- Enables display of rank string for Psionic ranks
Hex Change
original: | E5 15 00 00 AB 1F 00 00 00 00 00 00 DE 15 00 00 00 00 00 00 00 00 00 00 E5 15 00 00 00 00 00 00 4A 01 00 00 90 27 00 00 B9 05 00 00 09 04 00 00 07 45 00 2D 01 AF 15 00 00 0F 00 E2 15 00 00 2C 03 0F 00 E1 15 00 00 19 01 AE 15 00 00 0A 00 02 45 00 00 00 1B 05 10 00 00 00 00 00 00 16 06 7A 00 0F 00 E2 15 00 00 2C 07 0F 00 E1 15 00 00 19 01 AE 15 00 00 0A 00 00 45 00 00 00 1B 10 10 00 00 00 00 00 00 16 14 2D 00 DF 15 00 00 27 0F 00 E5 15 00 00 25 07 AB 05 96 00 E5 15 00 00 00 E2 15 00 00 16 14 2D 00 E0 15 00 00 27 0F 00 E4 15 00 00 25 07 F8 02 96 00 E4 15 00 00 2C 02 16 07 18 01 97 00 E4 15 00 00 25 16 07 F3 00 9A 00 E5 15 00 00 25 16 06 F8 02 06 18 01 07 18 01 82 F2 2D 01 AF 15 00 00 28 16 18 0E 00 9A 00 E5 15 00 00 2C 05 16 16 06 F8 02 0F 00 E3 15 00 00 19 1B 91 0F 00 00 00 00 00 00 4A 16 6D 00 D3 3F 00 00 00 1B F2 0F 00 00 00 00 00 00 35 30 FF FF FF 7D FA FF FF 00 00 35 B4 F9 FF FF 74 FA FF FF 00 00 19 01 AE 15 00 00 09 00 EC 44 00 00 00 01 EC 44 00 00 92 00 E5 15 00 00 26 16 00 E4 15 00 00 2D 01 AF 15 00 00 16 07 F6 01 84 19 01 AE 15 00 00 13 00 97 45 00 00 00 1B 1B 11 00 00 00 00 00 00 00 E3 15 00 00 16 18 15 00 99 00 E5 15 00 00 00 E1 15 00 00 16 16 14 2D 00 E0 15 00 00 28 07 5D 02 99 00 E5 15 00 00 00 E1 15 00 00 16 1B 19 02 00 00 00 00 00 00 00 E5 15 00 00 00 E4 15 00 00 1F 75 6E 6B 6E 6F 77 6E 00 19 01 AE 15 00 00 13 00 97 45 00 00 00 1B 1B 11 00 00 00 00 00 00 00 E3 15 00 00 16 16 06 EA 02 1B 19 02 00 00 00 00 00 00 00 E5 15 00 00 00 E4 15 00 00 12 20 A1 FE FF FF 34 00 1B FA FF FF 00 1B F1 0F 00 00 00 00 00 00 00 E3 15 00 00 19 1B 91 0F 00 00 00 00 00 00 4A 16 0A 00 D8 00 00 00 00 1B AE 21 00 00 00 00 00 00 16 16 19 01 AE 15 00 00 13 00 97 45 00 00 00 1B 1B 11 00 00 00 00 00 00 00 E3 15 00 00 16 16 A3 00 E4 15 00 00 16 06 BF 00 07 6A 04 2D 00 E0 15 00 00 07 DA 03 2D 00 DF 15 00 00 14 2D 00 DF 15 00 00 28 19 1B 91 0F 00 00 00 00 00 00 4A 16 16 00 00 00 00 00 00 1B A4 23 00 00 00 00 00 00 92 00 E5 15 00 00 26 16 16 1B 28 02 00 00 00 00 00 00 00 E5 15 00 00 EB 19 19 2E 92 FE FF FF 19 12 20 FD FE FF FF 0A 00 3B FB FF FF 00 1C 92 FD FF FF 16 09 00 25 FB FF FF 00 01 25 FB FF FF 09 00 01 FB FF FF 00 01 01 FB FF FF 18 00 EC F9 FF FF 00 1B 12 10 00 00 00 00 00 00 92 00 E5 15 00 00 26 16 4A 4A 16 16 26 16 06 67 04 1B 28 02 00 00 00 00 00 00 00 E5 15 00 00 EB 19 19 2E 92 FE FF FF 19 12 20 FD FE FF FF 0A 00 3B FB FF FF 00 1C 92 FD FF FF 16 09 00 25 FB FF FF 00 01 25 FB FF FF 09 00 01 FB FF FF 00 01 01 FB FF FF 18 00 EC F9 FF FF 00 1B 12 10 00 00 00 00 00 00 92 00 E5 15 00 00 26 16 4A 4A 16 16 2C 02 16 06 9D 05 07 11 05 99 00 E5 15 00 00 00 E1 15 00 00 16 1B 28 02 00 00 00 00 00 00 00 E5 15 00 00 EB 19 19 2E 92 FE FF FF 19 12 20 FD FE FF FF 0A 00 3B FB FF FF 00 1C 92 FD FF FF 16 09 00 25 FB FF FF 00 01 25 FB FF FF 09 00 01 FB FF FF 00 01 01 FB FF FF 18 00 EC F9 FF FF 00 1B 12 10 00 00 00 00 00 00 92 00 E5 15 00 00 26 16 4A 4A 16 16 2C 03 16 06 9D 05 1B 28 02 00 00 00 00 00 00 00 E5 15 00 00 EB 19 19 2E 92 FE FF FF 19 12 20 FD FE FF FF 0A 00 3B FB FF FF 00 1C 92 FD FF FF 16 09 00 25 FB FF FF 00 01 25 FB FF FF 09 00 01 FB FF FF 00 01 01 FB FF FF 18 00 EC F9 FF FF 00 1B 12 10 00 00 00 00 00 00 92 00 E5 15 00 00 26 16 4A 4A 16 16 25 16 A3 00 E5 15 00 00 16 06 91 00 1C E8 15 00 00 4A 16 04 0B 53 |
new: | E5 15 00 00 AB 1F 00 00 00 00 00 00 DE 15 00 00 00 00 00 00 00 00 00 00 E5 15 00 00 00 00 00 00 4A 01 00 00 90 27 00 00 25 05 00 00 09 04 00 00 07 45 00 2D 01 AF 15 00 00 0F 00 E2 15 00 00 2C 03 0F 00 E1 15 00 00 19 01 AE 15 00 00 0A 00 02 45 00 00 00 1B 05 10 00 00 00 00 00 00 16 06 7A 00 0F 00 E2 15 00 00 2C 07 0F 00 E1 15 00 00 19 01 AE 15 00 00 0A 00 00 45 00 00 00 1B 10 10 00 00 00 00 00 00 16 14 2D 00 DF 15 00 00 27 0F 00 E5 15 00 00 25 07 AA 03 96 00 E5 15 00 00 2C 07 16 07 D6 00 97 92 00 E5 15 00 00 26 16 00 E1 15 00 00 16 0F 00 E4 15 00 00 2C 03 14 2D 00 DF 15 00 00 28 06 FF 02 14 2D 00 E0 15 00 00 9A 9C 19 01 AE 15 00 00 09 00 E9 44 00 00 00 01 E9 44 00 00 94 26 92 00 E5 15 00 00 45 2D 01 AF 15 00 00 02 00 2C 10 01 00 25 16 16 16 25 16 07 84 02 2D 00 DF 15 00 00 0F 00 E4 15 00 00 25 07 84 02 96 00 E4 15 00 00 2C 04 16 0F 00 E3 15 00 00 19 1B 91 0F 00 00 00 00 00 00 4A 16 6D 00 D3 3F 00 00 00 1B F2 0F 00 00 00 00 00 00 35 30 FF FF FF 7D FA FF FF 00 00 35 B4 F9 FF FF 74 FA FF FF 00 00 19 01 AE 15 00 00 09 00 EC 44 00 00 00 01 EC 44 00 00 92 00 E5 15 00 00 26 16 00 E4 15 00 00 2D 01 AF 15 00 00 16 07 76 02 97 00 E3 15 00 00 25 16 1B 19 02 00 00 00 00 00 00 00 E5 15 00 00 00 E4 15 00 00 12 20 A1 FE FF FF 34 00 1B FA FF FF 00 1B F1 0F 00 00 00 00 00 00 00 E3 15 00 00 19 1B 91 0F 00 00 00 00 00 00 4A 16 0A 00 D8 00 00 00 00 1B AE 21 00 00 00 00 00 00 16 16 19 01 AE 15 00 00 13 00 97 45 00 00 00 1B 1B 11 00 00 00 00 00 00 00 E3 15 00 00 16 16 A3 00 E4 15 00 00 16 06 3C 01 07 F4 02 2D 00 E0 15 00 00 07 E5 02 2D 00 DF 15 00 00 0F 00 E4 15 00 00 26 14 2D 00 DF 15 00 00 28 19 1B 91 0F 00 00 00 00 00 00 4A 16 16 00 00 00 00 00 00 1B A4 23 00 00 00 00 00 00 92 00 E5 15 00 00 26 16 16 06 F1 02 0F 00 E4 15 00 00 2C 02 06 FF 02 0F 00 E4 15 00 00 25 1B 28 02 00 00 00 00 00 00 00 E5 15 00 00 EB 19 19 2E 92 FE FF FF 19 12 20 FD FE FF FF 0A 00 3B FB FF FF 00 1C 92 FD FF FF 16 09 00 25 FB FF FF 00 01 25 FB FF FF 09 00 01 FB FF FF 00 01 01 FB FF FF 18 00 EC F9 FF FF 00 1B 12 10 00 00 00 00 00 00 92 00 E5 15 00 00 26 16 28 2D 01 AF 15 00 00 16 16 00 E4 15 00 00 16 A3 00 E5 15 00 00 16 06 91 00 1C E8 15 00 00 4A 16 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 04 0B 53 |
Decompiled Code
Original Code
protected simulated function UpdateAbilityData() { local int column, Row, perk, abilityColumns, SoldierRank; local bool isColumnPromotable, isFirstPromotableColumn; // End:0x45 if(m_bPsiPromotion) { abilityColumns = 3; SoldierRank = m_kSoldier.GetPsiRank(); } // End:0x7A else { abilityColumns = 7; SoldierRank = m_kSoldier.GetRank(); } isFirstPromotableColumn = true; column = 0; J0x91: // End:0x5AB [Loop If] if(column < abilityColumns) { isColumnPromotable = true; Row = 0; J0xBF: // End:0x2F8 [Loop If] if(Row < 3) { // End:0x118 if(Row < 0) { // End:0xF3 if(column == 0) { // [Explicit Break] goto J0x2F8; } // End:0x118 else { // End:0x118 if((m_bPsiPromotion == false) && column == 5) { // [Explicit Break] goto J0x2F8; } } } perk = GetMgr().GetPerkInTree(m_kSoldier.m_kSoldier.kClass.eType, column + 1, Row, m_bPsiPromotion); // End:0x1F6 if(m_kSoldier.HasPerk(perk) || column >= SoldierRank) { isColumnPromotable = false; } // End:0x25D if(column >= SoldierRank) { AS_SetAbilityIcon(column, Row, "unknown", m_kSoldier.HasPerk(perk)); } // End:0x2EA else { AS_SetAbilityIcon(column, Row, class'UIUtilities'.static.GetPerkIconLabel(perk, GetMgr().perkMgr()), m_kSoldier.HasPerk(perk)); } ++ Row; J0x2F8: // [Loop Continue] goto J0xBF; } // End:0x46A if(isColumnPromotable) { // End:0x3DA if(isFirstPromotableColumn) { isFirstPromotableColumn = false; GetMgr().SetAbilityTreeBranch(column + 1); AS_SetColumnData(column, Caps(XComGameReplicationInfo(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kGameCore.GetRankString(column + 1)), 1); } // End:0x467 else { AS_SetColumnData(column, Caps(XComGameReplicationInfo(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kGameCore.GetRankString(column + 1)), 2); } } // End:0x59D else { // End:0x511 if(column >= SoldierRank) { AS_SetColumnData(column, Caps(XComGameReplicationInfo(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kGameCore.GetRankString(column + 1)), 3); } // End:0x59D else { AS_SetColumnData(column, Caps(XComGameReplicationInfo(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kGameCore.GetRankString(column + 1)), 0); } } ++ column; // [Loop Continue] goto J0x91; } RealizeSelected(); //return; }
New Code
protected simulated function UpdateAbilityData() { local int column, Row, perk, abilityColumns, SoldierRank; local bool isColumnPromotable, isFirstPromotableColumn; // End:0x45 if(m_bPsiPromotion) { abilityColumns = 3; SoldierRank = m_kSoldier.GetPsiRank(); } // End:0x7A else { abilityColumns = 7; SoldierRank = m_kSoldier.GetRank(); } isFirstPromotableColumn = true; column = 0; J0x91: // End:0x5AB [Loop If] if(column < 7) // loop all the way up, in order to suppress brackets above current rank { if(column+1 > SoldierRank) // turn off columns above current soldier rank { row = 3; isFirstPromotableColumn = false; } else { // new check to see if column is promotable... based on data stored in m_iEnergy // regular rank promotions are marked in bits 0-6 (1 means has accepted promotion at that rank) // psi rank promotions are marked in bits 16-18 isColumnPromotable = ((m_kSoldier.m_iEnergy & (1 << (column + (m_bPsiPromotion ? 16 : 0)))) == 0); // only display icons up to the first promotable column if(isFirstPromotableColumn) { Row = 0; J0xBF: // End:0x2F8 [Loop If] if(Row < 4) { // keep call to retrieve perk, as before perk = GetMgr().GetPerkInTree(m_kSoldier.m_kSoldier.kClass.eType, column + 1, Row, m_bPsiPromotion); // only display icons for spots with valid perks if(perk > 0) { AS_SetAbilityIcon(column, Row, class'UIUtilities'.static.GetPerkIconLabel(perk, GetMgr().perkMgr()), m_kSoldier.HasPerk(perk)); } ++ Row; // loop continue goto J0xBF; } } //temporarily re-use the row variable to store the AS_SetColumnData mode if(isColumPromotable) { if(isFirstPromotableColumn) { // mode 1 -- column is highlighted and active row = 1; // activate this branch -- makes it valid to select perks isFirstPromotableColumn = false; GetMgr().SetAbilityTreeBranch(column + 1); } else { // mode 2 -- column is faded and inactive row = 2; } } else { // mode 0 -- column has been promoted -- column highlighting is off row = 0; } } AS_SetColumnData(column, Caps(XComGameReplicationInfo(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kGameCore.GetRankString(column + 1), false, m_bPsiPromotion), row); ++ column; // [Loop Continue] goto J0x91; } RealizeSelected(); //return; }
References
Referred to by this article:
- Original Nexus forum thread
- Modding Tools - XCOM:EU 2012
- XCOM:EU_Perks
- Enhanced Perk Tree mod - XCOMEU: 2012
- Table of Perk Codes and Offsets - XCOM:EU 2012
- XComStrategyGame.upk
That refer to this article: