Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Making an Inventory system that affects Stats (carryweight etc)

Hey to all!
This is a discussion to see what ways others can think around this particular problem.

I want to make an inventory of multiple items that all have a carry-weight
Equipped items affect stats (EG, weapons increase DAM etc)
I also want the option to discard said items and use them when needed (making camp at night etc)

Some items are easy.
Having the bedroll will activate the 'just sleep here' button that progresses the clock 8 hrs, triggers the 'time past 24' event etc...

I am struggling a little with how to have the character carrying 5 health potions, each weighing 1.

I'm probably being too ambitious, but I can't be the only one trying to get my head around this!

(Using Sugarcane in Twine 1.4.2 but am content to use any other build format)

Also, for anyone just wanting an inventory system, I uncovered this: https://strugglingwithtwine.blogspot.co.uk/2014/03/handling-inventory.html?showComment=1483911375627#c3406710617839643496 I understand it takes a little shoe-horning, but I think it might work... but it won't do what I want to here.

Comments

  • edited January 2017
    I created one for harlowe (twine 2.x) so assuming you want to redo all our work and learn a new format follow on

    first I want to know what do you want to accomplish because mine is maybe more complex than what you need

    do you want a shop system (which btw will take lots of time)

    what types of items do you want

    is there a limit to the inventory or is it an infinite black hole of items

    what stats do you want, what stats do you have in the game

    is a inventory system really useful to your situation by that I mean can you drop gear or is gear just replaced automatically

    if gear is just replaced all you need is a datamap

    for whatever reason you want to drop gear or get gear out of loot you need an inventory system

    is loot luck based or is it a specific item

    does gear stack,if so how much does each item stack

    I can't help if you're being too damn vague
  • edited January 2017
    [EDIT] I can't use twine 2 because I can't see anything on it.
    I'm colourblind and anything on a blue background is impossible to see
    Stuffed that up.

    No shop. This will be loot-based only
    Items are in four categories: Weapon. Armour. Food. Water. (and coins, but they'll be easy enough to track with a +1 variable)
    There will be a limit. To avoid the game getting too easy. Each item will be balanced to match the biome it'll be found in.
    Current stats are: Strength, Agility, Stealth, Inteligence, Ingenuity ,Endurance, Luck, Carry, Damage, S-Damage, Defence, S-Defence, Critical, Hands.
    An inventory system would be very useful for the carried items, but weapons and armour can be replaced as there's no need to waste your pocket-space on it.
    Loot is luck-based
    Gear will stack as high as the carry-weight allows (up for discussion). Want to carry nothing but healing potions and your gear, sure.

    I didn't want to throw all the particulars of my game out when I don't know what information is relevant. I didn't mention a shop anywhere and unless asked, I wouldn't have even thought about it.
  • general tips (since there's no harlowe in twine 1.x wish I could actually help)

    1.reduce the amount of stats it's a bit too much I have no idea what hands could be, neither do I know the difference between strength/damage,intelligence/ingenuity, endurance/defense, as a player I would not like a game that's too complicated look at popular sandbox games (I am assuming your making a sandbox game) like Don't starve or minecraft they have about 3-4 stats even most mmorpgs/rpgs don't have that much

    2.maybe you can upgrade/enchant your equipment to get specific stats that you're looking for

    good luck it's unfortunate that I couldn't be of help
  • Some of it might be simplest is your base item was a stack, not a single item. So a healing potion would be a stack of 1 healing potion. You'd store the attributes of single items in the base of the stack and use a widget (assuming you're using Sugarcane 2 with 1.4.2) to recalculate the total attributes of the stack:

    healing_potion: { tag: 'Healing Potion',
    single: [ 1, 0, 0, 0 ,0 ,0 ]
    count: 3,
    total: [ 3, 0, 0, 0, 0, 0] }

    The total array is simply the single array multiplied by the count. To total your inventory you just need to add all the individual total arrays together.

    The tag is used to locate objects when moving some of them to a new location. If you can find a stack of the object in the new location, simply adjust the counts and retotal each stack. If a stack ends up with 0 count, destroy it (but watch clone vs pointer - set $a to $b simply makes $a point at $b, you need set $a to clone($b) to get a new a object that is independent of the $b object. ) If you can't find an existing stack in the new destination, you'll need to create a new one (i.e. the first time you pick up a healing potion).

    You might be able to save some memory with a 'type' value that points to an entry in a master single array, but that makes things a bit more complicated.
  • mykael wrote: »
    […] use a widget (assuming you're using Sugarcane 2 with 1.4.2) […]
    (emphasis mine) No such story format exists. You're confusing Sugarcane—included with Twine 1.4.2, no longer actively developed—with SugarCube. The OP claims to be using Sugarcane.
  • I'm still new to all this, been using Harlowe and SugarCube (focusing more on SC because it seems more powerful), but I'd like to throw in my input. I'll say this, without going into javascript functions and/or using SugarCube's widget system, you're gonna have a hellova time keeping things neat, clean, and usable. I'm currently looking into better ways of utilizing datamaps or any key-value structure so I can create complex objects (like items) on the fly. The difficult part is creating the functions that play nicely with them and Twine script. I've spent 95% of my time just researching how to make custom Javascript functions work, and JS was my first language.

    When I first played around with Harlowe I used a ton of flag variables (basically just booleans) to act as inventory and item system, and it was hell. I definitely suggest looking into compartmentalizing your code as much as possible.

    Ultimately, though, I don't think it's wise to attempt something as complex as an Inventory in Harlowe. I don't particularly care for SugarCube's format, and I like the color highlighting on Harlowe, but it just doesn't have the same fundamental power that SugarCube does.

    Hope that helps a little.
  • mykael wrote: »
    […] use a widget (assuming you're using Sugarcane 2 with 1.4.2) […]
    (emphasis mine) No such story format exists. You're confusing Sugarcane—included with Twine 1.4.2, no longer actively developed—with SugarCube. The OP claims to be using Sugarcane.

    Sorry, I meant Sugarcube - which is a much better place to start a major project from.
  • I'm in the same battle. My inventory system relies on item weight, number of items and "body slots", like hands, chest, etc. I made it work, including drop/equip and stats effect, but the inventory brakes after a load from save.

    It would be great to see a "pro" solution or framework about it...
  • edited June 2017
    It seems you have your work cut out for you. I'm also in the process of implementing an inventory. This one supports multiple items that can be used at the same time. The items can be affected by the character (when you hit an enemy, it's blood will stay on the sword for example) and vice-versa when the item is being used (for example: casting a spell from a magic wand that has limited use). Items can affect other items (for instance: the magic wand can be recharged using a magic stone). If you have two wands, then you'll start to use up one of the wands before switching to the other one that is still charged. The same way if one of your swords has dragon blood on it, it will be treated as an enchanted sword and will not "pile up" with your other swords of the same kind (otherwise all of the other swords would be affected by the blood).

    I've been developing this inventory system for weeks now and only starting testing it recently. I need to say the design phase and the prototyping was a bit mind bending. Now, I'm thinking about automating some tests to keep all the mechanics and the inventory system in check (since it's internals are fairly complicated and surprisingly hard to test).

    I wish I came up with an easier solution :cold_sweat:

    I recommend you try and design your inventory system on pen and paper first. Think about ALL the things your items can do and can affect. Think about the possibility of other NPCs manipulating your inventory and vice-versa There are so many things that need to be considered before starting to implement an inventory system for a game. I only recently learned this the hard way :tired_face:
  • edited June 2017
    Using Twine 2.1.3 and Sugarcube 2.18.0

    I just started dabbling with both Twine and coding in general, but unless I am missing something, this doesn't seem too complicated to do.

    I just created an inventory system and a little shop system to try it out. First we set up our items and a few other things in StoryInit:
    <<set $iron_sword = {
    "name": "Iron Sword",
    "weight": 30,
    "cost": 50
    }>>
    
    <<set $steel_armor = {
    "name": "Steel Armor",
    "weight": 55,
    "cost": 100
    }>>
    
    <<set $hpotion = {
    "name": "Healing Potion",
    "weight": 2,
    "cost": 10
    }>>
    
    <<set $store = {
    "inventory": [3, 2, 5]
    }>>
    
    <<set $player = {
    "inventory": [0, 0, 0],
    "gold": 100,
    "strength": 5
    }>>
    
    <<set $weight = 0>>
    <<set $items to [$iron_sword, $steel_armor, $hpotion]>>
    


    Then we create a widget to easier manage the games behaviour for when the player is carrying too much:
    @
    <<else>>
    [[$args[0]|$args[1]]]
    <</if>>
    
    <</nobr>><</widget>>
    

    Then we set up the "store" passage to test out our inventory system:
    You are standing in a store. You have $player.gold gold.
    
    
    Buy:
    <<nobr>>
    <<for _i to 0; _i lt $items.length; _i++>>
    	<<if $store.inventory[_i] > 0>>
    		$items[_i].name ($items[_i].cost gold) *$store.inventory[_i]:
    		<<if $player.gold >= $items[_i].cost>>
    			<<capture _i>>
    			 [[Buy|store][$player.inventory[_i] += 1, $store.inventory[_i] -= 1, $player.gold -= $items[_i].cost]]
    			<</capture>>
    		<<else>>
    			You can't afford this.
    		<</if>>
    		<br>
    	<</if>>
    <</for>>
    <</nobr>>
    
    Sell:
    <<nobr>>
    <<for _i to 0; _i lt $items.length; _i++>>
    	<<if $player.inventory[_i] > 0>>
    		$items[_i].name ($items[_i].cost gold) *$player.inventory[_i]:
    			<<capture _i>>
    			 [[Sell|store][$store.inventory[_i] += 1, $player.inventory[_i] -= 1, $player.gold += $items[_i].cost]]
    			<</capture>>
    		<br>
    	<</if>>
    <</for>>
    <</nobr>>
    
    <<go "Leave the store" "passage name">>
    


    Obviously this is all still very raw and we might want to add a lot more features to it, but adding things won't take a lot of effort from here on out and I think this shows how both an inventory system as well as a shop system can be set up very quickly and effortlessly.
  • edited June 2017
    idling wrote: »
    I think this shows how both an inventory system as well as a shop system can be set up very quickly and effortlessly.
    Its a good start, but the code can quickly become complex and very bespoke.

    eg.
    1. You are allowing the player to buy items that they may not be able to carry.

    2. What happens if there is more than a single shop, or different types of shops.

    3. What happens if an item can be used multiple times.
    eg a potion with more than a single dosage, which is different to multiple potions.

    4. What happens if there are containers that can contain other items.
    eg. placing a small sack/bag containing items within a backpack.

    5. What happens if items can degrade and eventually become unusable.

    6. What happens if items can be combined together to make other items, and how do you track which items can be combined together.

    Basically, a 'standard' inventory system does not really exist because the potential feature list required changes from game to game.

    NOTE: Because the 'values' of each of your items in your implementation don't change it would be better to store those items within the setup object instead of within story variables, although the inventory content related arrays themselves will need to remain story variables.

    The reason to store the items in setup is because the state of all known story variables is 'cloned' each you passage traversal occurs, the original states are associated with the passage being left and stored within the History System, and the 'copy' is made available to the next passage. This process can consume memory quickly If you have many unchanging story variable values in your story, like the possible items in your example.
  • edited June 2017
    greyelf wrote: »
    NOTE: Because the 'values' of each of your items in your implementation don't change it would be better to store those items within the setup object instead of within story variables, although the inventory content related arrays themselves will need to remain story variables.

    The reason to store the items in setup is because the state of all known story variables is 'cloned' each you passage traversal occurs, the original states are associated with the passage being left and stored within the History System, and the 'copy' is made available to the next passage. This process can consume memory quickly If you have many unchanging story variable values in your story, like the possible items in your example.

    Oh thanks – I had read somewhere that variables that don't change should be stored elsewhere, but was always unclear where and why. This clears things up



    Like I said, most additions can be done quick and easy with this kind of setup. What will be complicated is problems number 4 and 5 you mention. Initially I wanted to make the Inventory system work by cloning a model objects, then adding the clone to the individual inventory arrays – I never started experimenting with clone() though, since I am unsure how to pop the clones and afraid the ever-growing stack of clones might eventually get a problem for the memory.
    Is there a way to create and pop clones?

    Most of the other problems you mentioned can be fixed quite quickly. I'm just quickly typing the possible solutions down, without an attempt of running them – sorry if there are any mistakes or typos in the code:

    1. Prevent Player from buying past their Carry Weight

    The player can currently buy as many items as they want, but if they are unable to carry the weight, they won't be able to move to another passage, thanks to our widget. If we'd want to prevent them from buying them in the first place, all we'd have to do is to alter the shop a little:
    <<set $weight = 0>>
    
    <<for _i to 0; _i lt $items.length; _i++>>
            <<set $weight += ($items[_i].weight * $player.inventory[_i])>>
    <</for>>
    
    Buy:
    <<nobr>>
    <<for _i to 0; _i lt $items.length; _i++>>
    	<<if $store.inventory[_i] > 0>>
    		$items[_i].name ($items[_i].cost gold) *$store.inventory[_i]:
    		<<if  $weight + items.[_i].weight > $player.strength * 10>>
    		You can't carry this much.
    		<<elseif $player.gold >= $items[_i].cost>>
                            <<capture _i>>
                             [[Buy|store][$player.inventory[_i] += 1, $store.inventory[_i] -= 1, $player.gold -= $items[_i].cost]]
                            <</capture>>
                    <<else>>
                            You can't afford this.
                    <</if>>
                    <br>
            <</if>>
    <</for>>
    <</nobr>>
    


    2.Multiple shops

    We can already add as many stores with different stocks to the game using the current setup. Then we can easily add further information to the stores to specify, what kind of items can be bought and sold there.
    <<set $store_smith = {
    “name”: “Smith”,
    "inventory": [3, 2, 0],
    “trade”: [1, 1, 0]
    }>>
    
    <<set $store_alchemist = {
    “name”: “Alchemist”,
    "inventory": [0, 0, 15],
    “trade”: [0, 0, 1]
    }>>
    
    
    Buy:
    <<nobr>>
    <<for _i to 0; _i lt $items.length; _i++>>
    	<<if $store_smith.inventory[_i] > 0 and $store_smith.trade[_i] === 1>>
    	...
    	<</if>>
    <</for>>
    

    3. Multiple Use Items

    If we want one “Healing Potion” to last four times, we can just have it decrease upon use by 0.25.
    [[Drink a Healing Potion|passage()][$player.hp += 10, $player.inventory[2] -= 0.25]]
    

    Then we only let them sell unused potions:
    Buy:
    <<nobr>>
    <<for _i to 0; _i lt $items.length; _i++>>
    	<<if $player.inventory[_i] >= 1 and $store_alchemist.trade[_i] === 1>>
    	$items[_i].name ($items[_i].cost gold) *<<print Math.floor($player.inventory[_i])>>:
    	...
    	<</if>>
    <</for>>
    


    4. Storage items:

    A single storage item can be easily created by adding an array to an object:
    <<set $backpack = {
    "name": "Backpack",
    "weight": 5,
    "cost": 30,
    “inventory”: [1, 0, 2]
    }>>
    
    Since we only have one actual backpack object however, we will run into problems, if our character has two backpacks with several different inventories. We could probably find a workaround by creating an array to store all this information: [[1, 0, 2], [3, 4, 1],...] - but I admit this is going to be annoying to set up.


    5. Degrading Weapons

    Like the storage containers below, this wouldn't be a problem, if we only had one instance of the object in question.
    <<set $brittle_sword = {
    "name": "Brittle Sword",
    "weight": 15,
    "cost": 10,
    “durable”:  5,
    “damage”: 3
    }>>
    
    <<if $brittle_sword.durable > 0>>
    [[Attack the Goblin|passage()][$goblin.hp -= $brittle_sword.damage, $brittle_sword.durable -= 1]]
    <<else>>
    Oh no! Your sword broke!
    <</if>>
    

    But as soon as we have multiple instances of the same object that are all supposed to be in different states of being worn off, we'd have to create another array, just as above.


    6. Something like combining items to form new items would not alter the proposed inventory system in any way. We can handle that with a something like a crafting widget, which removes used items from then adds one of the created items to our inventory. It's going to take a lot of work depending on how many things we'd like to be craftable, but that's just the nature of a crafting system and it it won't be complicated to build it.


  • @idling:
    Again some good answers.

    You could create a dummy copy of an empty 'item' and then clone it, or you could use an Javascript Object Constructor function like the one shown in the Using an Object Constructor section of this JavaScript Objects documentation to create different types of items.

    Another way to approach 'inventory' is to think of it as things (NPC's, Locations, Items, etc..) that than can act like containers, and that there are different types of containers (Personal, Bags, Shops, etc..).

    You could then use Passage Tags to mark some of the passages within your story as representing a Type of 'Thing' / Container, and have (more) generic background code that knows how to handle the storage and item transfer between each of the different types of container. You could do something similar (maybe not via passage tags) to mark items that have functionality (like the ability to combine) and have generic code that knows how to apply that functionality to marked items.

    eg. You could have passage tags/object markings representing things like:
    a. People that can equip items.
    b. Items that can be equipped.
    c. People that can carry items.
    d. Items that can be carried.
    e. People/Locations that can sell/buy items.
    f. Locations where items can be picked up/dropped.
    g. Containers that can contain other Containers.
    h. Containers that can be contained within another.
    i. etc....

    For instance what happens if the Player drops a Bag from their Backpack onto the floor of a Location? Does it disappear into the Void or is it there next time the Player passes by, and if its there then what happens if a wandering monster (that can carry things) travels through that location?

    These are the types of things that the developers of MUD's / MUSH's / MOO's engines potentially needed to solve when they created their frameworks/libraries.
  • There comes a point where it's simpler to download a copy of a MUD engine - there are quite a few out there, and they are almost all free than it is to try and persuade Twine to become something than it isn't. My own contributions are to CthulhuMud and the 16k Mud competition - both of which should be available for download. I'm sure some of the other contributors here have contributed to other MUDs over the years. Run the server locally with telnet client and you can use it for single player.

    Now, if I could use a twine like editor to build my MUD, that would be nice. OLE's a bit slow.
Sign In or Register to comment.