Jump to content

R&D Inventory, Items & Weapons Overhaul


anUser

Recommended Posts

Not off-topic at all... point 1 is making items buildable and equippable without perk requirement, and this trick of giving the perk on item equipment is a cool thing. Yeah giving perk-items is quite the opposite but totaly related to inventory management. Anyway until I'm convinced that managing several inventory slots isn't the way to go, I think I'll just GivePerk() each unit each mission with relevant perks and I'll make it all equippable.

 

I didn't thought about the implications of skipping that check... what a pity. Maybe there's some workaround, but I guess that won't be so simple now.

Link to comment
Share on other sites

  • Replies 129
  • Created
  • Last Reply

Top Posters In This Topic

So, I've been digging into the actionscript code to see if it is possible to add a scrollbar to the inventory list.

 

I'll explain. The loadout menu code creates two classes in the SWF code: the InventoryList and the LockerList.

 

The LockerList is what is on the left side of the UI window -- what your soldier currently has equipped. This doesn't have a scroll bar.

 

The InventoryList is what is on the right side of the UI window -- items in the locker that are selectable to be equipped. This DOES have a scroll bar.

 

In the SWF code, both LockerList and InventoryList are derived from the same parent class: XcomList. XcomList implements the scroll bar functionality (which is mostly defined as another widget class, XcomScrollbar, but I digress).

 

The InventoryList already has some of the functionality of a scrollable window in the vanilla game. When you equip a sixth item, it is partially displayed (but clipped) off the bottom of the list.

 

The primary difference between InventoryList and LockerList is the initiation:

LockerList has the following two calls in its OnLoad (initiation) function:

 

this.scrollbar=this.myScrollbar;
this.scrollbar.SetTargetList(this);
which InventoryList is lacking.
These two calls total 35 bytes of hex code. Unfortunately, the OnLoad function for InventoryList leaves no possibility of adding these calls, as it only calls its parent classes OnLoad function:
function onLoad()
{
super.onLoad();
}
If I could only add in those two calls to the InventoryList.Onload function, I think everything would work beautifully. Alas, I can't. Am trying to figure out some clever workaround, but so far have come up dry.
Link to comment
Share on other sites

Dagnabit!

 

I actually figured out how to recode a bit in Actionscript (as opposed to simpler value changes).

 

I was going to change the OnLoad call in the master function SoldierLoadout from:

 

 

 

function onLoad()
{
super.onLoad();
this.SetScreenTitle();
this.SetListTitles("","");
this.selectorMC=this.selectionIndicatorMC;
this.initialSelectorY=this.selectorMC._y;
this.inventoryList=this.inventoryListMC;
this.inventoryList._visible=false;
this.lockerList=this.lockerListMC;
this.lockerList._visible=false;
}

 

to

 

 

 

function onLoad()
{
super.onLoad();
this.selectorMC=this.selectionIndicatorMC;
this.initialSelectorY=this.selectorMC._y;
this.inventoryList=this.inventoryListMC;
this.inventoryList.scrollbar=this.myScrollbar;
this.inventoryList.scrollbar.SetTargetList(this.inventoryList);
this.lockerList=this.lockerListMC;
}

 

I even figured out how to build the new assignment and function calls in hex. Unfortunately, the new hex was 96 bytes, and I had only freed up 68 bytes ~_~. Time for a new plan.

 

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

 

The SWF decompiler I'm using (http://www.free-decompiler.com/flash/) has some nice features.

 

One is that it has a limited recompiler ability built into it. Currently it only really works in the "stack view" mode (although this most recent 1.50 build has a beta mode for editting/recompiling "regular" SWF code). This allows me to easily get to the new hex construction I'm trying to build. Unfortunately most of the SWF functions are pretty small, and there's not nearly as much extraneous code / functions to play with as in the upk code.

Link to comment
Share on other sites

Very good, it seems you're doing great progress here... all this flash stuff it's absolutely new to me, I actualy haven't even tried to access the code, and I don't think I'll try it any sooner, I still have got several "balance" issues I'm working on.

 

