Warcraft III resources & community, 2003–2006 · archived

RDZ's Incredible Item Stacking System of Doom

10 posts
#1

RDZ's Incredible Item Stacking System of Doom

Item stacking is a nasty business. And since I've been grappling with it recently for my All-In-One Micro Map, I thought it good to pass on my findings in the form of a pleasant little tutorial.

What you need:
- Basic triggering knowledge
- Basic item editing knowledge

For your stacking item, you need two items - a "runic" one (Stats - Use Automatically When Acquired = True) and a "non-runic" one (Stats - Use Automatically When Acquired = False). Now, the player will be interacting with both of these in slightly different ways, so the same name is probably essential. However, the Item Editor lacks an "Editor - Suffix" field, so to avoid confusion give both versions different names and change them back when you're finished. Why? Well, with a runic item, even when your inventory is full, you'll still be able to stack.

Now, you can create a very simple item stacking system thus:

Stacking HealPotion
Events
Unit - A unit owned by Player 1 (Red) Acquires an item
Conditions
(Item-type of (Last created item)) Equal to Potion of Healing (Runic)
Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
((Hero manipulating item) has an item of type Potion of Healing (Non-Runic)) Equal to True
Then - Actions
Item - Set charges remaining in (Item carried by (Hero manipulating item) of type Potion of Healing (Non_Runic)) to ((Charges remaining in (Item carried by (Hero manipulating item) of type Potion of Healing(Non-Runic))) + 1)
Else - Actions
Hero - Create Potion of Healing (Non-Runic) and give it to (Hero manipulating item)


For those of you unable to read triggers outside the editor (like me), this fires when the hero picks the rune (which handily disappears), then checks to see if the hero has the inventory (non-runic) version of the potion. If he/she/it does have the non-runic potion, then add one charge to it, if not, then create a non-runic potion. Done. If you can't be bothered catering for acquisition of the non-runic version, the buck stops here. If you want a totally fool-proof system, keep reading.

So, what if the player has a full inventory and no non-runic potion to add to? We get a nice non-runic potion deposited on the ground. Oh oh. In the heat of battle, the hero might pick up the runic version somewhere else after dropping something, and later go back to that initially dropped non-runic potion - argh, we've got two stacks! This can be very nasty if you've dropped a large stack in a stash or backpack and forgotten about it, then built up a new stack. Maybe two heroes have two different stacks, and one wants to give its stack to the other - again, two large stacks. This might not happen too often, but it's an inconvenience for the poor player.

So we need something a little more complex. Note that in a multiplayer, or even multihero environment, you may need to resort to local variables and jass and all that madness. But we don't like that, so I'll stick to the easy version.

