Jump to content

R&D to Increase Squad Size


Beknatok

Recommended Posts

But where does the move token get into the picture?

From what I can gather from the code Move() is handled exactly the same as SetLocation() (0x0B), I figured you were familiar with the latter as you pondered using it several times :)

Move() never seems to be called anywhere in the main game packages, but I suppose you can recycle a call to the related SetLocation() method (e.g. inside XGStrategySoldier.PlaceOnArmoryPlinth()) and simply swap the 0x0B token with 0x0A :)

Link to comment
Share on other sites

  • Replies 429
  • Created
  • Last Reply

Top Posters In This Topic

I actually assumed SetLocation() and move() to be called in the same fashion as any other .function... Well well... I have collected all references and put them into my trusty notepad document now, so it should be pretty straightforward to puzzle it together tomorrow.

Link to comment
Share on other sites

I implemented the proposed code but had to un-inline roomname (back to AddToLocation) to make space in DemoUltimateSoldier.

 

Except for that it was possible to implement the proposed code.

 

But... During testing the game crashes as soon as I try to load an old game.

 

I have now almost completely emptied DemoUltimateSoldier and removed any need for borrowing parameter variables from AddToLocation:

function DEMOUltimateSoldier(XComGame.XGTacticalGameCoreData.ESoldierClass eClass, optional bool bPsi)
{
  // End:0x89
  if(!class'SeqEvent_HQUnits'.static.AddUnitToRoomSequence(RoomName, m_kPawn, eClass))
  {
    DestroyPawn();                                                                                                                                                                
  }
  //return;  
}

4B 45 00 00 AB 1F 00 00 00 00 00 00 49 45 00 00 00 00 00 00 00 00 00 00 4B 45 00 00 00 00 00 00 B0 02 00 00 D2 47 00 00 4D 00 00 00 7E 00 00 00 0B 07 4A 00 81 12 20 BA FE FF FF 25 00 93 FF FF FF 00 1B CD 00 00 00 00 00 00 00 00 5B 45 00 00 01 E0 44 00 00 00 4B 45 00 00 16 16 1B BC 07 00 00 00 00 00 00 16 04 0B 53 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 00 00 00 02 40 02 00 B3 07 00 00 00 00 00 00

And AddToLocation looks like this:

private final function AddToLocation(XGStrategySoldier.ESoldierLocation Loc, optional int SlotIdx)
{
  local name SoldierState;
  local string RoomName;

  SlotIdx = -1;
  // End:0x111
  if(RoomRequiresPawn(Loc))
  {
    switch(Loc)
    {
      // End:0x4D
      case 1:
        SoldierState = 'InHQ';
        // End:0xB0
        break;
      // End:0x68
      case 6:
        SoldierState = 'CharacterCustomization';
        // End:0xB0
        break;
      // End:0x6D
      case 0:
      // End:0x72
      case 2:
      // End:0x77
      case 5:
      // End:0x92
      case 8:
        SoldierState = 'OffDuty';
        // End:0xB0
        break;
      // End:0xAD
      case 7:
        SoldierState = 'InGollup';
        // End:0xB0
        break;
      // End:0xFFFF
      default:
        CreatePawn(SoldierState);
        RoomName = HQLocToName(Loc);
        DEMOUltimateSoldier(SlotIdx, (Loc == 1) && (SlotIdx >= 6));
        // End:0x11B
        break;
      }
  }
  DestroyPawn();
  //return;  
}
Byte code: Decimal offset 3915217
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 1E 01 00 00 FD 00 00 00 49 06 00 1D FF FF FF FF 15 07 11 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 0F 00 5B 45 00 00 1B 69 11 00 00 00 00 00 00 00 5E 45 00 00 16 1B B3 07 00 00 00 00 00 00 00 5D 45 00 00 82 F2 00 5E 45 00 00 26 16 99 00 5D 45 00 00 2C 06 16 16 16 06 1B 01 1B BC 07 00 00 00 00 00 00 16 04 0B 53 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 00 00 00 03 40 04 00 C9 00 00 00 00 00 00 00

