Jump to content

R&D - New Modding Tools


Amineri

Recommended Posts

Good work, Amineri!

 

I vote for second variant: to make it a separate modding tool. Not because I don't like tweaking, but because tweaking is not always simple and inexperienced user can break the game with inaccurate changes. I think, for most users it will be sufficient (and much easier) to allow tweaking of constant values via ToolBoks custom mod feature in it's present form (offset-value).

 

The input code to this tool could be considered as source code and released for modders to learn scripting and use in their own projects.

 

BTW, about turning variables into arrays: it may not be possible. First, arrays have a longer object file with additional info about element type (object reference). Second: there seems to be two entries in objectlist table for each array. One looks like array (with additional info) and the other like variable.

Link to comment
Share on other sites

  • Replies 211
  • Created
  • Last Reply

Top Posters In This Topic

I've been called for help, although I'm not a fan of re-doing what's already done. Not sure what exactly is needing my help but nonetheless I noticed and agree that my library lacks documentation. So I have started abit of documentation on its API, you can read about it on github

UPK format description would be MOST appreciated. At least for me. :smile: Discovering it myself certainly adds to my education, but since I know it's already done I don't have that much fun. :sad:
Link to comment
Share on other sites

I've been called for help, although I'm not a fan of re-doing what's already done. Not sure what exactly is needing my help but nonetheless I noticed and agree that my library lacks documentation. So I have started abit of documentation on its API, you can read about it on github

Is there any chance that you could consider to add any of the below features to UE Explorer?

  • A right-click option on functions: "View All Tokens"
    • Would in chronological order, very similar to "View Tokens", list same information as is if user had hovered the mouse over all bytes, one by one, in the buffer view window.
    • Would ideally output like this:
      • (Virtual memory size / Storage size / Storage Location of first byte) [hex bytes]​​​​
      • Object code (the popup information you receive when you hold mouse still on given bytes in view buffer)

This alone would be an incredible step forward in mod-user-friendliness in all areas.

It would immensely decrease the learning curve for new modders.

It would be a huge time-saver for experienced modders (allowing them to skip a lot of the manual steps done today).

It would also most likely allow all users to occasionally (more or less by accident) pick up on small details, previously not noticed.

  • Expanded batch export options for View Buffer, View Object Code, View Tokens (and View All Tokens (if implemeted)) on functional level.

This would make assessing and repairing modded code after patch possible on a completely new level without modders inventing a new mark-up-language and advanced tools. Focus would be more on how to use UE Explorer rather than how to re-invent parts of it.

 

As we are also getting closer to towards Christmas I have already planned to make a donation as a token of appreciation for the UE Explorer tool.

While it would in no way be a fair monetary compensation for the time it would take to implement, even the tiniest change, the donation would be bigger and hold some more symbolic meaning if you were to consider the above ideas :smile:

Edited by Bertilsson
Link to comment
Share on other sites

 

BTW, about turning variables into arrays: it may not be possible. First, arrays have a longer object file with additional info about element type (object reference). Second: there seems to be two entries in objectlist table for each array. One looks like array (with additional info) and the other like variable.

 

It looks like dynamic arrays are set up this way. The variable itself has a special type indicating "dynamic array" and has a slightly larger referenced object containing a link to a second object which contains the type.

 

However static arrays appear to be much simpler -- simply changing the 5th word of the variable object (the referenced object, not the objectlist entry) will alter the static array size.

 

There does appear to be a bit of complexity I don't yet understand to variable hex. It appears to vary slightly in size in ways I don't understand.

In XGUnit:

  • int m_aPanicModifier[ECharacterStat] = size 0x28
  • privatewrite XComInteractPoint m_arrInteractPoints[6] = size 0x2C
  • ForceFeedbackWaveform m_arrPanicFF[2] = size 0x2C
  • XGVolume m_aVolumes[16] = size 0x2E
  • int m_iBWAimPenalty = size 0x2A
  • int m_iWillCheatBonus = size 0x28

 

 

Looking in more detail at:

int m_aPanicModifier[ECharacterStat]

the object bytecode is:

55 AF 00 00 50 55 00 00 00 00 00 00 40 AF 00 00 
13 00 00 00 00 00 00 00 00 00 00 00 50 55 00 00 
00 00 00 00 E1 0A 00 00

