Inventory items that increase stats when equipped

So I’ve made my inventory system but now I actually want players to be able to equip certain items (armor, trinkets, weapons, etc):

[b]Inventory[/b]
*if leatherarmor =1
	leather armor, 
*if leatherarmor =2
	[i]leather armor[/i]
	*set dr +2

1 means that the item is in the player’s possession, 2 means that the item is equipped. (dr is damage reduction)

The problem is that when the item is equipped the stats increase as they should, but as soon as I go to the next page the stats keep increasing.

Ex: gained the armor, equipped it, dr =2
I progress the game by clicking “Next”, when I check the stats dr =4

Is there a way to make the stats increase only once when equipped, then decrease once the item is unequipped (when its value is 1 instead of 2) or do I have to manually increase/decrease them.

Checked a lot of topics and wiki articles but I couldn’t find anything.

Do you put that code inside a subroutine?

Only way I can think of is making two subroutines, one that increases the stat and one that decreases it, then running the appropiate one whenever the item is equipped/unequipped.

EDIT: Or, you can make a subroutine you use everytime you check a stat, that calculate all the possible bonuses.

Make sure to always reset the DR before equipping an armor (reset it to 0) and then add all the armor values to it.

For example whenever the player leaves the inventory screen, run a subroutine to set all the armor values correctly; resetting them to 0 and then summing up all the armor components and setting it to the DR.

*label equip_armor

*set dr 0

*if (has_helmet)
	*set dr + 2
*if (has_shoulder_pads)
	*set dr + 1
*if (has_leggings)
	*set dr + 3
*if (has_armor)
	*set dr + 4

*return
1 Like

I haven’t used any subrutines at all.

Yes but I want it to work for stats as well, do I have to save said stats in a separate variable and basically do the same thing but with that variable?

Well I’d have to see your code to understand exactly what you’re trying to do, but it’s better if you leave separate variables for stuff you are gonna use in battle. For example if you split stats for the player and for the armor and then sum them up together. Let’s say player has like 8 endurance and half of that is used as DR, while the armor has 2 DR.

*set dr 0
*set dr + (endurance/2)
*if (has_helmet)
	*set dr +2
.
.
.

And say you want to calculate the possible attacking power of the player, based on their strength and equipped weapon.

*set attack_rating strength + equipped_weapon

Then you would use the attack_rating on the damage calculation, but you would need to run these scripts everytime there is a change to them (either because the player leveled up or changed weapon) so a subroutine is useful for that.

A subroutine (*gosub) is something the code goes to and then comes back to where it was called once it reaches a *return. We could have this variables updater in one nifty spot and call it when needed. Suppose we want to have this:

*label update_stats

*set attack_rating strength + equipped_weapon
*set dr 0
*set dr + (endurance/2)

*if (has_helmet)
	*set dr + 2
*if (has_shoulder_pads)
	*set dr + 1
*if (has_leggings)
	*set dr + 3
*if (has_armor)
	*set dr + 4

*return

This would be something that would always update the Attack_rating to be based on the player’s strength, equipped weapon and in the case of DR to be based on half the endurance and the gear they have equipped. Since it’s something we would use whenever we want the items to have an effect, we can run it easily by calling the *gosub.

*gosub update_stats

And it will run that code and come back to where it was called; you could have this run after the player equips something to make sure the stats are updated.

*label helmet_on_ground

There is a helmet on the ground.

*choice
	#Proceed down the hallway.
		*goto hallway
	*if (has_helmet = false) #Equip the helmet.
		*set has_helmet true
		*gosub update_stats
		*goto helmet_on_ground
	*if (has_helmet) #Unequip the helmet.
		*set has_helmet false
		*gosub update_stats
		*goto helmet_on_ground

Here for example you can either equip this helmet or unequip it. After you pick any of them, the code will go into the gosub to redefine your DR. It will start by resetting it to 0 and checking if the helmet is equipped, if it is, it will add +2 to your DR. Even if you pick up or remove the helmet multiple times, your DR will still be at max 2 (without taking endurance into account).

I imagine on your example the problem is that if you just kept going to the inventory and re-equipping it would keep summing it by +2 without resetting it to 0 before? If you could post your code we could check if that’s the problem.


I’m not sure if this is what you meant? If you show some of the code and explain in more detail what you want to do we can help more.