And the game just keeps on crashing as soon as I expect to see the 3D base layout.

 

I can only conclude that one or more of the following is true:

  • It is not OK to read local variable values from calling function (RoomName)
  • I accidently messed up jump offsets in AddToLocation even if I have manually verified them.
  • Something is wrong with the logic in AddToLocation

I will do some more testing later tonight and post the hexes if someone else wants to trouble shoot, but right now it doesn't look promissing at all.

 

Edit:

 

It just won't run :sad:

function DEMOUltimateSoldier(XComGame.XGTacticalGameCoreData.ESoldierClass eClass, optional bool bPsi)
{
  // End:0x24
  if(bPsi)
  {
    eClass = eClass % 6;
  }
  // End:0x6F
  if(!class'SeqEvent_HQUnits'.static.AddUnitToRoomSequence(RoomName, m_kPawn, eClass))
  {
    DestroyPawn();
    return;
  }
  // End:0xA1
  if(bPsi)
  {
    m_kPawn.Move(vect(0.0, 0.0, 0.0));
  }
  //return;  
}

Byte code: Decimal offset: 3913869
4B 45 00 00 AB 1F 00 00 00 00 00 00 49 45 00 00 00 00 00 00 00 00 00 00 4B 45 00 00 00 00 00 00 B0 02 00 00 D2 47 00 00 A4 00 00 00 7E 00 00 00 07 24 00 2D 00 4A 45 00 00 0F 00 4B 45 00 00 FD 00 4B 45 00 00 2C 06 16 07 6F 00 81 12 20 BA FE FF FF 25 00 93 FF FF FF 00 1B CD 00 00 00 00 00 00 00 00 5B 45 00 00 01 E0 44 00 00 00 4B 45 00 00 16 16 1B BC 07 00 00 00 00 00 00 16 04 0B 07 A1 00 2D 00 4A 45 00 00 19 01 E0 44 00 00 21 00 B5 FF FF FF 00 61 0A 23 00 00 00 00 00 00 00 00 00 00 00 00 16 04 0B 53 0B 0B 0B 0B 0B 0B 00 00 00 02 40 02 00 B3 07 00 00 00 00 00 00

I've tried always setting bPsi to false in the call, I've tried removing almost all new code and I've even tried hardcoding HQLocToName(1) instead of RoomName in hope that everyone would gather in the hangar... But no matter what it just crashes instead of showing the base.

 

So I'm pretty much giving up now.

Edited by Bertilsson
Link to comment
Share on other sites

This:

      default:
        CreatePawn(SoldierState);
--->>   DEMOUltimateSoldier(0);   <<-----
        if(!class'SeqEvent_HQUnits'.static.AddUnitToRoomSequence(HQLocToName(Loc), m_kPawn, SlotIdx))
        {
          DestroyPawn();
        }
        break;

And this:

function DEMOUltimateSoldier(XComGame.XGTacticalGameCoreData.ESoldierClass eClass, optional bool bPsi)
{
  SlotIdx = SlotIdx % 6;
  //return;  
}

Has no ingame effect... So I guess that rules out the possibility to alter any local input parameters via helper function.

 

Also

This:

        CreatePawn(SoldierState);
        if(!class'SeqEvent_HQUnits'.static.AddUnitToRoomSequence(HQLocToName(Loc), m_kPawn, SlotIdx))
        {
          DestroyPawn();
        }
--->>   DEMOUltimateSoldier(0);  <<---
        break;
      } 

and this:

function DEMOUltimateSoldier(XComGame.XGTacticalGameCoreData.ESoldierClass eClass, optional bool bPsi)
{
  m_kPawn.move(vect(10.0, 10.0, 0.0)):
  //return;  
}

Is one of the many ways to crash the game...

 

So to sumarize... It's not working out well at all.

Link to comment
Share on other sites

Optional parameters are a little bit tricky and could be causing some of your crashing issues.

 