Word 4 is 0x13 = 19, which is the size of the static array.

The objectlist entry for this variable is:

95 FE FF FF 00 00 00 00 44 B8 00 00 00 45 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 04 00 07 00 
28 00 00 00 3E ED 8D 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00

The initial 0xFFFFFE95 is what defines the type of the array as int.

 

--------

 

In comparison a "simple" integer variable:

int m_iBWAimPenalty

has object bytecode of:

4E AF 00 00 50 55 00 00 00 00 00 00 39 AF 00 00 
01 00 00 00 20 00 00 00 00 00 00 00 50 55 00 00 
00 00 00 00 00 00 00 00 2F 00

which is the same size as for the static array. Word 4 here is 1. I've tested changing this and alters the variable into a static array.

 

The objectlist entry for this is :

95 FE FF FF 00 00 00 00 44 B8 00 00 10 4B 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 04 00 07 00 
2A 00 00 00 18 EC 8D 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00

In one piece of code I've written I was able to change a function parameter from a static array into a basic int, although I passed a 'none' token and didn't use the parameter so it's not really a complete test.

Link to comment
Share on other sites

Seems, UE Exlorer has a problems with decompiling code like this one:

if((iItem > 31) && iItem < 57)                       
{                                                    
	goto label
}                                                    
                                                     
if(kAlien.IsExalt())                                 
{                                                    
	if((iItem < 211) || iItem > 219)             
	{                                            
		goto label
	}	                                     
}                                                    
                                                     
eItem = byte(iItem)                                  
kDesc.m_kDropShipCargoInfo.m_arrArtifacts[eItem] += 1

// label
It returns

if((iItem > 31) && iItem < 57)                                
{                                                             
}                                                             
else                                                          
{                                                             
    if(kAlien.IsExalt())                                      
    {                                                         
        if((iItem < 211) || iItem > 219)                      
        {                                                     
        }                                                     
        else                                                  
        {                                                     
        }                                                     
        eItem = byte(iItem);                                  
        kDesc.m_kDropShipCargoInfo.m_arrArtifacts[eItem] += 1;
    }                                                         
}                                                             
Would it be possible to add all goto lines and labels for all jumps to decompiled code? Edited by wghost81
Link to comment
Share on other sites

I think the reason UE Explorer doesn't decompile it is that there is no valid unrealscript that would generate the bytecodes that you show. I don't think unrealscript actually allows goto statements.

 

When writing hex code its definitely possible to create "assembly spaghetti code" that UE Explorer just isn't going to be able to decompile.

 

I think that instead of :

if((iItem > 31) && iItem < 57)                       
{                                                    
	goto label
}                                                    
                                                     
if(kAlien.IsExalt())                                 
{                                                    
	if((iItem < 211) || iItem > 219)             
	{                                            
		goto label
	}	                                     
}                                                    
                                                     
eItem = byte(iItem)                                  
kDesc.m_kDropShipCargoInfo.m_arrArtifacts[eItem] += 1

// label

it would be cleaner to write it as:

if(!(((iItem > 31) && iItem < 57)) || (kAlien.IsExalt() && (iItem < 211 || iItem > 219))))                  
{                                                    
   eItem = byte(iItem)                                  
   kDesc.m_kDropShipCargoInfo.m_arrArtifacts[eItem] += 1
}

Of course that begs the question of whether non-Exalt units can ever drop items with IDs in the range from 211 to 219. If not then the kAlien.IsExalt() condition could be removed.

Link to comment
Share on other sites

My next step in this fun fun process has been building automation to detect and mark references automatically.

 

I built a simplified language parser using the UE Explorer NTL table file and now have a class that can parse hex code and identify where the references are. It will skip any 00 00 00 00 null references as well as any negative values (which I think are export table references).

 

Sample input code:

 

 

// sample comment

/*more
sample
comments*/

UPKFILE=XComGame.upk
FUNCTION=AddStatModifiers.XGUnit

[BEFORE_HEX]// hex from EU patch 4
//final 2 words of header (function memory/file size)
// [HEADER]
// A6 02 00 00 DE 01 00 00 
// [/HEADER]

