Jump to content

R&D Inventory, Items & Weapons Overhaul


anUser

Recommended Posts

  • Replies 129
  • Created
  • Last Reply

Top Posters In This Topic

I've been conducting some more research and experimentation in my attempt to get consumible items. So far I've coded the ApplyActionCost function to actually remove the item from inventory during the tactical game, and that is reflected back in the base, but there's still something wrong in the lockers (where you equip your units). I'm not devoting too much time currently to modding, can't afford to, so if anyone is willing to take it on from here I'm happy with it.

 

Besides removing the item from the inventory once it's used, I've taken the approach of deprecating the claimed items array, and making that whenever a unit equipped an item that were removed from storage, and vice versa, so in XGStorage.EquipSmallItem I've replaced

STORAGE().ClaimItem(iItem, kSoldier);

for

STORAGE().RemoveItem(iItem); kSoldier;

 

in XGStorage.UnequipSmallItem I made the same, replacing

STORAGE().ReleaseItem(kSoldier.m_kChar.kInventory.arrSmallItems[iSlot], kSoldier);

for STORAGE().AddItem(kSoldier.m_kChar.kInventory.arrSmallItems[iSlot]); kSoldier;

 

and the same in ReleaseLoadout, replacing ReleaseItem(iItem, kSoldier); for AddItem(iItem);

 

BUT, when I equip any item it doesn't decrease the amount displayed, so I always have the starting amount of that item plus as many as I've build in engineering, and both values in engineering (storage) and lockers match, it just ignores what my units have equipped.

 

Next attempt I planned to restore the claiming system and add as well this calls to add/remove items from storage on un/equipping, and see if both combined work well... I'm too lazy and busy to investigate why it does what it does, I'm ok if I just make it work :P

 

XGAbility_Tree.ApplyActionCost

 

