Bertilsson Posted August 10, 2013 Share Posted August 10, 2013 (edited) I was suspecting that 8F had that function, but since terniary operations require that you declare the number of virtual memory bytes you are going to spend on each of the statements I was not very interested in testing it. But yes if works like a negation token then 1 or 2 bytes could be saved depending on if it also requires and end token or not. I just discovered a small bug related to the OTS naggers: If you buy Squad upgrade I only then the extra soldier will be correctly placed left of the existing soldiers but the remaining nagger will be put left of that.It does not affect centering at the original 6 slots, so it is really such a small bug that I will probably not try to fix it any time soon even though it is most likely a simple misplacement of m_iMaxSlots with or without +1. Edit: It was that simple.Fixed hex: F2 16 00 00 AB 1F 00 00 00 00 00 00 ED 16 00 00 00 00 00 00 00 00 00 00 F2 16 00 00 00 00 00 00 25 01 00 00 3A 1E 00 00 6F 05 00 00 B4 03 00 00 0F 00 F0 16 00 00 25 07 B6 00 96 00 F0 16 00 00 36 01 C8 16 00 00 16 14 2D 35 B9 16 00 00 C3 16 00 00 00 01 10 00 F0 16 00 00 01 C8 16 00 00 27 0F 00 EF 16 00 00 46 01 C7 16 00 00 0A 00 00 F0 16 00 00 16 14 2D 35 B8 16 00 00 C3 16 00 00 00 01 10 00 F0 16 00 00 01 C8 16 00 00 99 00 EF 16 00 00 01 C4 16 00 00 16 A5 00 F0 16 00 00 16 06 0B 00 07 48 01 19 19 19 2E B3 16 00 00 01 14 FB FF FF 0A 00 86 16 00 00 00 1B 91 0F 00 00 00 00 00 00 16 0A 00 C7 00 00 00 00 1B 1A 15 00 00 00 00 00 00 16 0C 00 D2 35 00 00 00 1B 14 05 00 00 00 00 00 00 2C 0C 16 14 2D 35 B7 16 00 00 C3 16 00 00 00 01 10 10 92 01 C4 16 00 00 26 16 01 C7 16 00 00 01 C8 16 00 00 27 06 C0 02 07 C0 02 19 19 19 2E B3 16 00 00 01 14 FB FF FF 0A 00 86 16 00 00 00 1B 91 0F 00 00 00 00 00 00 16 0A 00 A0 00 00 00 00 1B 5C 11 00 00 00 00 00 00 16 0C 00 FC 32 00 00 00 1B 0D 11 00 00 00 00 00 00 2C 0C 16 07 32 02 81 19 19 19 2E B3 16 00 00 01 14 FB FF FF 0A 00 86 16 00 00 00 1B 91 0F 00 00 00 00 00 00 16 0A 00 A8 00 00 00 00 1B F4 02 00 00 00 00 00 00 16 0C 00 54 28 00 00 00 1B 17 11 00 00 00 00 00 00 24 01 16 16 14 2D 35 B7 16 00 00 C3 16 00 00 00 01 10 10 92 01 C4 16 00 00 26 16 01 C7 16 00 00 01 C8 16 00 00 27 07 C0 02 81 19 19 19 2E B3 16 00 00 01 14 FB FF FF 0A 00 86 16 00 00 00 1B 91 0F 00 00 00 00 00 00 16 0A 00 A8 00 00 00 00 1B F4 02 00 00 00 00 00 00 16 0C 00 54 28 00 00 00 1B 17 11 00 00 00 00 00 00 24 02 16 16 14 2D 35 B7 16 00 00 C3 16 00 00 00 01 10 10 01 C4 16 00 00 01 C7 16 00 00 01 C8 16 00 00 27 0F 00 F1 16 00 00 25 07 BA 03 96 00 F1 16 00 00 36 19 19 2E B3 16 00 00 01 14 FB FF FF 0A 00 86 16 00 00 00 1B 91 0F 00 00 00 00 00 00 16 09 00 0F 23 00 00 00 01 0F 23 00 00 16 0F 00 EE 16 00 00 10 00 F1 16 00 00 19 19 2E B3 16 00 00 01 14 FB FF FF 0A 00 86 16 00 00 00 1B 91 0F 00 00 00 00 00 00 16 09 00 0F 23 00 00 00 01 0F 23 00 00 0F 10 10 35 08 17 00 00 11 17 00 00 00 00 00 EE 16 00 00 01 C7 16 00 00 01 C8 16 00 00 1C 15 17 00 00 00 EE 16 00 00 16 A5 00 F1 16 00 00 16 06 CB 02 0F 00 F0 16 00 00 25 07 62 05 96 00 F0 16 00 00 36 01 C8 16 00 00 16 0F 00 F2 16 00 00 10 00 F0 16 00 00 01 C8 16 00 00 07 54 05 2D 35 B9 16 00 00 C3 16 00 00 00 00 00 F2 16 00 00 0F 35 C2 16 00 00 C3 16 00 00 00 01 00 F2 16 00 00 1D FF FF FF FF 0F 35 BB 16 00 00 C3 16 00 00 00 01 00 F2 16 00 00 1D FF FF FF FF 0F 35 C1 16 00 00 C3 16 00 00 00 01 00 F2 16 00 00 1F 00 0F 35 C0 16 00 00 C3 16 00 00 00 01 00 F2 16 00 00 1F 00 0F 35 BF 16 00 00 C3 16 00 00 00 01 00 F2 16 00 00 1F 00 0F 35 BE 16 00 00 C3 16 00 00 00 01 00 F2 16 00 00 1F 00 0F 35 BD 16 00 00 C3 16 00 00 00 01 00 F2 16 00 00 1F 00 0F 35 BC 16 00 00 C3 16 00 00 00 01 00 F2 16 00 00 1F 00 14 2D 35 B9 16 00 00 C3 16 00 00 00 01 00 F2 16 00 00 27 0F 10 00 F0 16 00 00 01 C8 16 00 00 00 F2 16 00 00 A5 00 F0 16 00 00 16 06 C5 03 1B B1 2B 00 00 00 00 00 00 16 04 0B 53 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 00 00 00 02 01 82 00 AC 2B 00 00 00 00 00 00 Edited August 10, 2013 by Bertilsson Link to comment Share on other sites More sharing options...
Bertilsson Posted August 11, 2013 Share Posted August 11, 2013 I did some thinking about how to place all pawns in diagonal line...And got as far as coming up with this target code: I = 1; IStart: if (I < kSkyranger.m_arrSoldiers.Length) { kSoldier = kSkyranger.m_arrSoldiers[I]; J = 0; JStart: if (J < I) { kSoldier.m_kPawn.SetLocation(kSoldier.m_kPawn.Location + vect(10.0, 10.0, 0.0)); ++J; Goto JStart } ++I; Goto IStart } Then I realized that I want to modify the locations _before_ the soldiers are actually put inside the skyranger not after... Doh! But putting that (very significant) detail aside, is there any additional reason why the above code would not work?Is it a correct assumption that the pawn belonging to a strategysoldier can be accessed by adding .m_kPawn and that the pawn in turn can be moved with .setlocation and asked about current location with .location? Link to comment Share on other sites More sharing options...
XMarksTheSpot Posted August 11, 2013 Share Posted August 11, 2013 I did some thinking about how to place all pawns in diagonal line...And got as far as coming up with this target code: [snip] Then I realized that I want to modify the locations _before_ the soldiers are actually put inside the skyranger not after... Doh! But putting that (very significant) detail aside, is there any additional reason why the above code would not work?Is it a correct assumption that the pawn belonging to a strategysoldier can be accessed by adding .m_kPawn and that the pawn in turn can be moved with .setlocation and asked about current location with .location?Two things:Where would you try to insert that piece of code?And why not simply use Move() nstead of SetLocation()? You don't have to worry about the pawn's current position that way, you only need a delta vector. I've been tinkering around with the XGStrategySoldier.AddToLocation() method, in particular this snippet: CreatePawn(SoldierState); RoomName = HQLocToName(Loc); // End:0x129 if(!class'SeqEvent_HQUnits'.static.AddUnitToRoomSequence(RoomName, m_kPawn, SlotIdx)) { DestroyPawn(); } // End:0x136 break; By inlining the RoomName = HQLocToName(Loc) line I could free up some bytes to replace SlotIdx with SlotIdx % 6 which made additional soldier pawns beyond slot 5 appear on top of the default 6 ones.I think that would be a good place to alter the positions of the extra pawns after their initial placement, maybe some unused function could be hijacked to add in the necessary logic (DEMOUltimateSoldier() looks like a viable candidate?). Link to comment Share on other sites More sharing options...
Bertilsson Posted August 11, 2013 Share Posted August 11, 2013 (edited) Same reason as usual, no idea how it works :smile: If you haven't already tried inlining this is the code to do it: 5E 45 00 00 AB 1F 00 00 00 00 00 00 5A 45 00 00 00 00 00 00 00 00 00 00 5E 45 00 00 00 00 00 00 EB 02 00 00 6D 4D 00 00 2A 01 00 00 FD 00 00 00 49 06 00 1D FF FF FF FF 15 07 1D 01 1B 43 23 00 00 00 00 00 00 00 5E 45 00 00 16 05 5E 45 00 00 00 00 5E 45 00 00 0A 4D 00 24 01 0F 00 5C 45 00 00 21 FB 12 00 00 00 00 00 00 06 B0 00 0A 68 00 24 06 0F 00 5C 45 00 00 21 4E 05 00 00 00 00 00 00 06 B0 00 0A 6D 00 24 00 0A 72 00 24 02 0A 77 00 24 05 0A 92 00 24 08 0F 00 5C 45 00 00 21 E2 1F 00 00 00 00 00 00 06 B0 00 0A AD 00 24 07 0F 00 5C 45 00 00 21 FA 12 00 00 00 00 00 00 06 B0 00 0A FF FF 1B 6D 06 00 00 00 00 00 00 00 5C 45 00 00 16 07 1A 01 81 12 20 BA FE FF FF 25 00 93 FF FF FF 00 1B CD 00 00 00 00 00 00 00 1B 69 11 00 00 00 00 00 00 00 5E 45 00 00 16 01 E0 44 00 00 FD 00 5D 45 00 00 2C 06 16 16 16 1B BC 07 00 00 00 00 00 00 16 06 27 01 1B BC 07 00 00 00 00 00 00 16 04 0B 53 0B 0B 0B 0B 0B 0B 0B 00 00 00 03 40 04 00 C9 00 00 00 00 00 00 00 Edit: Corrected and tested code. It works. It now looks like this: default: CreatePawn(SoldierState); // End:0x11A if(!class'SeqEvent_HQUnits'.static.AddUnitToRoomSequence(HQLocToName(Loc), m_kPawn, SlotIdx % 6)) { DestroyPawn(); } // End:0x127 break; As to where to insert movement code I hadn't planned any further than finding an unused function and replace something with that function, ideally letting that function do the movement and whatever was replaced. Edited August 11, 2013 by Bertilsson Link to comment Share on other sites More sharing options...
Bertilsson Posted August 11, 2013 Share Posted August 11, 2013 (edited) If I understand how to use functions correctly simply calling DemoUltimateSoldier(0) takes 11 bytes or 12 bytes if you want send an integer larger than 1 as parameter. In the UpdateData function there are 13 unused bytes after removing the redundant line and making OTS naggers dynamic. (I'm pretty sure the logic surrounding the naggers could be optimized to save some more bytes if needed.) So how about adding a call to DemoUltimateSoldier(0) in the end of UpdateData, right before UpdateDisplay()? Edit: Or hmm... If some more space was made would it work to put this line inside the iSoldier-Loop?kLoadout.DemoUltimateSoldier(iSoldier) to have a the strategysoldier in context and iSoldier as parameter to figure out where the soldier should be moved? Edited August 11, 2013 by Bertilsson Link to comment Share on other sites More sharing options...
XMarksTheSpot Posted August 11, 2013 Share Posted August 11, 2013 I'd place it further downstream somewhere in the XGStrategySoldier class, e.g. inside AddToLocation(). In there you have direct access to the pawn reference as well as the HQ location and slot variables.Logic-wise you'd only need to check whether Loc == 1 (hangar) and SlotIdx >= 6. If that yields true you'd modify the AddUnitToRoomSequence() call to target some other slot (e.g. 0) and finally move the actor to some different position.Somewhere down the road we'd need to work out some formula for the position deltas, maybe via investigating the vanilla positions and extrapolating from there. For a proof-of-concept implementation a simple static delta vector would suffice, I'd say. Link to comment Share on other sites More sharing options...
Bertilsson Posted August 11, 2013 Share Posted August 11, 2013 (edited) Could additional bytes be saved in AddToLocation() by changing: if(!class'SeqEvent_HQUnits'.static.AddUnitToRoomSequence(HQLocToName(Loc), m_kPawn, SlotIdx % 6)) { DestroyPawn(); } // End:0x127 break; } } DestroyPawn(); //return; to: if(!class'SeqEvent_HQUnits'.static.AddUnitToRoomSequence(HQLocToName(Loc), m_kPawn, SlotIdx % 6)) { goto XXX //DestroyPawn(); } // End:0x127 break; } } XXX: DestroyPawn(); //return; ? Edited August 11, 2013 by Bertilsson Link to comment Share on other sites More sharing options...
XMarksTheSpot Posted August 11, 2013 Share Posted August 11, 2013 (edited) Could additional bytes be saved in AddToLocation() by changing: function call in conditional to: function call replaced with jump ?Quite possibly, yeah. I'm not sure whether putting in SlotIdx % 6 right there is a good idea as it might interfere with the actor placement in other contexts (e.g. inside barracks). If anything modifying the slot id should be part of the logic specific to the hangar placement.If the Loc and SlotIdx references could be passed to a helper function (they aren't local variables per se, so I don't know whether they are accessible from inside other functions like it's possible for locals) the logic could look something like this: if ((Loc == 1) && (SlotIdx >= 6)) { if (!class'SeqEvent_HQUnits'.static.AddUnitToRoomSequence(HQLocToName(Loc), m_kPawn, SlotIdx % 6)) { DestroyPawn(); } else { m_kPawn.Move(vect(10.0, 10.0, 0.0)) } } else { if (!class'SeqEvent_HQUnits'.static.AddUnitToRoomSequence(HQLocToName(Loc), m_kPawn, SlotIdx)) { DestroyPawn(); } } Edited August 11, 2013 by XMarksTheSpot Link to comment Share on other sites More sharing options...
Bertilsson Posted August 11, 2013 Share Posted August 11, 2013 Hmm... Spagethi coding was not appreciated by UE Explorer, it completely messed up the object code :( I did look into the barracks to see if there was any visible issue with overlapping soldiers after adding the % 6 as I also suspected that it could be an issue. However, there were no strange issues going on there... (I never ruled out the possibility that some soldier were missing though). Removing the % 6 would save 4 bytes leaving a total of 12 bytes available to play with in updatedata... Not much room for being creative there... Also passing variables to helper function requires finding an unused function which is already defined to accept parameters of correct type. Link to comment Share on other sites More sharing options...
XMarksTheSpot Posted August 11, 2013 Share Posted August 11, 2013 (edited) Also passing variables to helper function requires finding an unused function which is already defined to accept parameters of correct type.I suppose through clever use of bit-packing or otherwise encoding the variables one could get around that limitation and use a helper method with some other king of parameter, e.g. single int or string.Edit: I see DEMOUltimateSoldier(4, true) being called, so XComGame.XGTacticalGameCoreData.ESoldierClass is essentially wrapping an int, as it seems Edited August 11, 2013 by XMarksTheSpot Link to comment Share on other sites More sharing options...
Recommended Posts