// body
//kAbility = none
49 02 00 2A 15 

//iStat = 0
0F 00 39 B7 00 00 25 // example of reference-naming

//if(iStat < 19)
07 56 00 96 00 39 B7 00 00 2C 13 16 // example of reference-marking 

	//m_aCurrentStats[iStat] += aStatModifiers[iStat]
	A1 1A 00 39 B7 00 00 01 0D 31 00 00 1A 00 39 B7 00 00 00 3B B7 00 00 16 

	//++ iStat
	A5 00 39 B7 00 00 16 

	// break
	06 10 00 

// if(kAbility != none)
07 A3 02 77 00 3A B7 00 00 2A 16 

	// switch(kAbility.GetType())
	05 1C 7C 00 00 00 19 00 3A B7 00 00 0A 00 1C 7C 00 00 00 1B 1E 35 00 00 00 00 00 00 16 

		// case 76:
		0A 72 01 2C 4C 

			// XGCharacter_Soldier(kAbility.m_kUnit.GetCharacter()).AddPsiXP(XComGameReplicationInfo(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kGameCore.CalcXP(kAbility.m_kUnit, 11, self))
			19 2E B4 A3 00 00 19 19 00 3A B7 00 00 09 00 E6 7B 00 00 00 01 E6 7B 00 00 0A 00 63 B4 00 00 00 1B 7B 31 00 00 00 00 00 00 16 93 00 00 00 00 00 00 1B 3F 02 00 00 00 00 00 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 2B 00 A3 76 00 00 00 1B F3 0E 00 00 00 00 00 00 19 00 3A B7 00 00 09 00 E6 7B 00 00 00 01 E6 7B 00 00 2C 0B 17 16 16 

			// break
			06 A3 02 

		// case 72:
		0A 56 02 2C 48 

			// XGCharacter_Soldier(kAbility.m_kUnit.GetCharacter()).AddPsiXP(XComGameReplicationInfo(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kGameCore.CalcXP(kAbility.m_kUnit, 10, self));
			19 2E B4 A3 00 00 19 19 00 3A B7 00 00 09 00 E6 7B 00 00 00 01 E6 7B 00 00 0A 00 63 B4 00 00 00 1B 7B 31 00 00 00 00 00 00 16 93 00 00 00 00 00 00 1B 3F 02 00 00 00 00 00 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 2B 00 A3 76 00 00 00 1B F3 0E 00 00 00 00 00 00 19 00 3A B7 00 00 09 00 E6 7B 00 00 00 01 E6 7B 00 00 2C 0A 17 16 16 

			// break
			06 A3 02 

		// case 74:
		0A 68 02 2C 4A 

			// CreateTelekineticFieldVolume()
			1B 6B 13 00 00 00 00 00 00 16 

			// break
			06 A3 02 

		// case 41:
		0A 70 02 2C 29 

			// break
			06 A3 02 

		// case 88:
		0A A0 02 2C 58 

			// XComUnitPawn(m_kPawn).ApplyBloodCall()
			19 2E CF 37 00 00 01 09 31 00 00 0A 00 00 00 00 00 00 1B F3 03 00 00 00 00 00 00 16 

			// break
			06 A3 02 

		// default:
		0A FF FF 

// return
04 0B 

// EOS
53 
[/BEFORE_HEX]


[AFTER_HEX]
//final 2 words of header (function memory/file size)
// HEADER=7A 02 00 00 DE 01 00 00 

// body
// kAbility = none
49 02 00 2A 15 

//iStat = 0
0F 00 39 B7 00 00 25 // example of reference-naming

//if(iStat < 19)
07 56 00 96 00 39 B7 00 00 2C 13 16 // example of reference-marking 

	//m_aCurrentStats[iStat] += aStatModifiers[iStat]
	A1 1A 00 39 B7 00 00 01 0D 31 00 00 1A 00 39 B7 00 00 00 3B B7 00 00 16 

	//++ iStat
	A5 00 39 B7 00 00 16 

	// goto J0x10
	06 10 00 