In particular, I've been playtesting with 3 inventory slots and consumible items (every small item removed at mission end, including grenades, which I only had 10 when I started the game) and the feeling of it wasn't that great as one could have expected. Nevertheless I still think a small dose of strategic micromanagement to boost the tactical game is in order (ie not only choosing bringing you best soldiers to battle or not, but also choosing bringing to battle your best and most expensive equipment or not, which may require a bit of planning beforehand), so I'll try to sum up my impressions so far:

 

- giving so many inventory slots you can power up your units pretty much. This isn't bad per se, but it makes poorly equipped units seem so unpowered in comparison... this is merely a psychological effect of seeing your soldier's backpack one besides the other in the squad selection screen, and it ends once you start the mission, there you only have different soldiers with different stats and abilities, just so, but I can tell the effect in the squad selection screen is real... it kinda feels bad leaving a unit unequipped.

 

- sometimes it's hard to mind the cost those items have, despite they do have a cost. Using my current price list the difference between equipping your units well each mission or not doing so may represent having to wait another month to build the OTS or the foundry, or having to sell ufo items and elerium, which was right the effect I was looking for, ... but as they're such small things and so cheap in themselves it's easy to forget they do have a cost. I was so tempted te equip every soldier with at least an armor vest the first missions... and grenades at least I carried two per mission, that was easier to leave aside, but not armor vests (despite I made them pricy, 10$ each, and consumible). Sometimes, if you assume certain items as strictly necessary, it may feel like you've just got yet another requirement instead of a strategic choice. On the other hand, if you choose to go cheap, as cheap as not equipping a single item, completing the mission isn't that rewarding... it may be if you don't buy any item at all and with that money you manage to launch 7 satellites by the second month, but truly after finishing a mission my thought isn't "hurray I saved $20 by not equipping an extra grenade!", you gotta be quite greedy to think in this terms...

 

- About the loss of opportunity cost with more inventory slots: it's a fact, if you only have 1 inventory slot you can only equip 1 item, so you can't equip any of the other items. With 3 inv. slots this is no longer the case. While it is ok for items that have a limited number of uses, such as grenades, smoke grenades, battlescanner, rockets, it is not so for items that grant constant effects like nanofiber vest, scope or grapple. The more available item slots the smaller the opportunity cost of equipping those "passive" items. This isn't necessarily a bad thing, by increasing inventory slots we also create more possible combinations, and given the pretty wide range of equippable items now you still can't have it all, so there's still an opportunity cost to pay, but it's less for certain items, just that. Maybe my dependency on nanofiber vests is due a bad balance between weapons damage curve and units hp and hp increase, maybe with another setup I'll always pick grenade over nanofiber as I did in vanilla... but again, with only 1 inventory slot I may pick grenade, with 2 slots I may pick 2 grenades, but 3 slots or + it's unlikely I'll pick 3 grnades and no nanofiber vest.

 

- wasting resources: it may happen, as it happened to me, that I got a mission and the one before went bad, so this time I decided to equip my soldiers well each with nanofiber and grenade, and also a medikit and a smoke grenade in the squad... and it turned out there was only 4 sectoids in the map... 2-3 turns and ~80$ gone! I still got split feelings about that... in this case I kind of deserved it, I knew the mission was tagged "Easy" and it was by the beginning of the game, I was fearing that thin men could show up but they didn't, oh well, my fault. But as the game preogresses and it gets harder it's kinda the choice of wether equipping your soldiers or not doing so is gone, specially considering the monthly budget always increase and prices goes down. I haven't gone that far in my playtests, I'm expecting by that time the choice will be either equipping nanofiber vest or chiting plating if available, or alien grenades instead of regular frag grenades.

 

All in all, I'll keep playtesting this setup for a while, it quite changes a few dynamics of the game I've still to get used to, like planning monthly investments considering combat needs. Next thing I want to try is making consumible items are spent only if used, I def think it'll improve the overall effect (less equipping, less building, cheapper). I was planning to remove items once used right after they're used, in the middle of the battle, and removing armor vests if the soldier gets hit ... it may be fun to see what happen with those extra hp if a soldier gets the armor vest removed in the middle of the tactical game... hopefuly we'll see that soon

Edited by anUser
Link to comment
Share on other sites

@anUser -- I have a question for you regarding consumable items and charges.

 

For some things it's pretty clear, like if one frag grenade gives you one charge, then each charge used would consume one frag grenade at the end of the mission.

 