function ApplyActionCost(XGAbility_Targeted kAbility)
{
    local int iCost;

    // End:0x343
    if((kAbility.HasProperty(1) || kAbility.GetType() == 40) || kAbility.GetType() == 40)
    {
        iCost = 0;
        switch(kAbility.GetType())
        {
            // End:0xF3
            case 22:
                kAbility.m_kUnit.m_iFragGrenades -= 1;
                iCost = 85;
                // End:0x343
                break;
            // End:0x13E
            case 23:
                kAbility.m_kUnit.m_iSmokeGrenades -= 1;
                iCost = 86;
                // End:0x343
                break;
            // End:0x189
            case 24:
                kAbility.m_kUnit.m_iAlienGrenades -= 1;
                iCost = 88;
                // End:0x343
                break;
            // End:0x18E
            case 36:
            // End:0x193
            case 37:
            // End:0x1DE
            case 41:
                kAbility.m_kUnit.m_iMediKitCharges -= 1;
                iCost = 76;
                // End:0x343
                break;
            // End:0x21D
            case 40:
                kAbility.m_kUnit.m_iGhostCharges -= 1;
                // End:0x343
                break;
            // End:0x268
            case 71:
                kAbility.m_kUnit.m_iBattleScanners -= 1;
                iCost = 99;
                // End:0x343
                break;
            // End:0x2B3
            case 66:
                kAbility.m_kUnit.m_iShredderRockets -= 1;
                iCost = 87;
                // End:0x343
                break;
            // End:0x332
            case 25:
                kAbility.m_kUnit.m_iRockets -= 1;
                // End:0x323
                if(kAbility.m_kWeapon == 7)
                {
                    iCost = 89;
                }
                // End:0x32F
                else
                {
                    iCost = 90;
                }
                // End:0x343
                break;
            // End:0xFFFF
            default:
                iCost = 0;
                // End:0x343
                break;
            }
    }
    // End:0x3E4
    if((kAbility.m_kWeapon != none) && kAbility.m_kWeapon.AllObjects('XGWeapon_ArcThrower'))
    {
        kAbility.m_kUnit.m_iArcThrowerCharges -= 1;
        iCost = 92;
    }
    // End:0x6D5
    if(iCost)
    {
        kAbility.m_kUnit.m_iAlienGrenades += (kAbility.m_kUnit.m_iFragGrenades * 16);
        kAbility.m_kUnit.m_iFragGrenades = iCost;
        iCost = 0;
        J0x4A7:
        // End:0x5F4 [Loop If]
        if(iCost < 16)
        {
            // End:0x5E5
            if(kAbility.m_kUnit.m_kCharacter.m_kChar.kInventory.arrSmallItems[iCost] == kAbility.m_kUnit.m_iFragGrenades)
            {
                kAbility.m_kUnit.m_kCharacter.m_kChar.kInventory.arrSmallItems[iCost] = 0;
                // [Explicit Break]
                goto J0x5F4;
            }
            iCost += 1;
            J0x5F4:
            // [Loop Continue]
            goto J0x4A7;
        }
        kAbility.m_kUnit.m_iFragGrenades = int(float(kAbility.m_kUnit.m_iAlienGrenades) / float(16));
        kAbility.m_kUnit.m_iAlienGrenades -= (kAbility.m_kUnit.m_iFragGrenades * 16);
    }
    // End:0x8D7
    if((kAbility.m_kWeapon != none) && kAbility.HasProperty(1))
    {
        iCost = XComGameReplicationInfo(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kGameCore.GetAmmoCost(kAbility.m_kWeapon.GameplayType(), kAbility.GetType(), kAbility.m_kUnit.GetPlayer().HasFoundryHistory(10), kAbility.m_kUnit.GetCharacter().m_kChar, kAbility.m_bReactionFire);
        kAbility.m_kWeapon.ApplyAmmoCost(iCost);
    }                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
    //return;    
}

Two notes, I made several testings with the switch case and it seems it needs a default block, at least it didn't decompile correctly without one. It could actually run well, but it crashed when the switch didn't found any case, I guess it couldn't tell if it were still in the switch block, since it doesn't tell where it ends. Another thing, to make it display correctly I had to wrap it in an if block, otherwise the sentence following the default case appeared as if inside the switch block. Didn't test functionality on this one.

 

Two comments on the AAC function, the double check for action 40 is because I reserved space for action 45 (reload) so this way I won't have to re-writte hex offsets. In theory now it should make that any action with the arc thrower should take 1 charge, so it could be fair to give standard shot or suppression or disabling shot or other abilities to the arc thrower and make they all consume 1 charge. Using it removes an item 92 (sectoid grenade) which I repurposed as arc thrower batteries, so you could have more chances to stun an alien but at the cost of an inventory item each.

 

I didn't know how to call the TInventorySmallItemsSetItem function because the kInventory var there is a TInventory struct, not an object of XGStorage class... do structures have their own methods, or are they treated like objects and inherit from the class where they're defined? Anyway, I just set the item to 0, it seems that's what the function did, but maybe that one set as well the iNumSmallItems var, I didn't found (haven't really searched for it neither) where this is defined and modified, I've seen some functions making reference to that but most just don't. I've replaced a couple of them for a 16 (I think that's the number of small item slots) to make sure it loops through every item it has to, but I guess that has to be adressed as well.

 

@JL: It would be soo great if it were possible to share inventory within units, and pass over some item. Then it could make sense making the machinegun uses ammo items (it would be pretty easy right now to make that upon realoading it consumes an ammo magazine of the type that weapon uses, what'd happen when out of ammo it's another matter), and also I'd make lot of sense for rockets. Maybe some unused ability can be repurposed for this using current range restrictions, there's one called "loot", not sure if it works though.

Link to comment
Share on other sites

Sounds like you've made excellent progress on this :)

 

Some of the ideas you posted above sparked some ideas to me -- it turns out the basic change to the claim system to remove items from storage is pretty simple.

 

I attacked the issue by rewriting the ClaimItem and ReleaseItem functions themselves.

 

Instead of ClaimItem incrementing the m_arrClaims, it decrements the m_arrItems

 

Instead of ReleaseItem decrementing the m_arrClaims, it increments the m_arrItems

 

Only other change necessary was in GetNumItemsAvailable, to make it return m_arrItems instead of m_arrItems - m_arrClaims

 

I checked and with the changes above equipping an item correctly decrements the count in BOTH the loadout screen and in Engineering (Engineering count has always been based strictly on the number of items in storage, ignoring claims)

 

Here are the hex changes for the above three places:

 

 

ClaimItem:

original:
m_arrClaims[iItemType] += 1;
A1 10 00 85 40 00 00 01 65 40 00 00 26 16
new:
m_arrItems[iItemType] -= 1;
A2 10 00 85 40 00 00 01 67 40 00 00 26 16

 

 

ReleaseItem:

original:
07 46 00 96 10 00 89 40 00 00 01 65 40 00 00 26 16 04 28 A2 10 00 89 40 00 00 01 65 40 00 00 26 16
if(m_arrClaims[iItemType] < 1)
07 46 00 96 10 00 89 40 00 00 01 65 40 00 00 26 16
return false;
04 28
m_arrClaims[iItemType] -= 1;
A2 10 00 89 40 00 00 01 65 40 00 00 26 16
new:
07 46 00 28 10 00 89 40 00 00 01 65 40 00 00 0B 0B 04 28 A1 10 00 89 40 00 00 01 67 40 00 00 26 16
if(false) m_arrClaims[iItemType]
07 46 00 28 10 00 89 40 00 00 01 65 40 00 00 0B 0B
return false;
04 28
m_arrItems[iItemType] += 1;
A1 10 00 89 40 00 00 01 67 40 00 00 26 16

 

GetNumItemsAvailable:

change:
return m_arrItems[iItemType] - m_arrClaims[iItemType];
04 93 10 00 7E 40 00 00 01 67 40 00 00 10 00 7E 40 00 00 01 65 40 00 00 16
to:
return m_arrItems[iItemType] ; m_arrClaims[iItemType]
04 10 00 7E 40 00 00 01 67 40 00 00 0B 0B 10 00 7E 40 00 00 01 65 40 00 00

-------------------------------------

 

Note that this potentially makes EVERY type of item consumable, not just small items. However, to actually remove an item requires removing it from a soldier's inventory during a mission. Pistols, rifles and armor could potentially be lost in this way.

 

This requires a further change to prevent "double removing" items. When a soldier is removed in such a way that his items would normally be lost, RemoveLoadout is called. This only happens from one location, in XGFacility_Barracks.UnloadSoldier.

 

The call to RemoveLoadout can be removed. However, the hex change will differ depending on whether the SHIV Loadout modlet is installed, as that modlet changes he UnloadSoldier function to enable loss of SHIV weapons. This modlet will have to have a second version in order to be compatible with consumible items, if implemented as above.

Link to comment
Share on other sites

Is that considering the Second Wave option where you lose all of their equipment on death?

 

Yes.

 

That is currently handled in XGFacility_Barracks.UnloadSoldier via the conditional:

 

if(kSoldier.m_bMIA || IsOptionEnabled(14))

{

STORAGE().RemoveLoadout(kSoldier);

}

// End:0x480

else

{

STORAGE().ReleaseLoadout(kSoldier);

}

 

 

Option(14) is eGO_LoseGearOnDeath, displayed in the menu as "Total Loss" (I think)

 

This is currently because of the claim system, which increments the claim array value when a piece of gear is equipped, rather than removing it from inventory. RemoveLoadout unclaims all items in a soldier's inventory AND removes them permanently from storage.

 

The alternate (where the soldier is dead but the gear is not lost) simply unclaims the soldier's inventory items.

 

By modifying claim/unclaim to remove/add items from/to STORAGE, the RemoveLoadout line is not necessary (the claim array needs no updating, since it isn't used, and STORAGE already reflects the item being gone). The ReleaseLoadout call will release all of the items, which will add them all back in STORAGE, making them available again.

 

Interestingly, this remove/add system is how the interceptor weapon loadouts are handled. Not sure why there is one system for soldier equipment and another for interceptors.

 

------------------------

 

As to the SHIV loadout differences...

 

Because the SHIV weapons are now built and equipped, I felt they should be able to be lost under the same conditions as soldiers losing gear, so I changed the UnloadSoldier function to:

 

 

if(kSoldier.m_bMIA || IsOptionEnabled(14))
{
// End:0x3DC
if(!kSoldier.IsATank())
{
STORAGE().RemoveLoadout(kSoldier);
}
// End:0x480
else
{
STORAGE().RemoveItem(kSoldier.m_kChar.kInventory.arrLargeItems[0]);
STORAGE().ReleaseLoadout(kSoldier);
}
}
// End:0x4AC
else
{
STORAGE().ReleaseLoadout(kSoldier);
}
In this case both the RemoveLoadout (for Soldiers) and RemoveItem (for SHIVs) have to be removed. The hex code changes and file positions would be different than the vanilla code.
Link to comment
Share on other sites

@ Amineri, that's great man, I'll give it a try. In theory that should be all that was left to have consumible items, but I've said that so many times already that I have too see it by myself :smile:

 

Well, each step should be taking you one step closer to the final solution. I really truly hadn't thought of changing the claim/release functions until something I saw in your post sparked the idea.

 

Probably because Interceptors lose their weapon loadouts by default whenever they're shot down. Unless, I'm wrong, but i'm pretty sure they do.

 

Haha, actually that was a bug I had to fix. In the vanilla game shot down interceptors return their weapons back into STORAGE.

 

It kind of got lost in the same thread as the bug fix to make soldiers lose their gear if you failed the mission due to all soldier dying.

 

Thread is here: http://forums.nexusmods.com/index.php?/topic/958662-r-d-equipment-loss-on-mission-failure-bug/&do=findComment&comment=7761724

 

I never realized that there was a bug there either until johnnylump pointed it out to me. In the vanilla game, though, you tend to lose a lot fewer intereceptors (or none) so it wasn't very noticable.

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.

×
×
  • Create New...