// if(kAbility != none)
07 77 02 77 00 3A B7 00 00 2A 16 

	// switch(kAbility.GetType())
	05 1C 7C 00 00 00 19 00 3A B7 00 00 0A 00 1C 7C 00 00 00 1B 1E 35 00 00 00 00 00 00 16 

		// case 76:
		0A 93 00 2C 4C 

		// case 72:
		0A 1A 01 2C 48 

			// XGCharacter_Soldier(kAbility.m_kUnit.GetCharacter()).AddPsiXP(((kAbility.GetType() == 72) ? 20 : 30))
			19 2E B4 A3 00 00 19 19 00 3A B7 00 00 09 00 E6 7B 00 00 00 01 E6 7B 00 00 0A 00 63 B4 00 00 00 1B 7B 31 00 00 00 00 00 00 16 36 00 00 00 00 00 00 1B 3F 02 00 00 00 00 00 00 45 9A 19 00 3A B7 00 00 0A 00 1C 7C 00 00 00 1B 1E 35 00 00 00 00 00 00 16 2C 48 16 02 00 2C 14 02 00 2C 1E 16 

			// break
			06 77 02 

		// case 74:
		0A 2C 01 2C 4A 

			// CreateTelekineticFieldVolume()
			1B 6B 13 00 00 00 00 00 00 16 

			// break
			06 77 02 

		// case 41:
		0A 44 02 2C 29 

			// m_aCurrentStats[0] -= aStatModifiers[0]
			A2 1A 25 01 0D 31 00 00 1A 25 00 3B B7 00 00 16 

			// if(kAbility.m_kUnit.IsInFront(none, float(83)))
			07 EF 01 19 19 00 3A B7 00 00 09 00 E6 7B 00 00 00 01 E6 7B 00 00 0F 00 8B B1 00 00 00 1B 99 3D 00 00 00 00 00 00 2A 38 3F 2C 53 16 

				// HealBy(2)
				1B D8 36 00 00 00 00 00 00 2C 02 16 

			// if(kAbility.m_kUnit.GetCharacter().HasUpgrade(55))
			07 EC 01 19 19 19 00 3A B7 00 00 09 00 E6 7B 00 00 00 01 E6 7B 00 00 0A 00 63 B4 00 00 00 1B 7B 31 00 00 00 00 00 00 16 0C 00 EA A2 00 00 00 1B B8 36 00 00 00 00 00 00 2C 37 16 

				// HealBy(2)
				1B D8 36 00 00 00 00 00 00 2C 02 16 

			// break
			06 04 02 

			// HealBy(aStatModifiers[0])
			1B D8 36 00 00 00 00 00 00 1A 25 00 3B B7 00 00 16 

			// null-ops
			00 39 B7 00 00 00 39 B7 00 00 00 39 B7 00 00 00 39 B7 00 00 00 39 B7 00 00 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 

			// break
			06 77 02 

		// case 88:
		0A 74 02 2C 58 

			// XComUnitPawn(m_kPawn).ApplyBloodCall()
			19 2E CF 37 00 00 01 09 31 00 00 0A 00 00 00 00 00 00 1B F3 03 00 00 00 00 00 00 16 

		// break
		06 77 02 

		// default:
		0A FF FF 

// return
04 0B 

// EOS
53 

[/AFTER_HEX]
 

 

 

 

together with the output of the code I have built so far:

 

 

// sample comment

/*more 
sample 
comments*/ 

UPKFILE=XComGame.upk 
FUNCTION=AddStatModifiers.XGUnit 

[BEFORE_HEX] // hex from EU patch 4
//final 2 words of header (function memory/file size)
// [HEADER]
// A6 02 00 00 DE 01 00 00 
// [/HEADER]

// body
//kAbility = none
49 02 00 2A 15 

//iStat = 0
0F 00 {{ 39 B7 00 00 }} 25 // example of reference-naming

//if(iStat < 19)
07 56 00 96 00 {{ 39 B7 00 00 }} 2C 13 16 // example of reference-marking 

	//m_aCurrentStats[iStat] += aStatModifiers[iStat]
	A1 1A 00 {{ 39 B7 00 00 }} 01 {{ 0D 31 00 00 }} 1A 00 {{ 39 B7 00 00 }} 00 {{ 3B B7 00 00 }} 16 

	//++ iStat
	A5 00 {{ 39 B7 00 00 }} 16 

	// break
	06 10 00 