However, some situations aresn't quite so clear. What about if a Support with "Field Medic" uses 1 or 2 charges of a medikit? Is the item consumed, or not? How about if a soldier with Grenadier uses up 1 charge? If you make grenadier use up 2 grenades from STORAGE when you equip, then that ability becomes FAR FAR less valuable than something like "Deep Pockets".

 

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

 

There are a couple of possibilities that have been floating around in the back of my mind about how to get consumable items working.

 

1) Change the "claim system" used in STORAGE. Instead of leaving the item count in STORAGE and incrementing the "claimed" counter, when equipping a soldier entirely remove the item from STORAGE. Then when the soldier comes back from a mission, her items would be transferred back to STORAGE as appropriate:

a) if unwounded, she would simply keep the equipped items and STORAGE would not be altered

b) if wounded, UnloadSoldier would decrement the soldier inventory and increment STORAGE

c) if dead, but not MIA, UnloadSoldier would do the same as b)

d) if MIA, item consumed or destroyed, the item is simply destroyed in the soldier's inventory in the tactical game. There would be no other 'copy' of the item to garbage collect.

 

2) Double the size of the artifacts dynamic array being passed back to the tactical game (from 195 to 390).

a) Each time an item is "lost" in the tactical game, the array entry from 196 to 390 (i.e. 195 + item ID) is incremented.

b) When Unloading soldiers, for each element of the upper half of the array that is non-zero, decrement the permanent amount kept in STORAGE

pseudocode for this would be something like:

for itemID = 196 to 310

{

if (arrArtifacts[itemID] > 0)

{

STORAGE().arrItems[itemID-195] -= arrArtifacts[itemID];

}

}

Link to comment
Share on other sites

 

@anUser -- I have a question for you regarding consumable items and charges.

For some things it's pretty clear, like if one frag grenade gives you one charge, then each charge used would consume one frag grenade at the end of the mission.

However, some situations aresn't quite so clear. What about if a Support with "Field Medic" uses 1 or 2 charges of a medikit? Is the item consumed, or not? How about if a soldier with Grenadier uses up 1 charge? If you make grenadier use up 2 grenades from STORAGE when you equip, then that ability becomes FAR FAR less valuable than something like "Deep Pockets".

Ideally, since this would be combined with more inventory slots there would be no need to fake item charges, each equipped items would grant exactly 1 charge, and those abilities like grenadier, smoke and mirrors, etc could perfectly dissappear. Boosts would be dense smoke, saviour, danger zone, etc. Lately I've been pondering the possibility of giving perk-related free items as you suggested in the techs post, such as making grenadier grants 1 extra completely free grenade charge, that wouldn't even need an item or anything (so completely appart from inventory stuff). Field medic could grant 1 free medikit, smoke & mirros 1 free smoke grenade, rocketeer 1 free rocket... the problem about this is as I've said above about the loss of opportunity cost, if you'd have an assault soldier that always carry a free grenade maybe you'd choose to equip it with something else, like an armor vest. It should be carefuly balanced with the rest of the perks as well.

 

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

There are a couple of possibilities that have been floating around in the back of my mind about how to get consumable items working.

 

1) Change the "claim system" used in STORAGE. Instead of leaving the item count in STORAGE and incrementing the "claimed" counter, when equipping a soldier entirely remove the item from STORAGE. Then when the soldier comes back from a mission, her items would be transferred back to STORAGE as appropriate:

a) if unwounded, she would simply keep the equipped items and STORAGE would not be altered

b) if wounded, UnloadSoldier would decrement the soldier inventory and increment STORAGE

c) if dead, but not MIA, UnloadSoldier would do the same as b)

d) if MIA, item consumed or destroyed, the item is simply destroyed in the soldier's inventory in the tactical game. There would be no other 'copy' of the item to garbage collect.

 

2) Double the size of the artifacts dynamic array being passed back to the tactical game (from 195 to 390).

a) Each time an item is "lost" in the tactical game, the array entry from 196 to 390 (i.e. 195 + item ID) is incremented.

b) When Unloading soldiers, for each element of the upper half of the array that is non-zero, decrement the permanent amount kept in STORAGE

