Looking for Help - Custom Variable For Loop

Status
Not open for further replies.
Level 21
Joined
Jan 14, 2014
Messages
567
Hey y'all. As some of you may know, I'm working on a "fully functional" Diablo Map, called The Darkening of Tristram.

I came across with a problem that perhaps need help or some greater attention from me.

I intend to make a For Loop Trigger that detects the Weapon Type I'm currently using, then the Hero can have its Attack Damage modified. I want the modification of the damage to work like this:

Minimum Damage: Number of Dices (Swords_MinDmg[])
Maximum Damage: Number of Dices * Sides per Dice (Swords_MaxDmg[])
"Base" Damage: Complement + Formula (Swords_BaseDmgMightDmg[0])
Formula: Percentage of Might Attribute

Note: The Complement number is to make the damage numbers from Diablo Weapons correct, check the Bastard Sword as an example.

SETUP:

Setup1.jpg

Setup2.jpg

Setup3.jpg


TRIGGER:


ForEachTrigger.jpg


Using the Short Sword weapon as base, if the Trigger worked correctly, the Attack Damage shown was supposed to be:

Minimum Damage: 2
Maximum Damage: 3
"Base" Damage: 0 + 15
Formula: 0.60 x 25 (base Might)
Total Damage: 15 + (2 - 6) = 17 - 21

InGameResults.jpg


But this is what I get when testing it ingame. Some of you may think: "Well, perhaps you just didn't set the Attack Index correctly, or you didn't enabled any Attack mode."

HeroInfo.jpg


But the Hero Type and the Attack Index (Attacks Enabled) were both correct. I guess, the greatest proof will be shown below when I'll use numbers to make the damage modification.

ForEachTriggerUsingNumbers.jpg


If the trigger is wrong, I guess that the result will be the same as when using the Variables instead of Numbers.

InGameResultsUsingNumbers.jpg


BUT this time worked because I used numbers. I guess the trigger isn't wrong at all, perhaps the system doesn't accept to change the Base, Number of Dices and Sides per Dice using variables. Just like the Game Interface doesn't accept commas when writing.

And that's the help I want and need. If the trigger is wrong because it's not showing the damage number, I would like to know how to correct it. If the system simply doesn't accept some changes by using variable, I'll have to think how to make this work.

That's all for now. Sorry for the long read.
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
You set Swords_Total to 14 when you want to set it to 13. Remember, the index of your last sword is 13, so your "total" variable that's referenced in your Loop range should be the same number as this.

Anyway, that's only a minor issue, the main issue is that you aren't checking if the Item you acquired is actually one of those 14 Swords. Because of this your trigger is applying the damage of EVERY-SINGLE-SWORD including the stats of a sword that doesn't even exist (#14) to the unit all at once. The last cycle of the loop is 14, which has no variables set so it defaults you to the value 0.

That's why your unit ends up without an attack, all of it's damage stats have been set to 0, which are the values of the non-existent 14th sword.

I would set it up to look something like this:
  • Set Variable ItemFound = Item being manipulated
  • For each (Integer SwordsVAR) from 0 to Swords_Total, do (Actions)
  • If (Item-type of ItemFound) Equal to Swords[SwordsVAR] then do your Set damage stuff
 
Last edited:
Level 21
Joined
Jan 14, 2014
Messages
567
You set Swords_Total to 14 when you want to set it to 13. Remember, the index of your last sword is 13, so your "total" variable that's referenced in your Loop range should be the same number as this.

Anyway, that's only a minor issue, the main issue is that you aren't checking if the Item you acquired is actually one of those 14 Swords. Because of this your trigger is applying the damage of EVERY-SINGLE-SWORD including the stats of a sword that doesn't even exist (#14) to the unit all at once. The last cycle of the loop is 14, which has no variables set so it defaults you to the value 0.

That's why your unit ends up without an attack, all of it's damage stats have been set to 0, which are the values of the non-existent 14th sword.
At the very first I set Swords_Total to 13, then I noticed that I started the index with 0. I thought that the For Each would already check the item used. I'll have to check this out.
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
A For Loop is basically a way to run a set of Actions X amount of times. It does this in the form of a range that you define from A to B (in your case 0 to 13). You can also define an Integer variable, like you did, to represent the current cycle of the For Loop. This variable is useful since you can make it match the Indexes in your Arrays, which is what you were attempting to do. Other than that, the For Loop has absolutely no idea of anything that you don't explicitly tell it about. Understand that the Loop could be used for many different things, so it can't come to conclusions on it's own, that's up to you. It's simply a tool for repeating Actions. Combining it's functionality with Arrays to find the correct Index is just something YOU can make it do, but again, it can't magically know to do this without you telling it to do so.

Anyway, I updated my last post with a trigger example of what you'd need to do. I wrote it from memory so it won't look perfect.
 
Last edited:

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
If you post your newly updated triggers I may be able to help some more -> How To Post Your Trigger
I think you may be making some more mistakes, you should only need one For Loop for the Swords category in the Item Acquired trigger.