// if(kAbility != none)
07 A3 02 77 00 {{ 3A B7 00 00 }} 2A 16 

	// switch(kAbility.GetType())
	05 {{ 1C 7C 00 00 }} 00 19 00 {{ 3A B7 00 00 }} 0A 00 {{ 1C 7C 00 00 }} 00 1B {{ 1E 35 00 00 }} 00 00 00 00 16 

		// case 76:
		0A 72 01 2C 4C 

			// XGCharacter_Soldier(kAbility.m_kUnit.GetCharacter()).AddPsiXP(XComGameReplicationInfo(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kGameCore.CalcXP(kAbility.m_kUnit, 11, self))
			19 2E {{ B4 A3 00 00 }} 19 19 00 {{ 3A B7 00 00 }} 09 00 {{ E6 7B 00 00 }} 00 01 {{ E6 7B 00 00 }} 0A 00 {{ 63 B4 00 00 }} 00 1B {{ 7B 31 00 00 }} 00 00 00 00 16 93 00 00 00 00 00 00 1B {{ 3F 02 00 00 }} 00 00 00 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 }} 2B 00 {{ A3 76 00 00 }} 00 1B {{ F3 0E 00 00 }} 00 00 00 00 19 00 {{ 3A B7 00 00 }} 09 00 {{ E6 7B 00 00 }} 00 01 {{ E6 7B 00 00 }} 2C 0B 17 16 16 

			// break
			06 A3 02 

		// case 72:
		0A 56 02 2C 48 

			// XGCharacter_Soldier(kAbility.m_kUnit.GetCharacter()).AddPsiXP(XComGameReplicationInfo(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kGameCore.CalcXP(kAbility.m_kUnit, 10, self));
			19 2E {{ B4 A3 00 00 }} 19 19 00 {{ 3A B7 00 00 }} 09 00 {{ E6 7B 00 00 }} 00 01 {{ E6 7B 00 00 }} 0A 00 {{ 63 B4 00 00 }} 00 1B {{ 7B 31 00 00 }} 00 00 00 00 16 93 00 00 00 00 00 00 1B {{ 3F 02 00 00 }} 00 00 00 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 }} 2B 00 {{ A3 76 00 00 }} 00 1B {{ F3 0E 00 00 }} 00 00 00 00 19 00 {{ 3A B7 00 00 }} 09 00 {{ E6 7B 00 00 }} 00 01 {{ E6 7B 00 00 }} 2C 0A 17 16 16 

			// break
			06 A3 02 

		// case 74:
		0A 68 02 2C 4A 

			// CreateTelekineticFieldVolume()
			1B {{ 6B 13 00 00 }} 00 00 00 00 16 

			// break
			06 A3 02 

		// case 41:
		0A 70 02 2C 29 

			// break
			06 A3 02 

		// case 88:
		0A A0 02 2C 58 

			// XComUnitPawn(m_kPawn).ApplyBloodCall()
			19 2E {{ CF 37 00 00 }} 01 {{ 09 31 00 00 }} 0A 00 00 00 00 00 00 1B {{ F3 03 00 00 }} 00 00 00 00 16 

			// break
			06 A3 02 

		// default:
		0A FF FF 

// return
04 0B 

// EOS
53 
[/BEFORE_HEX] 


[AFTER_HEX] 
//final 2 words of header (function memory/file size)
// HEADER=7A 02 00 00 DE 01 00 00 

// body
// kAbility = none
49 02 00 2A 15 

//iStat = 0
0F 00 {{ 39 B7 00 00 }} 25 // example of reference-naming

//if(iStat < 19)
07 56 00 96 00 {{ 39 B7 00 00 }} 2C 13 16 // example of reference-marking 

	//m_aCurrentStats[iStat] += aStatModifiers[iStat]
	A1 1A 00 {{ 39 B7 00 00 }} 01 {{ 0D 31 00 00 }} 1A 00 {{ 39 B7 00 00 }} 00 {{ 3B B7 00 00 }} 16 

	//++ iStat
	A5 00 {{ 39 B7 00 00 }} 16 

	// goto J0x10
	06 10 00 

