Jump to content

Photo

Modding Armor to add Grappler property - issues

mod armor properties grapple

  • Please log in to reply
23 replies to this topic

#1
JDDysart

JDDysart

    Regular

  • Members
  • PipPip
  • 57 posts

Running / playing XCom-EU vanilla (more-or-less, NO long-war & NOT playing EW; do have Slingshot-DLC & a few other mods added).

 

Installed Steam outside of "\Program Files (x86)\". Used PatcherGUI to disable Hash Checks. Have changed .exe to permit the .ini files to load.

 

On ArmorTitan and ArmorPsi, attempted adding/changing Property[2]=eAP_Grapple - no change(s) in tactical game.

Then changed ABILITIES[0]=eAbility_Grapple - causing Grapple control to appear after all SmallItem controls and before Psi-Ability controls.

(I did notice that for Skeleton and Ghost Armors the Grapple control appears just before any SmallItem controls; and neither needed an eAbility to make Grapple work.)

 

Regardless of whether or not I left in the eAP_Grapple property - attempting a "Grapple" causes the Soldier to fire weapon then do Grapple action - ending next to (and down from) grapple target location.

 

When at a crash site - if target is open terrain then Soldier can walk away; All-Other / else - said Soldier will be stuck with moving between Grapple target locations for the duration of the mission.

 

Interestingly enough, if said soldier is carrying an arcthrower, s/he can still stun in-range aliens.

 

 

Okay, if anyone with the appropriate knowledge is still watching this board, what did I overlook? do incorrectly? or otherwise fail to do what was needed to get the Grapple function to work properly?



#2
dubiousintent

dubiousintent

    Resident poster

  • Premium Member
  • 7,875 posts

It's been a number of years now and my memory is increasingly unreliable, but as I recall we found that certain items like the grapple were restricted to particular armors in the "native functions" (aka "black boxes of code" which we could not examine).  You might search in the "Mod Talk" sub-forum on "R&D Grapple" to see if you can find where those investigations led.

 

Not everything can be used by everyone.  That was an original design decision "for balance".  Some things are restricted by "class"/perk, some by armor, some by item.  (Items come in "small" and "large" sizes, which limit how many of each can be carried and by whom.)  Which is why Long War grew to be such a monster mod: they had to develop complete replacements for functions to get around the built-in limitations.  The changes you can make by way of the DGC.INI file are quite limited in EU, and only just less so in EW.

 

One thing to watch out for is that you fill in Properties and Abilities from [0], [1], and up.  Don't leave any "empty" ones when adding to the list.  Any empty Property/Ability stops the game processing of that list.

 

-Dubious-


Edited by dubiousintent, 03 October 2016 - 10:11 PM.


#3
JDDysart

JDDysart

    Regular

  • Members
  • PipPip
  • 57 posts

 

One thing to watch out for is that you fill in Properties and Abilities from [0], [1], and up. Don't leave any "empty" ones when adding to the list. Any empty Property/Ability stops the game processing of that list.

 

-Dubious-

 

Very Interesting ...

Did you know: there are just such gaps in the original definitions - especially amongst the human weapons definitions; where the game appears to read past these "empty" gaps just fine.

 

I did notice that the last iteration in such a list rarely (if ever) is processed; but otherwise does seem to read past eAbility_NONE and e?P_None just fine.

 

Anyway, for ArmorTitan I have DualWield, PoisonImmunity, and Grapple; for ArmorPsi I have Psi, PoisonImmunity and Grapple. (along with all the appropriate nomenclature in the proper locations.)

 

I've not had any luck with getting LargeItems to expand for additional Primary/Pistol weapons; but SmallItems seems to work just fine (within the confines of what the Graphical forms will display).

 

One possibility that I haven't yet tested for is if the game cares whether active vs passive properties are given in any particular order?

And I haven't tried starting a new game ... just to see if (some?) of these have to be in the ini file from the beginning of a new game; to function properly.

 