For this you will need two variables. These will hold the number of non-runic potions you have (I'll get to that later) and one to hold the number of charges in the newly acquired item. For this example: Item_TempPotionCount and Item_TempChargeCount.

First of all, the trigger must respond to an item being acquired. The item must be either of the two versions of the stackable item.

Potion Stacking Heal
Events
Unit - A unit owned by Player 1 (Red) Acquires an item
Conditions
Or - Any (Conditions) are true
Conditions
(Item-type of (Item being manipulated)) Equal to Potion of Healing (Runic)
(Item-type of (Item being manipulated)) Equal to Potion of Healing (Non-Runic)
Actions
...


Now, we get down to the hard-core bit.
We must make sure our temporary variables are reset to avoid spillage from previous trigger executions. At this stage, you'd be initialising your local variables.

Set Item_TempPotionCount = 0
Set Item_TempChargeCount = 0


Now, we must discover how many non-runic potions we have to decide what sort of stacking to do. This loop checks every inventory slot the hero has (NOTE: you can use "1 to Unit - Size of Inventory" for the loop condition if you're messing with many different heroes with different inventory sizes) for Potions of Healing that are Non-Runic. If it finds one, it adds 1 to the counter.

For each (Integer A) from 1 to 6, do (Actions)
Loop - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(Item-type of (Item carried by (Hero manipulating item) in slot (Integer A))) Equal to Potion of Healing
Then - Actions
Set Item_TempPotionCount = (Item_TempPotionCount + 1)
Else - Actions


So we know how many non-runic potions we have. This means we know what the hero has just acquired and what he/she/it already has. If we currently have 2 non-runic potions, then the hero has a stack and has picked up another one. So we take the number of charges in the new stack and remove it.

If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
Item_TempPotionCount Equal to 2
Then - Actions
Set Item_TempChargeCount = (Charges remaining in (Item being manipulated))
Item - Remove (Item being manipulated)
Else - Actions
...

Simple. Now, in that "else" section we must add another IF - if we have only one runic potion (the else section here houses what happens when we have 0 non-runic potions). And within this IF we need another one. Because here there is ambiguity - did the Hero acquire a rune and have a stack already, or did the hero have nothing and pick up a stack? Just check if he picked up a runic potion. If this is true, then set the number of charges. Leave this "else" section blank, because if you've just picked up a stack it's got all its charges.
And finally, if TempPotionCount is not 2 and it's not 1 either, it's 0. So we create a non-runic potion for the hero, and again leave TempChargeCount at 0.

If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
Item_TempPotionCount Equal to 1
Then - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(Item-type of (Item being manipulated)) Equal to Potion of Healing
Then - Actions
Set Item_TempChargeCount = (Charges remaining in (Item being manipulated))
Else - Actions
Else - Actions
Hero - Create Potion of Healing and give it to (Hero manipulating item)


And our last action is to add on the charges to the item we have. If you have just been given a new item or picked a stack, then TempChargeCount is 0; so 0 charges will be added to the item's default.

Item - Set charges remaining in (Item carried by (Hero manipulating item) of type Potion of Healing) to ((Charges remaining in (Item carried by (Hero manipulating item) of type Potion of Healing)) + Item_TempChargeCount)

So there you go. A simpler-than-it-looks way of stacking items that accounts for all eventualities. Just in case all that passed you by, here's a simple algorithm anybody should be able to understand without my rambling:

0. Initialise variables: TempPotionCount and TempChargeCount to 0.
1. Establish how many non-runic potions we have in the hero's inventory.
2. If we have 2, we've picked a stack while we have a stack - set charges and remove the picked item.
3. If we have 1,
4. If we picked a rune while we have a stack - set charges.
5. Else we picked a stack off the ground - do nothing.
6. If we have 0, we've picked a rune while we have no stack - create a non-runic potion.
7. Add the number of charges onto the non-runic potion in the inventory.

Thank you, and good night.

RDZ
#2
-- Example map now included above --
#3
This items stacking method is a little confusing and uses some variables. I have a suggestion

1. Have the hero pick up the item
2. Check if hero has any of the same kind
3. Stack

Here is my code (universal item stacker)
For condition add the items that are stackable.

Item Stacking

Event A unit aciqure an item
condition Stackable items (like potion)

Action

For each (Integer A) from 1 to 6, do (Actions)
Loop - Actions

For each (Integer B) from 1 to 6, do (Actions)
Loop - Actions

If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions

(Integer A) Not equal to (Integer B)

(Item-type of (Item carried by (Hero manipulating item) in slot (Integer A))) Equal to (Item-type of (Item carried by (Hero manipulating item) in slot (Integer B)))

Then - Action

Item - Set charges remaining in (Item carried by (Hero manipulating item) in slot (Integer A)) to ((Charges remaining in (Item carried by (Hero manipulating item) in slot (Integer A))) + (Charges remaining in (Item carried by (Hero manipulating item) in slot (Integer B))))

Item - Remove (Item carried by (Hero manipulating item) in slot (Integer B))

Else - Actions
Do nothing

If you don't understand PM me
#4

Reply to reply on tutorial

No, but I think this tutorial is for stacking items without actually having to pick them up, your "universal code" requires you to actually pick up the item 1st, I thought both of them are good, but the runic/non runic 1 is better because then you don't have to have an inventory slot free to pick the item up
#5

Re: Reply to reply on tutorial

Bigfootmech... you don't have to have an inventory slot free to pick the item up


Precisely the point of all the complexity. The advantage of my system is that it covers all eventualities - while you will have to have a slot free to merge two stacks, the chances of this needing to happen should be fairly slim.
#6
I totally forgot that stack eventuality, you can do that though with XTREME code :P, and I WAS SAYING that point,
Precisely the point of all the complexity. The advantage of my system is that it covers all eventualities - while you will have to have a slot free to merge two stacks, the chances of this needing to happen should be fairly slim.
#7
Just had to affirm you, though, a lot of people have been complaining about it being over-complicated.

8)
#8

Two Small Things

Awesome tutorial RDZ, just two small things...

1. Could you fix your link to the map you provided, cause it aint working.

2. Could you put the finished script to make it easier for people to see the finished result? That way we only have to change names and variables.

P.S. I know this isn't the place to ask, but are you going to make icons for your models?
#9
1. Whoops, must have deleted it by accident.

2. No, it's triggers and they're in the example map.

P.S. No. Just take some screenshots and do it yourself. :D
#10
I know this is slightly off topic, but I read your tutorial in hopes of answering my question, and it looks like you know a lot about items and triggers in GUI, so here I go:

Basically, I have a mini-quest where 4 checkpoints will spawn in random areas of the map. The checkpoints will be points on the map, nothing more.

Each checkpoint spawns a corresponding item (Checkpoint 1 spawns and item named "Checkpoint 1" and so on). When a checkpoint (item) is acquired, a new checkpoint item automatically spawns at that location until the quest is done. So if player 3 picks up a Checkpoint 2 item, a new checkpoint 2 item spawns at that location for another player to pick up. These triggers remain on until the quest is completed by a player acquiring all 4 checkpoint items.

Now, here's what I can't figure out for the life of me.

I need a trigger that will detect when a unit has all four checkpoints in his inventory, preferably the moment he picks up the item (not a trigger that relies on a periodic amount of time i.e. every 1 seconds). This trigger will then remove all four checkpoints from his inventory and will give the character a new item called "Fat Lewt". It will also remove every single "Checkpoint 1", "Checkpoint 2", "Checkpoint 3" and "Checkpoint 4" item from every single unit on the map.

Since you deal with GUI, it would be great if this could be in GUI. I'll continue to try and figure out how to do this on my own, but your help would be greatly appreciated. Sorry for having to post this in your thread.

EDIT: Something just came to my attention, and I REALLY hope it's not an issue, because if it is, I'm screwed. All the event responses referring to items also refer to heroes. In other words, the event response to a unit acquiring an item is "hero manipulating item". Does this mean that it must be a hero for this to work? Because I have no heroes in my map, only units, so does this mean that I have to make them all into heroes in order for this to work?
The conversation continued. After wc3sear.ch closed, 3 further replies were posted to this thread on The Hive Workshop. Read them there →