Loadout File Changes Additional Items Mod XCOM:EU - 2012
Contents
Overview
This contains the file changes to the soldier loadout process.
Details
These changes are required in order to use:
- Alien items
- Sectoid Grenade, ThinMan Grenade, Muton Grenade, Cyberdisc Grenade, and Floater Grenade
- ItemsIDs that do not have corresponding XGWeapon_<type> class definitions
- These items will not apply any stats in the tactical game without these changes
- For example, eItem_BEGIN_ALIEN_GRENADES, eItem_BEGIN_GRENADES, or eItem_PlaceholderGrenade0
Any perks set by any item will be reflected in the tactical game regardless of whether any hex changes made in this section are applied or not.
This package contains five distinct hex changes:
- Alter ItemType to return the local variable m_eType instead of default.m_eType
- Rewrite ApplyOverheatIncrement to set m_eType
- Alter ConvertTInventoryToSoldierLoadout to store the item ID instead of the class (for Backpack items only)
- Alter GetItem to return the class'XGWeapon_TargetingModule' for any ItemID with an undefined class
- Alter ApplyLoadout to retrieve+spawn the class for backpack items, then immediately set the ItemID
File Changes
These hex changes are applied to the XComGame.upk
ItemType
This change to XGItem.ItemType alters the function to return the current value of m_eType instead of the default value.
original: | 04 02 E3 9B 00 00 04 3A E4 9B 00 00 53 |
new: | 04 01 E3 9B 00 00 04 3A E4 9B 00 00 53 |
Decompiled Code
XGItem.ItemType
Original Code
static simulated function XGGameData.EItemType ItemType() { return default.m_eType; //return ReturnValue; }
New Code
static simulated function XGGameData.EItemType ItemType() { return m_eType; //return ReturnValue; }
ApplyOverheatIncrement
This function completely rewrites the XGWeapon.ApplyOverheatIncrement function to allow setting the class variable m_eType, defined in the parent class XGItem.
The m_eType variable is a protected variable, so it cannot be set from outside of the XGItem class or any child class descended from XGItem.
original: | 58 B9 00 00 50 55 00 00 00 00 00 00 41 B9 00 00 00 00 00 00 00 00 00 00 43 B9 00 00 00 00 00 00 ED 00 00 00 A7 1C 00 00 C8 00 00 00 90 00 00 00 07 C5 00 1B 9A 36 00 00 00 00 00 00 2C 0B 16 0F 01 1D B9 00 00 FB 92 01 1D B9 00 00 00 42 B9 00 00 16 25 2C 64 16 07 C5 00 19 19 2E FE 2C 00 00 19 12 20 4F FE FF FF 0A 00 D8 F9 FF FF 00 1C F6 FB FF FF 16 09 00 98 F9 FF FF 00 01 98 F9 FF FF 09 00 F0 2C 00 00 00 01 F0 2C 00 00 1F 00 BD 76 00 00 00 1B F1 0E 00 00 00 00 00 00 38 3A 1B 92 30 00 00 00 00 00 00 16 01 1D B9 00 00 16 1B C2 57 00 00 00 00 00 00 00 43 B9 00 00 16 04 0B 53 |
new: | 58 B9 00 00 50 55 00 00 00 00 00 00 41 B9 00 00 00 00 00 00 00 00 00 00 43 B9 00 00 00 00 00 00 ED 00 00 00 A7 1C 00 00 98 00 00 00 90 00 00 00 0F 01 E3 9B 00 00 38 3D 00 42 B9 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 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 04 0B 53 |
Decompiled Code
XGWeapon.ApplyOverheatIncrement
Original Code
simulated function ApplyOverheatIncrement(XGUnit kUnit, int iAmount) { // End:0xc5 Loop:False if(HasProperty(11)) { iOverheatChance = Clamp(iOverheatChance + iAmount, 0, 100); // End:0xc5 Loop:False if(XComGameReplicationInfo(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kGameCore.CalcWeaponOverheated(GameplayType(), iOverheatChance)) { Overheat(kUnit); } } //return; }
New Code
simulated function ApplyOverheatIncrement(XGUnit kUnit, int iAmount) { m_eType = byte(iAmount); //return; }
ConvertTInventoryToSoldierLoadout
This hex change alters the XGLoadoutMgr.ConvertTInventoryToSoldierLoadout by storing the ItemID in the Loadout.Backpack[] array instead of the class pointer.
This preserves the ItemID until the ApplyLoadout function so that the m_eType variable of the newly spawned copy of the appropriate class can be changed to the appropriate value.
original: | 55 35 35 46 00 00 38 46 00 00 00 00 48 D7 A8 00 00 4F 00 13 58 B9 00 00 12 20 04 A7 00 00 30 00 FD A6 00 00 00 1B D1 32 00 00 00 00 00 00 1A 00 D6 A8 00 00 35 C5 0D 00 00 CA 0D 00 00 00 00 00 D8 A8 00 00 16 16 |
new: | 55 35 35 46 00 00 38 46 00 00 00 00 48 D7 A8 00 00 4F 00 1A 00 D6 A8 00 00 35 C5 0D 00 00 CA 0D 00 00 00 00 00 D8 A8 00 00 16 0B 00 D6 A8 00 00 00 D6 A8 00 00 00 D6 A8 00 00 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B |
Decompiled Code
XGLoadoutMgr.ConvertTInventoryToSoldierLoadout
Original Code
Loadout.Backpack.AddItem(class<XGWeapon>(class'XGItemLibrary'.static.GetItem(kInventory.arrSmallItems[I])));
New Code
Loadout.Backpack.AddItem(kInventory.arrSmallItems[I]);
GetItem
This hex change to XGItemLibrary.GetItem causes the function to return the class'XGWeapon_TargetingModule' if the ItemID passed is not defined.
This makes this class the prototype for any new Backpack item that does not have an existing class.
original: | 13 A7 00 00 50 55 00 00 00 00 00 00 FC A6 00 00 00 00 00 00 00 00 00 00 FE A6 00 00 00 00 00 00 0B 00 00 00 20 01 00 00 39 00 00 00 25 00 00 00 07 1A 00 99 00 FE A6 00 00 36 02 FC A6 00 00 16 04 2A 04 10 00 FE A6 00 00 02 FC A6 00 00 04 3A FD A6 00 00 53 |
new: | 13 A7 00 00 50 55 00 00 00 00 00 00 FC A6 00 00 00 00 00 00 00 00 00 00 FE A6 00 00 00 00 00 00 0B 00 00 00 20 01 00 00 35 00 00 00 25 00 00 00 04 10 45 77 10 00 FE A6 00 00 02 FC A6 00 00 2A 16 09 00 00 FE A6 00 00 02 00 2C 51 02 FC A6 00 00 0B 0B 0B 53 |
Decompiled Code
XGItemLibrary.GetItem
Original Code
static simulated function class<XGItem> GetItem(int iItem) { // End:0x1a Loop:False if(iItem >= default.m_arrItems.Length) { return none; } return default.m_arrItems[iItem]; }
New Code
static simulated function class<XGItem> GetItem(int iItem) { return default.m_arrItems[((default.m_arrItems[iItem] != none) ? iItem : 81)]; }
ApplyLoadout
This hex changes alters XGLoadoutMgr.ApplyLoadout in the following ways:
- Assumes that the Loadout array contains an ItemID for Backpack items
- Calls XGItemLibrary to retrieve the class for the given item ID
- Spawns a copy of the retrieved class
- Calls the rewritten helper function GetOverheatIncrement to set the m_eType field of the newly spawned class
Fairly drastic restructuring of this function was required in order to fit these changes into the existing space.
Note that this function is distinct from the function XGUnit.ApplyLoadout
original: | 0F 00 BA 7C 00 00 19 19 00 BE 7C 00 00 0A 00 56 94 00 00 00 1B C5 34 00 00 00 00 00 00 16 0A 00 40 AC 00 00 00 1B 95 33 00 00 00 00 00 00 16 07 F2 01 19 19 19 2E 64 2D 00 00 19 12 20 4F FE FF FF 0A 00 D8 F9 FF FF 00 1C F6 FB FF FF 16 09 00 98 F9 FF FF 00 01 98 F9 FF FF 09 00 71 2D 00 00 00 01 71 2D 00 00 09 00 A3 9C 00 00 00 01 A3 9C 00 00 0A 00 A8 9F 00 00 00 2D 01 A8 9F 00 00 07 F2 01 82 81 19 01 E6 7B 00 00 0A 00 B5 32 00 00 00 1B DB 3D 00 00 00 00 00 00 16 16 18 21 00 19 1B 38 34 00 00 00 00 00 00 16 0A 00 B5 32 00 00 00 1B DB 3D 00 00 00 00 00 00 16 16 07 F2 01 82 82 2D 00 BD 7C 00 00 18 5F 00 77 19 2E 64 2D 00 00 2E FE 2C 00 00 19 12 20 4F FE FF FF 0A 00 D8 F9 FF FF 00 1C F6 FB FF FF 16 09 00 98 F9 FF FF 00 01 98 F9 FF FF 09 00 69 2D 00 00 00 01 69 2D 00 00 2A 16 16 18 74 00 81 19 19 2E 64 2D 00 00 2E FE 2C 00 00 19 12 20 4F FE FF FF 0A 00 D8 F9 FF FF 00 1C F6 FB FF FF 16 09 00 98 F9 FF FF 00 01 98 F9 FF FF 09 00 69 2D 00 00 00 01 69 2D 00 00 0A 00 97 4C 00 00 00 2D 01 97 4C 00 00 16 16 04 25 07 08 02 99 00 BA 7C 00 00 2C 04 16 04 1D FF FF FF FF 0F 00 B9 7C 00 00 93 F9 2C 04 19 19 00 BE 7C 00 00 0A 00 56 94 00 00 00 1B C5 34 00 00 00 00 00 00 16 0A 00 87 AC 00 00 00 1B AD 33 00 00 00 00 00 00 16 16 00 BA 7C 00 00 16 07 39 03 82 82 19 01 E6 7B 00 00 0A 00 B5 32 00 00 00 1B DB 3D 00 00 00 00 00 00 16 18 23 00 81 19 1B 38 34 00 00 00 00 00 00 16 0A 00 B5 32 00 00 00 1B DB 3D 00 00 00 00 00 00 16 16 16 18 0D 00 97 00 BF 7C 00 00 25 16 16 0F 00 BB 7C 00 00 91 00 BF 7C 00 00 2C 05 16 07 1E 03 99 00 BF 7C 00 00 2C 32 16 A1 00 BB 7C 00 00 F9 2C 1E 90 19 19 01 E6 7B 00 00 0A 00 EB B2 00 00 00 1B 0A 34 00 00 00 00 00 00 16 09 00 DB 93 00 00 00 01 DB 93 00 00 2C 0F 16 16 16 A1 00 BB 7C 00 00 90 00 B9 7C 00 00 2C 0F 16 16 06 18 04 07 18 04 82 81 19 01 E6 7B 00 00 0A 00 B5 32 00 00 00 1B DB 3D 00 00 00 00 00 00 16 16 18 21 00 19 1B 38 34 00 00 00 00 00 00 16 0A 00 B5 32 00 00 00 1B DB 3D 00 00 00 00 00 00 16 16 0F 00 BB 7C 00 00 90 8F 19 19 1B 38 34 00 00 00 00 00 00 16 0A 00 EB B2 00 00 00 1B 0A 34 00 00 00 00 00 00 16 09 00 DC 93 00 00 00 01 DC 93 00 00 16 2C 0A 16 07 FD 03 82 9A 00 BA 7C 00 00 26 16 18 0B 00 2D 00 BD 7C 00 00 16 0F 00 BB 7C 00 00 8F 00 BF 7C 00 00 16 06 18 04 A1 00 BB 7C 00 00 90 00 B9 7C 00 00 1D E7 FF FF FF 16 16 04 FB 92 00 BF 7C 00 00 00 BB 7C 00 00 16 25 2C 64 16 04 3A BC 7C 00 00 53 |
new: | 0F 00 BB 7C 00 00 25 07 31 00 19 01 E8 BB 00 00 0C 00 4F B9 00 00 00 1B 9A 36 00 00 00 00 00 00 2C 0A 16 04 25 07 55 00 19 01 E8 BB 00 00 0A 00 4D B9 00 00 00 1B D6 3D 00 00 00 00 00 00 16 04 25 07 87 01 81 2D 00 BD 7C 00 00 16 07 94 00 19 01 E8 BB 00 00 0C 00 4F B9 00 00 00 1B 9A 36 00 00 00 00 00 00 2C 08 16 0F 00 BB 7C 00 00 2C 19 07 C4 00 19 01 E8 BB 00 00 0C 00 4F B9 00 00 00 1B 9A 36 00 00 00 00 00 00 2C 04 16 0F 00 BB 7C 00 00 2C 19 07 F4 00 19 01 E8 BB 00 00 0C 00 4F B9 00 00 00 1B 9A 36 00 00 00 00 00 00 2C 02 16 0F 00 BB 7C 00 00 2C 32 07 24 01 19 01 E8 BB 00 00 0C 00 4F B9 00 00 00 1B 9A 36 00 00 00 00 00 00 2C 05 16 0F 00 BB 7C 00 00 2C 22 07 54 01 19 01 E8 BB 00 00 0C 00 4F B9 00 00 00 1B 9A 36 00 00 00 00 00 00 2C 06 16 0F 00 BB 7C 00 00 2C 22 07 84 01 19 01 E8 BB 00 00 0C 00 4F B9 00 00 00 1B 9A 36 00 00 00 00 00 00 2C 07 16 0F 00 BB 7C 00 00 2C 22 06 A7 02 07 B7 01 19 01 E8 BB 00 00 0C 00 4F B9 00 00 00 1B 9A 36 00 00 00 00 00 00 2C 08 16 0F 00 BB 7C 00 00 2C 11 07 E7 01 19 01 E8 BB 00 00 0C 00 4F B9 00 00 00 1B 9A 36 00 00 00 00 00 00 2C 04 16 0F 00 BB 7C 00 00 2C 11 07 17 02 19 01 E8 BB 00 00 0C 00 4F B9 00 00 00 1B 9A 36 00 00 00 00 00 00 2C 02 16 0F 00 BB 7C 00 00 2C 22 07 47 02 19 01 E8 BB 00 00 0C 00 4F B9 00 00 00 1B 9A 36 00 00 00 00 00 00 2C 05 16 0F 00 BB 7C 00 00 2C 14 07 77 02 19 01 E8 BB 00 00 0C 00 4F B9 00 00 00 1B 9A 36 00 00 00 00 00 00 2C 06 16 0F 00 BB 7C 00 00 2C 14 07 A7 02 19 01 E8 BB 00 00 0C 00 4F B9 00 00 00 1B 9A 36 00 00 00 00 00 00 2C 07 16 0F 00 BB 7C 00 00 2C 14 07 CF 02 9A 1B 1E 35 00 00 00 00 00 00 16 2C 11 16 0F 00 BB 7C 00 00 90 2C 02 00 BB 7C 00 00 16 07 F7 02 9A 1B 1E 35 00 00 00 00 00 00 16 2C 0C 16 0F 00 BB 7C 00 00 90 2C 01 00 BB 7C 00 00 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 04 00 BB 7C 00 00 53 |
Decompiled Code
XGLoadoutMgr.ApplyLoadout
Original Code
static function ApplyLoadout(XGUnit kUnit, TLoadout kLoad, bool bLoadFromCheckpoint) { local XGInventoryItem kItem; local XGArmor kArmor; local XGLoadoutInstances kLoadoutInstances; local int I, J; kLoadoutInstances = class'Engine'.static.GetCurrentWorldInfo().Spawn(class'XGLoadoutInstances', kUnit.Owner); // End:0x173 Loop:False if(kLoad.Armor != none) { kArmor = class'Engine'.static.GetCurrentWorldInfo().Spawn(kLoad.Armor, kUnit.Owner); kArmor.Init(); kArmor.PostInit(); kLoadoutInstances.m_kArmor = kArmor; } kLoadoutInstances.m_iNumItems = 0; kLoadoutInstances.m_iNumBackpackItems = 0; I = 0; J0x1be: // End:0x47f Loop:True if(I < 21) { // End:0x34b Loop:False if(I == 14) { J = 0; J0x1e9: // End:0x348 Loop:True if(J < kLoad.Backpack.Length) { // End:0x33a Loop:False if(kLoad.Backpack[J] != none) { kItem = class'Engine'.static.GetCurrentWorldInfo().Spawn(kLoad.Backpack[J], kUnit.Owner); kItem.Init(); kLoadoutInstances.m_aBackpackItems[J] = kItem; ++ kLoadoutInstances.m_iNumBackpackItems; } ++ J; // This is an implied JumpToken; Continue! goto J0x1e9; } } // End:0x471 else { // End:0x471 Loop:False if(kLoad.Items[I] != none) { kItem = class'Engine'.static.GetCurrentWorldInfo().Spawn(kLoad.Items[I], kUnit.Owner); kItem.Init(); kLoadoutInstances.m_aItems[I] = kItem; ++ kLoadoutInstances.m_iNumItems; } } ++ I; // This is an implied JumpToken; Continue! goto J0x1be; } kUnit.ApplyLoadout(kLoadoutInstances, bLoadFromCheckpoint); }
New Code
static function ApplyLoadout(XGUnit kUnit, TLoadout kLoad, bool bLoadFromCheckpoint) { local XGInventoryItem kItem; local XGArmor kArmor; local XGLoadoutInstances kLoadoutInstances; local int I, J; kLoadoutInstances = class'Engine'.static.GetCurrentWorldInfo().Spawn(class'XGLoadoutInstances', kUnit.Owner); kArmor = class'Engine'.static.GetCurrentWorldInfo().Spawn(kLoad.Armor, kUnit.Owner); kArmor.Init(); kArmor.PostInit(); kLoadoutInstances.m_kArmor = kArmor; kLoadoutInstances.m_iNumItems = 0; kLoadoutInstances.m_iNumBackpackItems = 0; I = 0; J0x19C: // End:0x473 [Loop If] if(I < 21) { // End:0x33F if(I < kLoad.Backpack.Length) { kItem = class'Engine'.static.GetCurrentWorldInfo().Spawn(class<XGWeapon>(class'XGItemLibrary'.static.GetItem(kLoad.Backpack[I])), kUnit.Owner); kItem.ApplyOverheatIncrement(none, kLoad.Backpack[I]); kItem.Init(); kLoadoutInstances.m_aBackpackItems[I] = kItem; ++ kLoadoutInstances.m_iNumBackpackItems; } // End:0x465 if(kLoad.Items[I] != none) { kItem = class'Engine'.static.GetCurrentWorldInfo().Spawn(kLoad.Items[I], kUnit.Owner); kItem.Init(); kLoadoutInstances.m_aItems[I] = kItem; ++ kLoadoutInstances.m_iNumItems; } ++ I; // [Loop Continue] goto J0x19C; } kUnit.ApplyLoadout(kLoadoutInstances, bLoadFromCheckpoint); //return; }
References
Referred to by this article:
That refer to this article:
- <none>