I did run across one Mod Example of adding Grapple to ArmorKevlar, just by using the "Properties[0]=eAP_Grapple" - I believe it was in the download documentation on "ResourceHacker".

But this didn't work, for me, either.

 

 

EDIT:

Searching "Mod Talk" sub-forum on "R&D Grapple" produced the function that enables eAP_Grapple for ArmorSkeleton & ArmorGhost

 

The relevant portion of the conditional is:

((kTransfer.kChar.kInventory.iArmor == 59 || kTransfer.kChar.kInventory.iArmor == 62)

 

I believe that if the above could be replaced with a test for the eAP_Grapple property, that one could then use the DGC.ini to properly add Grapple to any Armor.

 

I am now seeking the proper replacement conditional - checking for the presence of the  eAP_Grapple property?


Edited by JDDysart, 04 October 2016 - 03:28 PM.


#4
dubiousintent

dubiousintent

    Resident poster

  • Premium Member
  • 7,875 posts

Just to clarify a couple of points you raised:

 

"eAbility_NONE" and "eAP_NONE" are not "empty" values.  They are specific variables the game engine knows how to process; basically meaning "do nothing with this".  "Empty" values would be "Properties[4]=".  To the best of my recollection, no one figured out what, if any, significance there was to each specific "slot" (i.e. Properties[1] vs Properties[2]).

 

Anything related to "ResourceHacker" or the "ResourceCache" were very early days discoveries.  They predated discovering how to get the game to use the "loose" DGC.INI file instead of the "built-in/hard coded" version of it called the "ResourceCache".  "Enable INI Loading" in effect bypasses the "ResourceCache" and the need for ResourceHacker.

 

As for the conditional code you are looking for, try looking at the wiki articles "Hex values XCOM Modding" and "Enum Expansion".

 

-Dubious-



#5
JDDysart

JDDysart

    Regular

  • Members
  • PipPip
  • 57 posts

My attempt to enable the eAP_Grapple property, for use in the DGC.ini:

 

UPK_FILE=XComGame.upk

 

OBJECT=XGBattleDesc.BuildSoldierContent:KEEP

[BEFORE_HEX]

// ((kTransfer.kChar.kInventory.iArmor == 59) ||

82 84 9A 35 C9 0D 00 00 CA 0D 00 00 00 00 35 D2 0D 00 00 D5 0D 00 00 00 00 35 E2 44 00 00 E3 44

00 00 00 00 00 87 A0 00 00 2C 3B 16

 

// kTransfer.kChar.kInventory.iArmor == 62) &&

18 47 00 9A 35 C9 0D 00 00 CA 0D 00 00 00 00 35 D2 0D 00 00 D5 0D 00 00 00 00 35 E2 44 00 00 E3

44 00 00 00 00 00 87 A0 00 00 2C 3E 16 16

[/BEFORE_HEX]

 

 

[AFTER_HEX]

// XComGameReplicationInfo(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kGameCore.ArmorHasProperty(kInventory.iArmor, 2) &&

82 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 28 00 D8 77 00 00 00 1B 36 04 00 00

00 00 00 00 35 C9 0D 00 00 CA 0D 00 00 00 00 00 E9 A8 00 00 2C 02 16

[/AFTER_HEX]

 

 

 

As this will be my first attempt (with XCom-EU), anyone care to tell me what I may have forgotten? or otherwise gotten wrong?

 

Would eventually like to get this into a file that PatcherGUI could use to apply this mod?

As that will probably be the best way to recover? Should I have made a major oops?


Edited by JDDysart, 05 October 2016 - 07:45 PM.


#6
dubiousintent

dubiousintent

    Resident poster

  • Premium Member
  • 7,875 posts

If you folllow the PatchUPK Mod example template (it's in it's own folder when you unpack the archive), PatcherGUI will have no trouble reading it.  They are essentially the same tool.

 

You are attempting to isolate two different conditions in the [BEFORE_HEX], and replacing them both with a single line of code in the [AFTER_HEX].  Pretty sure (only "pretty sure" because I haven't actually written any myself) that won't work for two reasons. 

 

1) I doubt your two [before] conditions are contiguously adjacent (if only because you are identifying only the left portion of two compound conditionals).  The [before]/[after] syntax is a direct replacement of the [before] code by the [after] code.  Even if you are not changing any of the code between the two identified sections, it has to be included in the [after] replacement or it will be dropped/deleted.

 

The tool is essentially automating what you would have to do manually with a hex-editor: locate the exact matching code, then using the beginning of that matching code as the starting point, replace everything that follows byte by byte with the "[after]" code for the length of that replacement string.

 

Stick with a simple one section of code [before], followed by a simple replacement of that same code in the [after] section. You can have successive pairs of "[before]" and "[after]" sections.  There a number of examples in the wiki of such mods in PatchUPK format.

 

2) Replacement code needs to be the same length (in bytes, which means you have to determine the actual OP code used) as the code it is replacing, or you have to use the "pseudo-code" capabilities of PatcherUPK so it can calculate the code length adjustments for you.  (You can calculate this yourself, but it's messy and a pain and everyone prefers to let the "pseudo-code" tool do so.)  This is the simplest form.  Of course you can replace sections of code with "00 00" or delete large chunks in order to put completely new code there, but at the end of the day, you have to either keep the length of code the same or calculate the new length of the code and update the header with that information.

 

Additionally, one condition in your current [BEFORE_HEX] section is a logical "OR" (||) with the unspecified right portion, while the second condition is a logical "AND" (&&).  Switching from an "OR" condition to an "AND" condition usually requires you to reverse your resulting "if/else" logic.

 

I suggest you try a much simpler edit to test that you have the syntax of the PatchUPK format down first.

 

-Dubious-

[Edit: expanded for clarification.]


Edited by dubiousintent, 06 October 2016 - 12:31 AM.


#7
JDDysart

JDDysart

    Regular

  • Members
  • PipPip
  • 57 posts

Thanks for you, Dubious, for your kind words.

 

On the one hand, it is not quite as complicated as it looks as I am merely attempting to replace a three condition IF with a two condition IF.

The current structure is IF(((condition 1) || condition2) && condition3) { <turn on grapple> }; replacing with IF(condition-A && condition3) ...

 

On the other hand, I feel just about snowed under with trying to understand PatcherUPK's "pseudo-code" reference labels.

That is how do I break down something like <class'Engine'.static.GetCurrentWorldInfo().GRI> so that PatcherUPK can correctly translate it?

 

The Actual replacement is (if possible) even worse:

<XComGameReplicationInfo(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kGameCore.ArmorHasProperty(kInventory.iArmor, 2)>

 

Currently even the original conditions are beyond me; such as:

<kTransfer.kChar.kInventory.iArmor>

 

Background - current issue - sizing problems (of the modest small amount of code I am attempting to mod):

Memory Size = 145 (before) - 134 (after) ==> 11 byte difference?

File Size = 89 (before) - 86 (after) ==> 3 byte difference?

 

My current thought is I need to get the variable references into "pseudo-code" for PatcherUPK to properly recalculate (and reset) sizes?

Skips and Jumps I could manually recalculate; but I read somewhere that the game tracks both the Memory and File sizes, too?

But what I was reading was none too clear on how to go about modding said Memory and File sizes? as in where are they stored? How do I see them in the UEE?



#8
dubiousintent

dubiousintent

    Resident poster

  • Premium Member
  • 7,875 posts

Sorry, I can't help you with specific code as I never got into it.  You might see if any of the source code material on GitHub sheds any additional light on the subject.  You might also do a search on posts in this forum by "wghost81".  She wrote the UPKUtils and the pseudo-code compiler.  Undoubtedly she got asked similar questions about it.  She is still active on Nexus, so a PM is likely to get a response.  (She is incredibly helpful.)

 

From what I do understand, the byte size of the compound comparison operators is different (larger) than the more "normal" operators like ">".  You may be able to pad out your truncated replacement memory size with nulls (00 00) or "NOP"s (x0B) from the "Hex Values" article.

 

As for the File and Memory sizes, they go into the UPK header.  See the UPK Format Description file (it's a PDF IIRC) on the UPKUtils download page.  I'm not sure if you can see them in UUE, but recall that it has different "views" you may need to switch between.

 

PS: If you do learn anything that will make something clearer to others, let me know and I'll add it to the appropriate wiki article.

 

-Dubious-


Edited by dubiousintent, 06 October 2016 - 08:56 PM.


#9
JDDysart

JDDysart

    Regular

  • Members
  • PipPip
  • 57 posts

The going is soo sllooowwww ...

But I think I can ... I think I can ... Not Yet!

 

Currently attempting to translate (into Pseudo Code):

XComGameReplicationInfo(class'Engine'.static.GetCurrentWorldInfo().GRI)

 

Current Results:
 

[Pseudo-Code]

2E <Class.XComGameReplicationInfo>

19 12 20 <Engine.Engine> [@] <Engine.Engine.GetCurrentWorldInfo.ReturnValue> 00 ( 1C <Engine.Engine.GetCurrentWorldInfo> 16 )

[Hex-Code]

09 00 98 F9 FF FF 00 01 98 F9 FF FF

[/Hex-Code]

 

I still have that last little bit of hex code (that I am currently stubbing my toe on).

Some how "01 <GRI>" must produce "01 98 F9 FF FF", but so far I have not found the proper qualifiers to do this!

 

Lesson Learned:

While the UEE decompiler can (sometimes) translate 4 bytes of code into a single 'sublet' (such as GetCurrentWorldInfo), the PatchUPK tools usually require 2 or more 'sublets' (such as <Engine.Engine>) to kick out the correct 4 bytes of code; a single 'sublet' of pseudo code appears to come back as a local reference to a  inline (4-Byte) variable.

 

I did notice at the bottom of one of the PatchUPK readme files a ine about writing a compiler? Is this still coming? Has another option been found? or did such projects get put clear off the stove due to newer more intriguing challenges?

 

Please HELP: Anyone passing by here know what qualification is needed to get PatchUPK's pseudo code <GRI> to produce the hex '98 F9 FF FF' variable?/index?/object?-reference? ??

 

 

EDIT:

 

Oh! The embarrassment!! How red can my face get?! :wink:

wghost81 had almost exactly the code (that I've spent most of a week reconstructing) posted in the UPKTools thread (spoiler tagged - on something like page 15 of 39).

 

With the stated assist from wghost81 - I should be able to 'take off and run with' said info, to (hopefully) complete my modest little mod.


Edited by JDDysart, 07 October 2016 - 05:35 AM.


#10
JDDysart

JDDysart

    Regular

  • Members
  • PipPip
  • 57 posts

Attention: -Dubious-

 

Something that IMO is worth passing on. (for whatever worth  it may to others?)

Not sure just where it should be put, but here this 'SnipIt' is:

  • Function Token: 53 or 0x35
  • Name: StructMember
  • Expression: .
  • Hex data format: 35 <ObjRef(Member)> <ObjRef(Struct)> <Byte> <Byte> <Expr>
  • UPKTools Pseudo-Code: 35 <ClassName[.parentn[.etc]].parent0.child> <ClassName[.parentn[.etc]].parent0> 00 00 <Expr: NextMember or VarRef>

Notes: 

  • While my examples will produce the specified result, said result (may or) may NOT work in the game! ... yes, emphasis is where I want it.
  • Examples are context sensitive: that is ClassName, parent-refs and child-ref may vary between contexts.
  • Virtual Functions might be used in more complex structures - where there is a ReturnValue-ref specified; else I'm not sure how they work.
  • For those that might not already know this: (in UEE) ClassNames are the first level objects of a UPK-file.
  • "Class." translates as UPK-filename: for XComGame.upk - "Class." works in place of "XComGame." (where "XComGame." will cause UPKTools to throw an error).
    • usually only needed when referencing a ClassName (itself) - <Class.ClassName>; <ClassName.child> tends to work just fine.
  • XComGame.XComGameClassNames may be used outside of XComGame.upk, etc? as UPKTools throws an error if you try to use "XComGame." inside of XComGame.upk, etc.

 

Simple Example:

single Member and the VarRef

Given: TransferInfo.iArmor

 

UPKTools Pseudo-Code:

35 <XGTacticalGameCoreNativeBase.TInventory.iArmor> <XGTacticalGameCoreNativeBase.TInventory> 00 00 00 <.TransferInfo>

 

Complex Example:

three Members and the VarRef

Given: TransferInfo.kChar.kInventory.iArmor

 

UPKTools Pseudo-Code:

35 <XGTacticalGameCoreNativeBase.TInventory.iArmor> <XGTacticalGameCoreNativeBase.TInventory> 00 00

35 <XGTacticalGameCoreNativeBase.TCharacter.kInventory> <XGTacticalGameCoreNativeBase.TCharacter> 00 00

35 <XComContentManager.TTransferSoldier.kChar> <XComContentManager.TTransferSoldier> 00 00

00 <.TransferInfo>

 

Virtual Function Complex Example:

VirtualFunction(Arg0:three Members and the VarRef, Arg1:<%b 2>)

Given: ArmorHasProperty(TransferInfo.kChar.kInventory.iArmor, 2)

 

UPKTools Pseudo-Code:

1B <ArmorHasProperty>

35 <XGTacticalGameCoreNativeBase.TInventory.iArmor> <XGTacticalGameCoreNativeBase.TInventory> 00 00

35 <XGTacticalGameCoreNativeBase.TCharacter.kInventory> <XGTacticalGameCoreNativeBase.TCharacter> 00 00

35 <XComContentManager.TTransferSoldier.kChar> <XComContentManager.TTransferSoldier> 00 00

00 <.TransferInfo>

2C 02 16

 

Final Function Complex Example:

FinalFunction(Arg0:three Members and the VarRef, Arg1:2)

Given: ArmorHasProperty(TransferInfo.kChar.kInventory.iArmor, 2)

 

UPKTools Pseudo-Code:

1C <XGTacticalGameCore.ArmorHasProperty>

35 <XGTacticalGameCoreNativeBase.Tinventory.iArmor> <XGTacticalGameCoreNativeBase.TInventory> 00 00

35 <XGTacticalGameCoreNativeBase.TCharacter.kInventory> <XGTacticalGameCoreNativeBase.TCharacter> 00 00

35 <XComContentManager.TTransferSoldier.kChar> <XComContentManager.TTransferSoldier> 00 00

00 <.TransferInfo>

<%b 2> 16

 

The two function examples have a couple of easy to miss differences:

  • where I placed the <%b 2> is used to demonstrate that <%b 2> is the same as the hex-code: 2C 02
  • And Token 1B doesn't want the "XGTacticalGameCore." that Token 1C has to have, for UPKTools Pseudo-Code purposes.

 

Edit:

 

WARNING: If you are allowing UPKTools to calculate a script's MemSize using the Before-n-After method with a difference in sizes THEN you need to know that UPKTools doesn't do so good on pure Hex Code.

Caution: with different before-n-after sizes - it is just as IMPORTANT to have what is being replaced in Pseudo-Code as it is to have your modded info in Pseudo-Code! Else calculate and set the Sizes yourself!

 

The Good News: UPKTools does wonderful on resizing calculations - when both the before and after code are in Pseudo-Code.

Untouched hex-code (that contains  only relative-offsets) may be sandwiched in with your Pseudo-Code, as long as you include it in both the before and after sections.

Any absolute offsets, after your modded code and still within the modded script (such as the address included on a IF or IF-NOT token), will need to be modded TOO!

And remember, any control transfers into the area of your modded code, will also need your attention.


Edited by JDDysart, 09 October 2016 - 02:04 AM.





Page loaded in: 0.944 seconds