wghost81 Posted November 24, 2013 Share Posted November 24, 2013 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 More sharing options...
wghost81 Posted November 24, 2013 Share Posted November 24, 2013 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 githubUPK 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 More sharing options...
Bertilsson Posted November 24, 2013 Share Posted November 24, 2013 (edited) 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 githubIs 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 November 24, 2013 by Bertilsson Link to comment Share on other sites More sharing options...
Amineri Posted November 24, 2013 Author Share Posted November 24, 2013 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 0x28privatewrite XComInteractPoint m_arrInteractPoints[6] = size 0x2CForceFeedbackWaveform m_arrPanicFF[2] = size 0x2CXGVolume m_aVolumes[16] = size 0x2Eint m_iBWAimPenalty = size 0x2Aint 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 More sharing options...
EliotVU Posted November 25, 2013 Share Posted November 25, 2013 How's this for a change? http://i.imgur.com/55HWq1E.png Link to comment Share on other sites More sharing options...
Bertilsson Posted November 25, 2013 Share Posted November 25, 2013 How's this for a change?That looks awesome!!! Link to comment Share on other sites More sharing options...
wghost81 Posted November 26, 2013 Share Posted November 26, 2013 (edited) 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 returnsif((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 November 26, 2013 by wghost81 Link to comment Share on other sites More sharing options...
Amineri Posted November 26, 2013 Author Share Posted November 26, 2013 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 More sharing options...
Amineri Posted November 26, 2013 Author Share Posted November 26, 2013 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 More sharing options...
wghost81 Posted November 26, 2013 Share Posted November 26, 2013 (edited) Amineri, this is actually code from XComGame.upk, CollectArtifactsFromDeadAliens function. Edited November 26, 2013 by wghost81 Link to comment Share on other sites More sharing options...
Recommended Posts