1 Like

@Scrido this may not make much sense, but if you take the time to research how to implement subroutines, parameters, and multireplace, here’s a super efficient way to do it.

The variable helmet_equipped refers to whether you’ve got the helmet equipped. The variable helmet refers to whether you have a helmet at all and isn’t that important but I figured I’d distinguish it anyway.

Inventory.

*fake_choice
  *if (helmet = true) # Helmet (@{helmet_equipped equipped|not equipped}).
    *gosub equip "helmet"
  # (etc for other items)

*finish

...

*label equip
*params

*if (param_1 = "helmet")
  *set helmet_equipped @{helmet_equipped false|true}
  *set DR @{helmet_equipped +2|-2}
  You @{helmet_equipped put your helmet on|take your helmet off}. Damage resistance @{helmet_equipped increased|decreased} by 2.

*return

And you add other blocks for different inventory items.

Only thing I’m not sure about is whether the multireplace to increase/decrease stats will work, but it’s more likely it’ll work than it won’t. If anyone finds a mistake let me know.

Basically the helmet option in your inventory both equips and unequip a your helmet. The game flips the true/false for whether you’ve got it equipped, then increases your DR by 2 if you’ve just now equipped it or decreases your DR by 2 if you’ve just now unequipped it.

EDIT: added a bit of code that tells you whether you have it equipped or not, plus some text that tells you what happens when you equip/unequip.

It may actually be possible to just use the same chunk of code for EVERY item you have, too! Give me a second and I’ll see what I can do.

Genuinely don’t know if this will work but here goes:

*gosub equip "helmet" 2

...

*label equip
*params

*if (${param_1}_equipped = true)
  *set ${param_1}_equipped false
  *set DR -${param_2}
  You unequip your ${param_1}. Damage resistance decreased by ${param_2}.
*if (${param_1}_equipped = false)
  *set ${param_1}_equipped true
  *set DR +${param_2}
  You equip your ${param_1}. Damage resistance increased by ${param_2}.

*return

UPDATE: This won’t work because of a weird quirk with multireplace and using the words true/false or +x/-x, but you could modify it to work just with *if statements instead, albeit with much clunkier code.

Wait no I’m dumb, this actually doesn’t have any multireplace in it! So I don’t see why it wouldn’t work!

(feel free to PM me reasons why it wouldn’t work)

2 Likes

So I’ve been tinkering a bit with your method, but all I get is

subs line 5: Invalid expression, couldn’t extract another token: @{agiring_equipped false|true}

code in subs.txt

*label equip

*params
*if param_1 ="agiring"
	*set agiring_equipped @{agiring_equipped false|true}
	*set agility  @{agiring_equipped +2|-2]
	
*return

code in game txt

*gosub_scene subs equip "agiring"
You spot something shining in the fireplace however, you walk over and pick up a ring, it has a green hue to it, interesting oddity. You put it on and feel yourself lighter on your feet.
*if show =1
	*line_break
	<Green ring +1>
*set agiring 1

agiring_equipped is declared in startup.txt as false.

There might be more than one problem. Let me have a look at your code.

@{agiring_equipped +2|-2]

You’ve used a square brace here: ] instead of a curly brace: }

*if param_1 ="agiring"

I’m not 100% sure but I’m reasonably certain that you need brackets here: *if (param_1 = "agiring"). I find that I get errors otherwise, though I think I’ve seen people get away with not using them? Anyway.

testing this stuff myself

Yup, getting the same error. Tried out @{agiring_equipped lorem ipsum|delor sit amun} and that worked fine, so I think it’s actually having trouble parsing “true” and “false” as outputted string from a multireplace. No idea that would happen!

It also happens with the +2/-2 stuff because it thinks you’re trying to modify the base values rather than outputting a string which can then be parsed as code. I was too ambitious with my use of multireplace! It doesn’t quite work as intuitively as I had hoped.

Try this instead:

*if (param_1 = "agiring")
  *if (agiring_equipped = true)
    *set agiring_equipped false
    *set agility -2
    *return
  *if (agiring_equipped = false)
    *set agiring_equipped true
    *set agility +2
    *return

It’s chunkier and less elegant but it actually works, instead of not working, which is always better than not working.

1 Like

That’s perfect, now I only have to write about 20-30 more items hah.

Thank you!