// if(kAbility != none)
07 77 02 77 00 {{ 3A B7 00 00 }} 2A 16 

	// switch(kAbility.GetType())
	05 {{ 1C 7C 00 00 }} 00 19 00 {{ 3A B7 00 00 }} 0A 00 {{ 1C 7C 00 00 }} 00 1B {{ 1E 35 00 00 }} 00 00 00 00 16 

		// case 76:
		0A 93 00 2C 4C 

		// case 72:
		0A 1A 01 2C 48 

			// XGCharacter_Soldier(kAbility.m_kUnit.GetCharacter()).AddPsiXP(((kAbility.GetType() == 72) ? 20 : 30))
			19 2E {{ B4 A3 00 00 }} 19 19 00 {{ 3A B7 00 00 }} 09 00 {{ E6 7B 00 00 }} 00 01 {{ E6 7B 00 00 }} 0A 00 {{ 63 B4 00 00 }} 00 1B {{ 7B 31 00 00 }} 00 00 00 00 16 36 00 00 00 00 00 00 1B {{ 3F 02 00 00 }} 00 00 00 00 45 9A 19 00 {{ 3A B7 00 00 }} 0A 00 {{ 1C 7C 00 00 }} 00 1B {{ 1E 35 00 00 }} 00 00 00 00 16 2C 48 16 02 00 2C 14 02 00 2C 1E 16 

			// break
			06 77 02 

		// case 74:
		0A 2C 01 2C 4A 

			// CreateTelekineticFieldVolume()
			1B {{ 6B 13 00 00 }} 00 00 00 00 16 

			// break
			06 77 02 

		// case 41:
		0A 44 02 2C 29 

			// m_aCurrentStats[0] -= aStatModifiers[0]
			A2 1A 25 01 {{ 0D 31 00 00 }} 1A 25 00 {{ 3B B7 00 00 }} 16 

			// if(kAbility.m_kUnit.IsInFront(none, float(83)))
			07 EF 01 19 19 00 {{ 3A B7 00 00 }} 09 00 {{ E6 7B 00 00 }} 00 01 {{ E6 7B 00 00 }} 0F 00 {{ 8B B1 00 00 }} 00 1B {{ 99 3D 00 00 }} 00 00 00 00 2A 38 3F 2C 53 16 

				// HealBy(2)
				1B {{ D8 36 00 00 }} 00 00 00 00 2C 02 16 

			// if(kAbility.m_kUnit.GetCharacter().HasUpgrade(55))
			07 EC 01 19 19 19 00 {{ 3A B7 00 00 }} 09 00 {{ E6 7B 00 00 }} 00 01 {{ E6 7B 00 00 }} 0A 00 {{ 63 B4 00 00 }} 00 1B {{ 7B 31 00 00 }} 00 00 00 00 16 0C 00 {{ EA A2 00 00 }} 00 1B {{ B8 36 00 00 }} 00 00 00 00 2C 37 16 

				// HealBy(2)
				1B {{ D8 36 00 00 }} 00 00 00 00 2C 02 16 

			// break
			06 04 02 

			// HealBy(aStatModifiers[0])
			1B {{ D8 36 00 00 }} 00 00 00 00 1A 25 00 {{ 3B B7 00 00 }} 16 

			// null-ops
			00 {{ 39 B7 00 00 }} 00 {{ 39 B7 00 00 }} 00 {{ 39 B7 00 00 }} 00 {{ 39 B7 00 00 }} 00 {{ 39 B7 00 00 }} 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 

			// break
			06 77 02 

		// case 88:
		0A 74 02 2C 58 

			// XComUnitPawn(m_kPawn).ApplyBloodCall()
			19 2E {{ CF 37 00 00 }} 01 {{ 09 31 00 00 }} 0A 00 00 00 00 00 00 1B {{ F3 03 00 00 }} 00 00 00 00 16 

		// break
		06 77 02 

		// default:
		0A FF FF 

// return
04 0B 

// EOS
53 

[/AFTER_HEX] 
 

 

 

 

The only current issue is that it tries to identify references within the header, and of course fails since the header isn't valid executable hex code.

 

Another step toward simplifying modding... maybe then I'll get back to actually making some mods ;)

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.

×
×
  • Create New...