Also, see how you're defining Sword_BaseDmgMightDmg during Map Initialization? That's going to be it's value for the rest of the game. What if the Hero gains more Might since then? The Variable won't magically update, it's going to still have that original value defined at Map Initialization.

And another issue, you're referencing Hero in Sword_BaseDmgMightDmg but is Hero even set yet?
I recommend creating a single Map Initialization trigger that manages everything that needs to happen during map setup.
This way you choose the order of how things happen, something like this:
  • Events:
  • Map initialization
  • Actions:
  • Set Variable Hero = Your hero unit
  • Trigger - Run Setup (ignoring conditions)
  • Run any other "setup" triggers here as well
^ With this design you can choose the order in which things are initialized. This way Hero is guaranteed to be Set before you run any other triggers that might reference it.
 
Last edited:
Level 21
Joined
Jan 14, 2014
Messages
567
If you post your newly updated triggers I may be able to help some more -> How To Post Your Trigger
I think you may be making some more mistakes, you should only need one For Loop for the Swords category in the Acquired Item trigger.

Also, see how you're defining Sword_BaseDmgMightDmg during Map Initialization? That's going to be it's value for the rest of the game. What if the Hero gains more Might since then? The Variable won't magically update, it's going to still have that original value defined at Map Initialization.

And another issue, you're referencing Hero but have you Set that variable yet? I recommend making a single Map Initialization trigger that way you choose the order of how things happen, something like this:
  • Events:
  • Map initialization
  • Actions:
  • Set Variable Hero = Your hero unit
  • Trigger - Run Setup (ignoring conditions)
  • Run any other "setup" triggers here as well
^ With this design you can choose the order in which things are initialized. This way Hero is guaranteed to be Set before you run any other triggers that might reference it.
Yes, I set up the Hero unit because the map requires a hero selection.

  • Hero Selection
    • Events:
      • Unit - A unit Begins casting an ability
    • Conditions:
      • (Ability being cast) Equal to Select Hero
    • Actions:
      • Animation - Play (Casting unit)'s stand victory alternate animation
      • Cinematic - Turn cinematic mode On for Player Group - Player 2 (Blue)
      • Cinematic - Fade out over 1.25 seconds using texture Black Mask and color (0.00%, 0.00%, 0.00%) with 0.00% transparency
      • Wait 2.00 seconds
      • Game - Enable drag-selection functionality (Enable drag-selection box)
      • Game - Enable pre-selection functionality (Enable pre-selection circles, life bars, and object info)
      • Selection - Clear selection for Player 2 (Blue).
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Casting unit) Equal to Warrior (Hero Selection) 0011 <gen>
        • Then - Actions
          • Unit - Remove (Casting unit) from the game
          • Unit - Create 1 Warrior (Unarmed) for Player 2 (Blue) at (Center of Hero Starting Point <gen>) facing Default building facing degrees
          • Set VariableSet Hero = (Last created unit)
          • -------- Equipment Start --------
          • Hero - Create Bastard Sword and give it to Hero
          • -------- Equipment End --------
        • Else - Actions
      • Animation - Play the death animation for all doodads of type Fire Pit within Starting Fire Pit <gen>.
      • Game - Display to Player Group - Player 2 (Blue) for 10.00 seconds the text: Your game will soon...
      • Trigger - Turn off Camera Lock <gen>
      • Wait 12.75 seconds
      • Camera - Reset camera for Player 2 (Blue) to standard game-view over 0.00 seconds
      • Trigger - Turn on Hero Camera Lock <gen>
      • Trigger - Run Hero Camera Lock <gen> (ignoring conditions)
      • Cinematic - Fade in over 1.25 seconds using texture Black Mask and color (0.00%, 0.00%, 0.00%) with 0.00% transparency
      • Player - Add 500 to Player 2 (Blue).Current gold
      • Sound - Stop (Last played sound) After fading
      • Sound - Play TristramTheme
      • Cinematic - Turn cinematic mode Off for Player Group - Player 2 (Blue)
As for the updating Might % Damage, I will look towards it later. Perhaps I'll update the Might with another trigger that uses time.
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
That's your issue though. You're setting Hero AFTER Map Initialization. Hero doesn't exist until you pick him! So your Might Variables don't know who Hero is when you Set them. That's why their values are all 0, the Action to Set them couldn't find Hero so it "crashed" and instead gave them the default value of 0.

The Might thing can be a bit difficult to manage but ideally you wouldn't use time. It should all be Event based. The Hero acquires the item -> Calculate the Might using it's current Might attribute. The Hero gains Might, maybe from Leveling up -> Re-calculate the Might using it's newly improved Might attribute.

But I guess you can use time to periodically recalculate the stats, it's not the end of the world, especially if it's only a singleplayer map.
 
Last edited:
Level 21
Joined
Jan 14, 2014
Messages
567
That's your issue though. You're setting Hero AFTER Map Initialization. Hero doesn't exist until you pick him! So your Might Variables don't know who Hero is when you Set them. That's why their values are all 0, the Action couldn't find Hero so it "crashed" and instead gave you the default value of 0.