If you want, there’s something else you can do to go with what @will posted above. By using arrays you can define items and their stats so you don’t have to set them when calling the *gosub.

Let’s assume each armor will have a name, DR, price, a boolean to represent if it’s equipped or not and another boolean to represent if the item was acquired or not (either found or bought from a shop for example).

*create armors_1_1 "Leather Helmet"
*create armors_1_2 2
*create armors_1_3 100
*create armors_1_4 false
*create armors_1_5 false

*create armors_2_1 "Leather Gauntlets"
*create armors_2_2 1
*create armors_2_3 50
*create armors_2_4 false
*create armors_2_5 false

So what we have is a two dimensional array (like a table); the first bracket will be the ID of the item (either 1 for helmet or 2 for gauntlets) while the second bracket is the attribute (either 1 for name, 2 for the DR or 3 for the price).

Suppose we wanted to display the price of the leather gauntlets, we would use ${armors[2][3]} since we are looking at ID 2 (the gauntlet) and attribute 3 (the price). In the end, what would be displayed would be 50.

So that we don’t need to remember the numbers of each, we can assign some simple variables.

*create id_helmet 1
*create id_gauntlet 2

*create item_name 1
*create item_dr 2
*create item_price 3
*create item_equipped 4
*create item_acquired 5

These will make it simple so we don’t have to remember which number is what. To use the same example again, trying to display the leather gauntlets price, now we could say it as: ${armors[id_gauntlet][item_price]} which would be the same as ${armors[2][3]} like before; this is just a way so you don’t have to remember which number is what.

So applying this to @will’s example, you could have the subroutine very similar and have it take the values from the array instead of you always having to type it in when calling the *gosub.

*gosub equip id_helmet

...

*label equip
*params

You @{armors[param_1][item_equipped] remove|equip} your ${armors[param_1][item_name]}, @{armors[param_1][item_equipped] reducing|increasing} your damage resistance by ${armors[param_1][item_dr]}.

*if (armors[param_1][item_equipped] = true)
  *set armors[param_1][item_equipped] false
  *set DR - armors[param_1][item_dr]
*else
  *set armors[param_1][item_equipped] true
  *set DR + armors[param_1][item_dr]

*return

So when you make an inventory screen to the player, you can show them only what item they have acquired.

*label inventory_screen

Current DR: ${DR}.

*choice
	*if (armors[id_helmet][item_acquired]) #@{armors[id_helmet][item_equipped] Remove|Equip} the helmet.
		*gosub equip id_helmet
		*goto inventory_screen
	*if (armors[id_gauntlet][item_acquired]) #@{armors[id_gauntlet][item_equipped] Remove|Equip} the gauntlets.
		*gosub equip id_gauntlet
		*goto inventory_screen
	#Go back.
		*return

This will let you do all the things by simply sending id_helmet or the id of whatever item you want the equip *gosub to run.

This also simplifies you making any sort of shop. Here is a way to make one subroutine for any armor you want to sell.

*label shop_screen

"So, gonna buy anything?"

*choice
	*if (armors[id_helmet][item_acquired] = false) #"Show me the helmet."
		*gosub shop id_helmet
		*goto shop_screen
	*if (armors[id_gauntlets][item_acquired] = false) #"Let me take a look at the gauntlets."
		*gosub shop id_gauntlets
		*goto shop_screen
	#Leave the shop.
		*return

..........................

*gosub shop
*params

"Sure, have a look."

The ${armors[param_1][item_name]} provides ${armors[param_1][item_dr]} points of damage resistance; it costs ${armors[param_1][item_price]} gold.

*fake_choice
	*selectable_if (player_gold >= armors[param_1][item_price]) #Buy the ${armors[param_1][item_name]}. (${armors[param_1][item_price]} gold)
		*set player_money - armors[param_1][item_price]
		*set armors[param_1][item_acquired] true
		The shopkeeper packs the ${armors[param_1][item_name]} and hands it to you. "Thanks for the purchase!"
	#Go back.

*return

You could use *set armors[param_1][item_acquired] true for items you find on the ground at any time too. About the ring thing you could edit the equip *gosub to have similar effects into your attributes or just make other *gosubs to handle that too.

Here’s more info on the @{} (multireplace).

1 Like

This topic was automatically closed 24 hours after the last reply. If you want to reopen your WiP, contact the @moderators.