Each optional paramter in the function requires some sort of hex code at the beginning of the function or the code will crash at run-time.

 

The simplest is having a single 0x0B token at the beginning (although one is needed for each optional parameter). This basically tells the engine to use the default value for the optional parameter if it is not defined (i.e. false for boolean, 0 for integer, none for class, etc).

 

Removing the 0x0B will cause the code to crash.

 

The alternative is a more complex statement that sets the optional parameter to some other value. This statement is completely unlike the usual 0x0F construction, as it only performs the assignment if the optional parameter was not assigned a value when the function is invoked (using a 0x2A 'no parameter' token).

 

The decompile of AddToLocation shows a default value of -1 being assigned to the optional parameter SlotIdx. However, I don't see an assignment for the optional bPsi parameter in DEMOUltimateSoldier, and your hex code (following the header) is directly starting with a 0x07 conditional jump token. You definitely need a single 0x0B token there to instruct the engine that bPsi's default value when not assigned is false. I've found the hard way that removing that 0x0B token causes the game to crash.

Link to comment
Share on other sites

Regarding passing of additional information to functions ...

 

I've as yet been unable to figure out how to alter the parameter list, either adding new parameters or altering existing parameters into another type.

 

So, if I have a calling function but can't pass the parameter I need (a common occurence, actually), the only alternative is to pass the data indirectly via a class variable.

 

As an example of this, the code that upgrades individual alien units is XGUnit.DebugAnims:

simulated function DebugAnims(Canvas kCanvas, XComTacticalCheatManager kCheatManager)

It only has 2 classes as parameters. However, the alien leader level has to be passed in order to let the function know how to upgrade the alien unit.

 

I did this by putting the leader level in the XGUnit.m_iSmokeGrenades class variable (since aliens can never have smoke grenades this variable has no game effect for aliens -- plus they never have the smoke grenade perk so the ability remains unusable even if mind-controlled by the player).

 