pseudocode for this would be something like:

for itemID = 196 to 310

{

if (arrArtifacts[itemID] > 0)

{

STORAGE().arrItems[itemID-195] -= arrArtifacts[itemID];

}

}

The problem in both is that using the items doesn't affect at all soldier's inventory (that's precisely what I try to change). So no matter if the items are removed from storage, like in #1, or if you substract the equipped items from storage... this would work for removing all the items, which has already been done. The problem is checking many, many kSoldier.kInventory[85] against "custom" variables (m_iFragGrenades, etc) that aren't stored in any array whose index could match inventory array. So we can't just loop through inventory on mission completing, since it isn't enough to know what item is in each slot, we need to know the number of each of those items so we can substract the right value from storage.

 

I guess it could be something like:

 

var1 = 0;    // (grnades)
var2 = 0;    // smoke gren
var3 = 0;    // alien gren
var4 = 0;    // battescanner
var5 = 0;    // medikit
var6 = 0;

foreach (Soldier.Inventory.SmallItem as item) {
    switch (item.type) {
        case 85:
            var1++;
            if (var1 > iFragGrenadeCharges) {
                releaseItem(item, soldier)
                removeItem(item, 1);
                soldier.Inventory.SetItem(0, inventorySlot)
            }
        case 88:
            var3++;
            
and so on...
but that needs a long function after mission finish, and it's still unclear to me how to access those XGUnit variables (m_iFragGrenades, etc) from the strategy game, I've got to give it another look
Link to comment
Share on other sites

Oh, no, you'd update the soldier's inventory from the tactical game, for sure.

 

I was thinking more along the lines of building a small helper function to remove a particular item ID from inventory, and then calling that as a side effect of decrementing the item charge. That all happens in XGAbilityTree.ApplyActionCost. This is a big function, so it's likely to have space to add the calls necessary. It's also the natural place to add this (as losing an inventory item is truly a "cost" of using the ability).

 

For Battlescanners, say, it would be something like changing:

 

if(kAbility.GetType() == 71)
{
if(!kAbility.m_kUnit.m_bInfiniteGrenades)
{
kAbility.m_kUnit.SetBattleScannerCharges(kAbility.m_kUnit.GetBattleScannerCharges() - 1);
}
}
to:
if(kAbility.GetType() == 71)
{
kAbility.m_kUnit.SetBattleScannerCharges(kAbility.m_kUnit.GetBattleScannerCharges() - 1);
RemoveItem(eItem_BattleScanner);
}
To remove the item, you'd have to loop through the m_kUnit.m_kCharacter.m_kChar.m_kInventory.arrSmallItems[itemID] and find the one that matches, then remove it and decrement m_kUnit.m_kCharacter.m_kChar.m_kInventory.iNumSmallItems. The m_kChar variable is of type TCharacter.
The TCharacter data stored for each XGUnit is automatically copied back to the strategy game and put into a TCharacter data structure in XGStrategySoldier (this is how the perk data is getting back also). This would provide the inventory information modified in the tactical game back to the strategy game.
However, this requires altering the loadout mechanics -- the "claiming" system has to be removed, as described above. Items still in the kStrategySoldier.m_kChar.m_kInventory after the mission is complete have to be converted back into STORAGE or kept equipped to the soldier.
Edited by Amineri
Link to comment
Share on other sites

ohh man last day I was checking all the XGAbility and XGAction... I forgot about ability_tree... indeed that's it's natural place.

 

From my experience removing bunchs of items from inventory the following calls are enough to remove items completely and safely:

STORAGE().ReleaseItem(eItem, kSoldier);
STORAGE().RemoveItem(eItem, 1);
TACTICAL().TInventorySmallItemsSetItem(kSoldier.m_kChar.kInventory, I, 0);

 

that STORAGE() I just made it up, I think I've seen it somewhere, it would be a matter of finding the correct call.

 

So all this information is available at that moment except inventory slot number... hence that you suggested looping through the inventory I guess... but maybe we're lucky and there's some way to get the slot number right there. I was checking now XGInventory has a function called HasItemOfType, which calls native function FindItemByEnum, and returns that != none, so maybe if we are lucky that native function returns the inventory slot index, so the whole operation can be done there, and thus eliminating the need to rework the whole item claim system.

 

If that can be done it seems there might be enough space to code it all, now I see there's a big chunck of the code I already removed, I guess that'd be some ISCONTROLLED block, also reworking those if else into a switch can save a few bytes, and those kAbility.m_kUnit.SetFragGrenades(kAbility.m_kUnit.GetFragGrenades() - 1); could be changed to kAbility.m_kUnit.iFragGrenade -= 1;

Edited by anUser
Link to comment
Share on other sites

The STORAGE() calls are all only available in the strategy game, and so aren't available from the tactical game at all. They also don't modify individual soldier inventory.

 

The TInventorySmallItemsSetItem(...) is a good call though. I knew there were some functions like it, but I just couldn't find them last night.

 

Another option is:

TInventorySmallItemsRemoveItem(...)

native static final function int TInventorySmallItemsRemoveItem(out TInventory kInventory, int iItem);

 

Both of these are native functions defined in XGTacticalGameCoreNativeBase (in XcomGame.upk), so are callable but not modifiable. The trick is going to be removing exactly one item. The function above _might_ do that, but the code for it can't be peeked at, so it has to be verified via experimentation.

 

The other fun part will be building these function calls in the tactical game. The SetItem function is only every called from the strategy game, while the RemoveItem call is never called from either tactical or strategy games. The call to a function in one upk is completely unrelated to the call from another.

 

The XGInventory class appears to be mostly about managing inventory with respect to visual appearance on the unit pawn, and less about the full inventory. Many items in the TInventory are not kept in XGInventory.

 

Also, the information kept in XGInventory is not sent back to the strategy game. Ultimately it's the TInventory structure kInventory stored in the TCharacter structure that has to be modified.

 

XGUnitNativeBase >> XGCharacter >> TCharacter >> TInventory

m_kunit.m_kcharacter.m_kchar.kInventory

 

The TCharacter and TInventory structures are defined in XGTacticalGameCoreNativeBase.

 

TInventory is defined as:

struct native TInventory
{
var int iArmor;
var int iPistol;
var const int arrLargeItems[16];
var const int iNumLargeItems;
var const int arrSmallItems[16];
var const int iNumSmallItems;
var const int arrCustomItems[16];
var const int iNumCustomItems;

 

 

The TCharacter and TInventory structures are defined in XGTacticalGameCoreNativeBase.

---------------------------------------------------------------
The are two distinct parts to this change:
1) Making the change on the tactical side (XcomGame.upk) to remove items from the unit's TInventory when an item charge is used
2) Making the change on the strategy side (XomStrategyGame.upk) to remove the claim system
a) When item is equipped, remove item from STORAGE
b) When soldier is unloaded, add item to STORAGE
Link to comment
Share on other sites