The Might thing can be a bit difficult to manage but ideally you wouldn't use time. It should all be Event based. The Hero acquires the item -> Calculate the Might using it's current Might attribute. The Hero gains Might, maybe from Leveling up -> Re-calculate the Might using it's newly improved Might attribute.
So the correct thing to do is enable the item Setup after the Hero Selection? But how am I supposed to update the Might Damage Bonus since different weapons will offer different values for Might % Damage?

The Hero will gain Might with Attribute Points and Items that grants Might.
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
Well, that would be the correct thing to do under different circumstances. Sorry for misleading you. In this case you want that Variable to be used as part of the calculation for the Might bonus damage, not act as the actual predefined calculation itself.

So for example, you can replace the old Might variable with 2 new variables, one an Integer and one a Real:
  • Short Sword Might example:
  • Set Variable Swords_MightMultiplier[0] = 0.60
  • Set Variable Swords_MightFlat[0] = 0

Swords_MightMultiplier is the fraction of Might that is used in the calcuation.
Swords_MightFlat is that extra Integer that you add to some Swords like the Bastard Sword (+3).

Then when it comes time to calculate the Base Damage for your Hero you first figure out which Sword they have equipped (the Index of it to be exact) and then you use these 2 new variables in your Might calculation:
  • Set Variable index = The index of the sword (0 would be Short Sword)
  • Unit - Set Base damage of Hero to (Integer(Swords_MightFlat[index] + (Swords_MightMultiplier[index] * Agility of Hero (include bonuses)) for weapon index: 0

Anyway, I shouldn't be awake right now, I can help you again some more later. Good luck.
 
Last edited:

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
Using a periodic event (time) is okay as well if you want to keep it simple.

I can't help but suggest the "ideal" way of doing things. Ideally you'd take advantage of Events since this is efficient/instant. Gaining Might would probably only come from a few different Events: Acquiring an item, Losing an item, Leveling up, Casting a spell that adds Might/that spell wearing off.

A system could be made that you use throughout all of these Might-related triggers to make things easy on you.
Something like a simpler version of this: New Bonus [vJASS][LUA]
So you could just call a simple function or if you wanted it to be GUI friendly you Run a trigger that adds/removes Might and does the Might calculations.
But I realize and understand if that's just too much work.

The main idea is: If you want Might Bonus Dmg to work correctly then you can't define it once and forget about it. It needs to be updated to match the Hero's current Might.
 
Last edited:

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
No problem. I also recommend using Hashtables to store all of this information as this will help make your triggers clean and efficient. You would still have Arrays like you do now, but during the Setup process you would Loop over these Arrays and store their information inside of multiple Hashtables. You could probably even have an Array of Hashtables, one for each Item category (never actually tried this before). As a result, you could organize items by their category, for example:

First you define each Item category by assigning them a unique Integer:
  • Set Variable Swords = 0
  • Set Variable Axes = 1
  • Set Variable Bows = 2
  • Set Variable Helm = 3
  • etc...

Then when it comes time to save data to the Hashtable you would do something like this:
  • For each Integer (ItemIndex) from 0 to TotalSwords do Actions...
  • Hashtable - Save Swords_MinDmg[ItemIndex] as 0 of ItemIndex in ItemHashtable[Swords]
  • Hashtable - Save Swords_MaxDmg[ItemIndex] as 1 of ItemIndex in ItemHashtable[Swords]
  • /// etc...

So ItemHashtable[0] aka ItemHashtable[Swords] would contain ALL of the information for every Sword in the game. ItemHashtable[1] aka ItemHashtable[Axes] would contain all of the Axe information, etc.

You can then Load a specific Sword's (or any item) information from it's Hashtable and choose a Child Key (0, 1, 2, etc.) to get the MinDmg, MaxDmg, MightDmg, etc...
In my above example I saved MinDmg at Child Key 0 and MaxDmg at Child Key 1.

Perhaps a bit confusing if you're new to Hashtables but with this design you would make your life A LOT easier down the line. Your triggers would no longer need a long series of If Then Else statements and could directly look up the information needed as long as you have the Category of your Item and it's Index inside of that Category (Short Sword's category is 0 and it's item index in that category is 0 since it's the very first item).

You could then store the Category and Item Index information directly to the Items you find. This can be done using an Item Indexer, a simple system that allows you to save data directly to Items using their custom value. There's an easy to use one on Hiveworkshop called GUI Item Indexer.

As a result, you could get the item category/index from any item in the Hero's inventory and then plug that information into the correct Hashtable to get the values of MinDmg/MaxDmg/MightDmg/etc.

Getting this information would look something like this:
  • Events:
  • Unit - A unit acquires an item
  • Actions:
  • Set Variable ItemCV = Custom value of Item being manipulated
  • Set Variable Category = ItemCategory[ItemCV]
  • Set Variable Index = ItemIndex[ItemCV]
  • Set Variable MinDmg = Load 0 of Index from ItemHashtable[Category]
  • Set Variable MaxDmg = Load 1 of Index from ItemHashtable[Category]
You now have the MinDmg and MaxDmg of the item you just picked up. ItemCategory and ItemIndex would be variables used by the Item Indexer that are saved directly to the item itself.
 
Last edited:
Status
Not open for further replies.
Top