This is all set / invoked from XComAlienPodManager.OvermindSpawn with the code fragment:

                kAlien = m_kPlayer.SpawnAlien(eAlienType, kSpawnPt,,,, bUseAltWeapon);
                // End:0x565
                if(kAlien != none)
                {
                    // End:0x3FD
                    if(iNum == 0)
                    {
                        kAlien.m_iSmokeGrenades = 7 & kSpawn.kPod.eMainAltWeapon;
                    }
                    kAlien.DebugAnims(none, none);                    

The alien unit is spawned. Only the first alien has it's m_iSmokeGrenades value set (only the first alien is an upgradable leader), and then DebugAnims is called. DebugAnims then reads the local class copy of m_iSmokeGrenades, for example:

    if(m_iSmokeGrenades > 0)
Link to comment
Share on other sites

That explains why I was suddenly able to run the game with "0B 04 0B" as total code when testing the two later scenarios :wallbash:

 

Guess I this calls for some testing with restored 0B in DEMOfunction and temporary removed m_Kpawn.move()...

 

Edit: I suppose until someone is able to get some variant of m_kPawn.move(vect(10.0, 10.0, 0.0)) working it is pretty much a dead end.

 

If that can be made to work then it might also be reasonable to move the entire function to DEMOAddNewSoldiers or DEMOEquipNewSoldiers where there is at least plenty of space to work with.

Edited by Bertilsson
Link to comment
Share on other sites

This was a bit unexpected and interesting...

function DEMOUltimateSoldier(XComGame.XGTacticalGameCoreData.ESoldierClass eClass, optional bool bPsi)
{
  m_kPawn.SetLocation(m_kPawn.Location);
  //return;  
}

4B 45 00 00 AB 1F 00 00 00 00 00 00 49 45 00 00 00 00 00 00 00 00 00 00 4B 45 00 00 00 00 00 00 B0 02 00 00 D2 47 00 00 3A 00 00 00 7E 00 00 00 0B 19 01 E0 44 00 00 21 00 B5 FF FF FF 00 61 0B 19 01 E0 44 00 00 09 00 D3 F9 FF FF 00 01 D3 F9 FF FF 16 04 0B 53 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 00 00 00 02 40 02 00 B3 07 00 00 00 00 00 00

Instead of doing nothing it actually offsets soldiers quite a bit...

 

Edit: To clarify, they are offset from the barracks in the screenshot

Edited by Bertilsson
Link to comment
Share on other sites

And additional testing offers little more sense...

  m_kPawn.Location = m_kPawn.Location + vect(10.0, 10.0, 0.0); //Never ending load screen
  m_kPawn.SetLocation(m_kPawn.Location + vect(10.0, 10.0, 0.0)); //Never ending load screen
  m_kPawn.SetLocation(vect(10.0, 10.0, 0.0)); //Game crash
Link to comment
Share on other sites

This was a bit unexpected and interesting...

[snip]

Instead of doing nothing it actually offsets soldiers quite a bit...

 

Edit: To clarify, they are offset from the barracks in the screenshot

Interesting, especially considering I ran into that, too, just a few moments ago.

I've been messing around with the AddToLocation() function, freeing up some space by inlining the RoomName variable, trimming down the switch statement and inverting the AddUnitToRoomSequence() conditional:

private final function AddToLocation(XGStrategySoldier.ESoldierLocation Loc, optional int SlotIdx)
{
    local name SoldierState;
    local string RoomName;

    SlotIdx = -1;
    // End:0x11C
    if(RoomRequiresPawn(Loc))
    {
        switch(Loc)
        {
            // End:0x4C
            case 1:
                SoldierState = 'InHQ';
                // End:0x9B
                break;
            // End:0x67
            case 6:
                SoldierState = 'CharacterCustomization';
                // End:0x9B
                break;
            // End:0x82
            case 7:
                SoldierState = 'InGollup';
                // End:0x9B
                break;
            // End:0xFFFF
            default:
                SoldierState = 'OffDuty';
                // End:0x9B
                break;
        }
        CreatePawn(SoldierState);
        // End:0x11C
        if(class'SeqEvent_HQUnits'.static.AddUnitToRoomSequence(HQLocToName(Loc), m_kPawn, SlotIdx))
        {
            m_kPawn.SetLocation(vect(0.0, 0.0, 0.0));
            return;
        }
    }
    DestroyPawn();
    //return;    
}
hex offset 3915185 (0x3BBDB1), 316 (0x13C) bytes total
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 29 01 00 00 FD 00 00 00 49 06 00 1D FF FF FF FF 15 07 1C 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 4C 00 26 0F 00 5C 45 00 00 21 FB 12 00 00 00 00 00 00 06 9B 00 0A 67 00 24 06 0F 00 5C 45 00 00 21 4E 05 00 00 00 00 00 00 06 9B 00 0A 82 00 24 07 0F 00 5C 45 00 00 21 FA 12 00 00 00 00 00 00 06 9B 00 0A FF FF 0F 00 5C 45 00 00 21 E2 1F 00 00 00 00 00 00 06 9B 00 1B 6D 06 00 00 00 00 00 00 00 5C 45 00 00 16 07 1C 01 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 00 5D 45 00 00 16 19 01 E0 44 00 00 21 00 B5 FF FF FF 00 61 0B 23 00 00 00 00 00 00 00 00 00 00 00 00 16 04 0B 1B BC 07 00 00 00 00 00 00 16 04 0B 53 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 00 00 00 03 40 04 00 C9 00 00 00 00 00 00 00

As you can see I added a SetLocation() call targeted at [0, 0, 0] and interestingly it makes the pawns show up in exactly the same positions as in your screenshot.

This leads me to believe that m_kPawn.Location doesn't reflect the pawns' world coordinates... which means that the way the SetBase() call inside AddUnitToRoomSequence() moves pawns around probably differs from the SetLocation() mechanism. Perhaps calling SetLocation() like we did moved the parent actor to which the pawns were attached instead of the individual pawns?

Edited by XMarksTheSpot
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.

×
×
  • Create New...