So, I finally am giving up (for now at least) on getting a working scrollbar in the Soldier Loadout Inventory. I've tried about 8 different things, and have written significant portions of actionscript code, all to no avail.

 

I did make some progress on my fall back position, which was to simply squeeze things together in order to fit the third small item fully into view.

 

Behold my progress:

http://wiki.tesnexus.com/images/0/0d/Three_Small_Item_Inventory_Screen.jpg

 

 

This was actually a very simple change. I merely changed the padding value from 5 to -5.

 

The hex code change is almost embarassingly simple. The change is applied to Command1.upk

 

hex before:

96 09 00 04 01 08 02 07 05 00 00 00

 

hex after:

96 09 00 04 01 08 02 07 FB FF FF FF

 

Really and truly, this is it. And I checked ... the before and after hex codes are unique within Command1.upk.

 

The decompiled actionscript code changes

from:

 

function InventoryList()
{
super();
this.padding=5;
}
to:
function InventoryList()
{
super();
this.padding=-5;
}
I'm going to give up on adding a scrollbar, and move onto other projects now :smile:

 

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

 

P.S. You may notice some additional perks active on this soldier -- this is the save game I was using to test out new perks.

 

The "?" perk is "ReadyForAnything" (lets soldier enter Overwatch after firing if the soldier didn't move and aliens are in sight)

 

And the Bombard perk was working too ^_^

 

But clearly the perk UI window wasn't designed for 11+ perks

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.

×
×
  • Create New...