PDA

View Full Version : Need help with spell [FIRST approach to hashtables]


NarGalloth
07-24-2012, 04:58 PM
Hi.

I have a serious problem right now. I'm trying to make my very first spell. I've read some tutorials about hashtables, but I still don't know very well how to use them...

First, I'll explain what the spell should do. It's for a hero called "Gnoll Explorer". The spell's name is Evanescence, and if the hero uses it, it will teleport with fast speed above the enemies and will fall on them, inflicting damage.
Before showing the triggers, I'll explain a few things about the map, and the variables used:

- In the map, Player 12 is the user, and Player 11 is the enemy. The Gnoll Explorer is a Player 12's unit.
- In one of the triggers, I create a unit called "Gnoll Explorer (Evanescence)". This is some kind of dummy unit. It has the same model as the Gnoll Explorer, with 0 collision, and with flying movement, with default flying height of 500.

- Evanescence: Hashtable variable
- Evanescence_Vector: Integer array
- Evanescence_Damage: Integer array
- Remaining_Jumps: Integer variable
- LEAK: Point variable
- GroupLEAK: Unit group variable

Settings
Events
Map initialization
Conditions
Actions
-------- Here I create the hashtable --------
Hashtable - Create a hashtable
Set Evanescence = (Last created hashtable)
-------- Here I set the number of enemies he hero will fall on per level --------
Set Evanescence_Vector[1] = 3
Set Evanescence_Vector[2] = 5
Set Evanescence_Vector[3] = 7
-------- Here I set the damage dealt with each attack per level --------
Set Evanescence_Damage[1] = 85
Set Evanescence_Damage[2] = 125
Set Evanescence_Damage[3] = 175


Start Evanescence
Events
Unit - A unit Starts the effect of an ability
Conditions
(Unit-type of (Triggering unit)) Equal to Gnoll Explorer
(Ability being cast) Equal to Evanescence
Actions
-------- Here I save the number of attacks, the damage, and the target unit in the hashtable --------
Hashtable - Save Evanescence_Vector[(Level of Evanescence for (Triggering unit))] as 0 of (Key (Triggering unit)) in Evanescence
Hashtable - Save Evanescence_Damage[(Level of Evanescencia for (Triggering unit))] as 4 of (Key (Triggering unit)) in Evanescence
Hashtable - Save Handle Of(Target unit of ability being cast) as 1 of (Key (Triggering unit)) in (Last created hashtable)
-------- Here I add the hero to an unit group, I wil use it in the next trigger --------
Unit group - Add (Triggering unit) to Ability_Evanescence
-------- Graphical stuff --------
Unit - Hide (Triggering unit)
Set LEAK = (Position of (Triggering unit))
Special effect - Create a special effect at LEAK using war3mapImported\BlackBlink.mdx
Special effect - Destroy (Last created special effect)
Custom script: call RemoveLocation(udg_LEAK)


Evanescence Loop
Events
Time - Every 2.00 seconds of game time
Conditions
Actions
Unit group - Pick every unit in Ability_Evanescence and do (Actions)
Loop - Actons
Set Remaining_Jumps = (Load 0 of (Key (Picked unit)) from Evanescence)
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
Remaining_Jumps Igual a 0
Then - Actions
-------- If all the attacks have been used, the unit returns to normal state --------
Unit Group - Remove (Picked unit) from Ability_Evanescence
Unit - Unhide (Picked unit)
Other - Action
-------- I update the number of attacks left. I also play a sound, and create the dummy unit at the position of the target --------
Sound - Stop Evanescence <gen> Immediately
Set Remaining_Jumps = (Remaining_Jumps - 1)
Hashtable - Save Remaining_Jumps as 0 of (Key (Picked unit)) in Evanescence
Set LEAK = (Position of (Load 1 of (Key (Picked unit)) in Evanescence))
Unit - Create 1 Gnoll Explorer (Evanescence) for Player 12 (brown) at LEAK facing 270.00 degrees
Custom script: call RemoveLocation(udg_LEAK)
Sound - Play Evanescence <gen> at 100.00% volume, attached to (Last created unit)
-------- I store the dummy unit in the hashtable --------
Hashtable - Save Handle Of(Last created unit) as 2 of (Key (Picked unit)) in Evanescence
-------- I create a special effect on the dummy unit, and store it in the hashtable as well --------
Special effect - Create a special effect attached to the chest of (Last created unit) using war3mapImported\BlackBlink.mdx
Hashtable - Save Handle Of(Last created special effect) as 3 of (Key (Picked unit)) in Evanescence
-------- I make the unit fall, and wait until it reaches the ground --------
Animation - Change (Last created unit) flying height to 0.00 at 500.00
Wait 1.00 seconds
-------- I create a special effect at the position of the target --------
Set LEAK = (Position of (Load 1 of (Key (Picked unit)) in Evanescence))
Special effect - Create a special effect at LEAK using Abilities\Spells\Orc\WarStomp\WarStompCaster.mdl
Special effect - Destroy (Last created special effect)
Custom script: call RemoveLocation(udg_LEAK)
-------- I remove the dummy unit and the special effect attached to it --------
Special effect - Destroy (Load 3 of (Key (Picked unit)) in Evanescence)
Unit - Remove (Load 2 of (Key (Picked unit)) in Evanescence) from the game
-------- I set a region around the target --------
Set LEAK = (Position of (Load 1 of (Key (Picked unit)) in Evanescence))
Set GroupLEAK = (Units in (Region centered at LEAK with size (800.00, 800.00)) owned by Player 11 (dark green))
Custom script: call RemoveLocation(udg_LEAK)
-------- I damage the target --------
Unit - Set life of (Load 1 of (Key (Picked unit)) in Evanescence) to ((Life of (Load 1 of (Key (Picked unit)) in Evanescence)) - (Load 4 of (Key (Picked unit)) from Evanescence))
-------- I set a new random target for the next attack --------
Hashtable - Save Handle Of(Random unit from GroupLEAK) as 1 of (Key (Picked unit)) in (Last created hashtable)
Custom script: call DestroyGroup(udg_GroupLEAK)


The "Evanescence Start" trigger runs fine. However, the "Evanescence Loop" trigger does absolutely nothing. In-game, the hero disappears with a special effect, and after 3 second it reappears again, without doing damage to anything.
As I said before, this is the first time I try to make stuff with hashtables and handles IDs, I'm a NOOB with this things.
I'll be extremely grateful if you help me fix this spell. Also, I'll really appreciate that someone helps me find and fix any leak around the triggers.

Thanks in advance.

Regards

Pharaoh_
07-24-2012, 05:53 PM
Remove the wait. The code fails to be executed after it. Waits don't work inside unit group enumerations.

NarGalloth
07-24-2012, 06:15 PM
I already suspected that the "Wait" could be problematic... But I just don't know how to avoid using it.
I have read on some tutorials that it's a lot better to use timers instead of waits, but I can't figure out how...

Regards

Tank-Commander
07-24-2012, 09:16 PM
You can generate a wait which will work with group enumerations using a saved hashtable variable and an IF block:

Example:


Example
Events
Time - every 2.00 seconds of game time
Conditions
Actions
Unit Group - Pick every unit in Ability_Evanescence and do (Actions)
Loop - Actions
Hashtable - Save Handle Of(Load (x) of (Key (Picked Unit)) in Evanescence + 1) as (x) of (Key (Picked unit)) in Evanescence
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
Load x of Key(PickedUnit) in Evanescence > Delay
Then - Actions
<<Actions>>
Else - Actions





Though in this instance I'd use a variable to store the loaded value which is the delay, doesn't really matter if you use a real or integer, but it'll work

NarGalloth
07-25-2012, 02:45 PM
You can generate a wait which will work with group enumerations using a saved hashtable variable and an IF block:

Example:


Example
Events
Time - every 2.00 seconds of game time
Conditions
Actions
Unit Group - Pick every unit in Ability_Evanescence and do (Actions)
Loop - Actions
Hashtable - Save Handle Of(Load (x) of (Key (Picked Unit)) in Evanescence + 1) as (x) of (Key (Picked unit)) in Evanescence
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
Load x of Key(PickedUnit) in Evanescence > Delay
Then - Actions
<<Actions>>
Else - Actions





Though in this instance I'd use a variable to store the loaded value which is the delay, doesn't really matter if you use a real or integer, but it'll work

I'm sorry, I don't uderstand what you're exactly talking about...
:goblin_cry:
Maybe I'm still a bit inexperienced... Could you explain this with more detail, please?

Regards

Tank-Commander
07-25-2012, 03:05 PM
Basically you attach a variable to every unit in the group (which you've saved in your hashtable) then increase it by 1 in each loop instance, and then when it's greater than (or equal to depending on how you want to do it a constant delay variable (say 3) then run actions, this will generate a wait equal to the length of time it takes for the loop to run that many times:


You run the actions you want after the variable has reached this goal

Period loop runs every 1 second
Delay variable = 4

1st instance (1 second):
Variable = 1
Delay Variable = 4
-Actions do not run-

2nd instance (2 seconds):
Variable = 2
Delay Variable = 4
-Actions do not run-

3rd instance (3 seconds):
Variable = 3
Delay Variable = 4
-Actions do not run-

4th instance (4 seconds):
Variable = 4
Delay Variable = 4
-Actions do run-

NarGalloth
07-25-2012, 04:21 PM
Oh! I understand now!
I'll try it right now. :)

EDIT: OK, things are getting better, but the spell is still bugging. :(

Tank-Commander, I've made changes in the two main triggers, trying to use the trick you say. Now, the dummy hero succesfully appears over the first enemy and falls into him, but it doesn't disappear! Also, the spell is bugged there. The loop stops, the dummy doesn't disappears, and only the FIRST attack is done. It's a bit better than before, but still very bugged. I hope you can help fix it.
Here you have the new triggers. Note that the changes are marked with [UPDATE HERE] comments.

Start Evanescence
Events
Unit - A unit Starts the effect of an ability
Conditions
(Unit-type of (Triggering unit)) Equal to Gnoll Explorer
(Ability being cast) Equal to Evanescence
Actions
Hashtable - Save Evanescence_Vector[(Level of Evanescence for (Triggering unit))] as 0 of (Key (Triggering unit)) in Evanescence
Hashtable - Save Evanescence_Damage[(Level of Evanescencia for (Triggering unit))] as 4 of (Key (Triggering unit)) in Evanescence
Hashtable - Save Handle Of(Target unit of ability being cast) as 1 of (Key (Triggering unit)) in (Last created hashtable)
-------- UPDATE HERE: Here I save the time counter Tank-Commander said me to use. I set it to 0 when the spell begins --------
Hashtable - Save 0 as 5 of (Key (Triggering unit)) in Evanescence
Unit group - Add (Triggering unit) to Ability_Evanescence
Unit - Hide (Triggering unit)
Set LEAK = (Position of (Triggering unit))
Special effect - Create a special effect at LEAK using war3mapImported\BlackBlink.mdx
Special effect - Destroy (Last created special effect)
Custom script: call RemoveLocation(udg_LEAK)

Note: Now the second trigger runs every 0.5 seconds.

Evanescence Loop
Events
Time - Every 0.50 seconds of game time
Conditions
Actions
Unit group - Pick every unit in Ability_Evanescence and do (Actions)
Loop - Actions
Set Remaining_Jumps = (Load 0 of (Key (Picked unit)) from Evanescence)
-------- UPDATE HERE: Here I increment the time counter in 0.5 seconds --------
Hashtable - Save ((Load 5 of (Key (Picked unit)) from Evanescence) + 0.50) as 5 of (Key (Picked unit)) in Evanescence
-------- UPDATE HERE: The body of the spell will only start if the time counter is 2 seconds --------
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(Load 5 of (Key (Picked unit)) from Evanescence) Equal to 2.00
Then - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
Remaining_Jumps Equal to 0
Then - Actions
Unit group - Remove (Picked unit) from Ability_Evanescence
Unit - Unhide (Picked unit)
Other - Actions
Sound - Stop Evanescence <gen> Immediately
Set Remaining_Jumps = (Remaining_Jumps - 1)
Hashtable - Save Remaining_Jumps as 0 of (Key (Picked unit)) in Evanescence
Set LEAK = (Position of (Load 1 of (Key (Picked unit)) in Evanescence))
Unit - Create 1 Gnoll Explorer (Evanescence) for Player 12 (brown) at LEAK facing 270.00 degrees
Custom script: call RemoveLocation(udg_LEAK)
Sound - Play Evanescence <gen> at 100.00% volume, attached to (Last created unit)
Hashtable - Save Handle Of(Last created unit) as 2 of (Key (Picked unit)) in Evanescence
Special effect - Create a special effect attached to the origin of (Last created unit) using war3mapImported\BlackBlink.mdx
Hashtable - Save Handle Of(Last created special effect) as 3 of (Key (Picked unit)) in Evanescence
Animation - Change (Last created unit) flying height to 0.00 at 1000.00
-------- UPDATE HERE: The final part of the spell only starts if the time counter is 2.5 seconds --------
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Condition
(Load 5 of (Key (Picked unit)) from Evanescence) Igual a 2.50
Then - Actions
Set LEAK = (Position of (Load 1 of (Key (Picked unit)) in Evanescence))
Special effect - Create a special effect at LEAK using Abilities\Spells\Orc\WarStomp\WarStompCaster.mdl
Special effect - Destroy (Last created special effect)
Custom script: call RemoveLocation(udg_LEAK)
Special effect - Destroy (Load 3 of (Key (Picked unit)) in Evanescence)
Unit - Remove (Load 2 of (Key (Picked unit)) in Evanescence) from the game
Set LEAK = (Position of (Load 1 of (Key (Picked unit)) in Evanescence))
Set GroupLEAK = (Units in (Region centered at LEAK with size (800.00, 800.00)) owned by Player 11 (dark green))
Custom script: call RemoveLocation(udg_LEAK)
Unit - Set life of (Load 1 of (Key (Picked unit)) in Evanescence) to ((Life of (Load 1 of (Key (Picked unit)) in Evanescence)) - (Load 4 of (Key (Picked unit)) from Evanescence))
Hashtable - Save Handle Of(Random unit from GroupLEAK) as 1 of (Key (Picked unit)) in (Last created hashtable)
Custom script: call DestroyGroup(udg_GroupLEAK)
Other - Actions
Other - Actions


Well, as I said, the dummy hero falls, but nothing more happens. Any ideas to fix this?

Regards

NarGalloth
07-27-2012, 09:51 PM
Bump

NarGalloth
08-05-2012, 03:55 PM
Bump

Tank-Commander
08-05-2012, 04:07 PM
It's because at your "equal to 2.5" part needs to be in an else section of the "equal to 2" part, otherwise it won't go into the if block if it's 2.5 and so will never get to that stage

NarGalloth
08-07-2012, 04:48 PM
You're right!
OK, I fixed that. Now the hero falls down, the attack animation does show, and the hero dissappears. Then, it SHOULD chose another random enemy and do the next attack. However, he doesn't.
What I mean is, the hero falls over the target and dissappears, but he doesn't attack any more enemies. He doesn't reappear either. Also, the health of the target is NOT reduced.
I don't know why.

Regards

Tank-Commander
08-07-2012, 05:15 PM
owned by Player 11 (dark green))


It only effects units owned by the dark greeen player? Also don't bother with a region, just go units within (range) of (point)

also


Unit - Set life of (Load 1 of (Key (Picked unit)) in Evanescence) to ((Life of (Load 1 of (Key (Picked unit)) in Evanescence)) - (Load 4 of (Key (Picked unit)) from Evanescence))


Should be a given amount of damage rather than just setting life, doing a bit of maths can achieve the same effect without doing this, then units will recognise the damage source

I do not quite understand -what- makes your hero disappear again and if it's

Unit - Remove (Load 2 of (Key (Picked unit)) in Evanescence) from the game


Then it's more than obvious as to why you can't get him back

Almia
08-11-2012, 09:34 AM
Does any body saw (last created hashtable)? :D

NarGalloth
08-11-2012, 02:34 PM
Does any body saw (last created hashtable)? :D

I saw that too, but hopefully the "Eavescence" hastable if actually the only hashtable in the map, so I don't think that's a problem. Am I wrong?
I just forgot to change it when I made the triggers XD.
It's already fixed anyway.

owned by Player 11 (dark green))


It only effects units owned by the dark greeen player? Also don't bother with a region, just go units within (range) of (point)

also


Unit - Set life of (Load 1 of (Key (Picked unit)) in Evanescence) to ((Life of (Load 1 of (Key (Picked unit)) in Evanescence)) - (Load 4 of (Key (Picked unit)) from Evanescence))


Should be a given amount of damage rather than just setting life, doing a bit of maths can achieve the same effect without doing this, then units will recognise the damage source

I do not quite understand -what- makes your hero disappear again and if it's

Unit - Remove (Load 2 of (Key (Picked unit)) in Evanescence) from the game


Then it's more than obvious as to why you can't get him back


First of all, I was testing the ability with hostile creeps... :goblin_cry:

However, I changed the "Player 11 (dark green)" so the ability chooses targets from any nearby enemy units, and still doesn't do anything.
Anyway, I'll try to avoid regions, as you say.

I'll also try to do damage instead of setting life, and see if the results are better.

The unit that's removed in the last function you quoted is the dummy hero, not the hero itself. The original hero is hidden in the first trigger of the ability in the very moment he starts casting the ability, and the heros that fall over the enemies are dummy heros that are created and then removed fro each of the strikes.
Maybe I made something wrong with that, I'll check all the triggers again...

Note: I think I'll upload a test map with the acual triggers of the ability. Probably with a test map you'll be much more capable to help me find the source of the problem.

Regards

Tank-Commander
08-11-2012, 02:55 PM
For the record, if you're wanting it to repeat the loop, shouldn't you be resetting value 5 on the hashtable after it hits the 2.5 mark?


Hashtable - Save 0 as 5 of (Key (Picked unit)) in Evanescence

NarGalloth
08-17-2012, 07:26 PM
For the record, if you're wanting it to repeat the loop, shouldn't you be resetting value 5 on the hashtable after it hits the 2.5 mark?


Hashtable - Save 0 as 5 of (Key (Picked unit)) in Evanescence


My god... THAT was the problem! (I feel stupid now...)

I reset the value to 0 after each loop, and now the spell works almost fine!
The animations and the strikes now run correctly... However the only problem that I still can't solve is the damage. The spell doesn't do any damage. The targeted units don't recognize the damage.

I tried using this:

Unit - Cause (Picked unit) to damage (Load 1 of (Key (Picked unit)) in Evanescence), dealing (Load 4 of (Key (Picked unit)) from Evanescence) damage of attack type Spells and damage type Normal

However, it doesn't work. The life of the enemies doesn't change at all. What's wrong with this? Is there any other way to damage a unit with spells (apart from setting the life, which didn't work either)?

Regards

Pharaoh_
08-18-2012, 09:24 AM
You set the unit group, but you are not picking any units in that region. By the way, prefer Units in range, not units in region. The only thing you do at the moment is damaging a random enemy from the units in region around hero, when that random enemy is defined in the next line of the code - and it shouldn't even be saved, just use Cause (Picked unit) to damage (Random unit from GroupLEAK).

NarGalloth
08-28-2012, 07:38 PM
Sorry for taking so long time without answering, but I gas a bit busy with other proyects. However, I want to take this problem to the end now.

First of all, the triggers posted before are a bit outdated, so I upload here the new ones:

Evanescence Start
Events
Unit - A unit Starts the effect of an ability
Conditions
(Unit-type of (Triggering unit)) Equal to Gnoll Explorer
(Ability being cast) Equal to Evanescence
Actions
Hashtable - Save Evanescence_Vector[(Level of Evanescence for (Triggering unit))] as 0 of (Key (Triggering unit)) in Evanescence
Hashtable - Save Evanescence_Damage[(Level of Evanescence for (Triggering unit))] as 4 of (Key (Triggering unit)) in Evanescence
Hashtable - Save Handle Of(Target unit of ability being cast) as 1 of (Key (Triggering unit)) in Evanescence
Hashtable - Save 0 as 5 of (Key (Triggering unit)) in Evanescence
Unit Group - Add (Triggering unit) to Ability_Evanescence
Unit - Hide (Triggering unit)
Set LEAK = (Position of (Triggering unit))
Special Effect - Create a special effect at LEAK using war3mapImported\BlackBlink.mdx
Special Effect - Destroy (Last created special effect)
Custom script: call RemoveLocation(udg_LEAK)


Evanescence Loop
Events
Time - Every 0.50 seconds of game time
Conditions
Actions
Unit Group - Pick every unit in Ability_Evanescence and do (Actions)
Loop - Actions
Set Remaining_Jumps = (Load 0 of (Key (Picked unit)) from Evanescence)
Hashtable - Save ((Load 5 of (Key (Picked unit)) from Evanescence) + 0.50) as 5 of (Key (Picked unit)) in Evanescence
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(Load 5 of (Key (Picked unit)) from Evanescence) Equal to 1.00
Then - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
Remaining_Jumps Igual a 0
Then - Actions
Unit Group - Remove (Picked unit) from Ability_Evanescence
Unit - Unhide (Picked unit)
Other - Actions
Sound - Stop Evanescence <gen> Immediately
Set Remaining_Jumps = (Remaining_Jumps - 1)
Hashtable - Save Remaining_Jumps as 0 of (Key (Picked unit)) in Evanescence
Set LEAK = (Position of (Load 1 of (Key (Picked unit)) in Evanescence))
Unit - Create 1 Gnoll Explorer (Evanescence) for Player 12 (brown) at LEAK facing 270.00 degrees
Custom script: call RemoveLocation(udg_LEAK)
Sound - Play Evanescence <gen> at 100.00% volume, attached to (Last created unit)
Hashtable - Save Handle Of (Last created unit) as 2 of (Key (Picked unit)) in Evanescence
Special Effect - Create a special effect attached to the origin of (Last created unit) using war3mapImported\BlackBlink.mdx
Hashtable - Save Handle Of(Last created special effect) as 3 of (Key (Picked unit)) in Evanescence
Animation - Change (Last created unit) flying height to 0.00 at 2000.00
Other - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(Load 5 of (Key (Picked unit)) from Evanescence) Equal to 1.50
Then - Actions
Unit - Cause (Picked unit) to damage (Load 1 of (Key (Picked unit)) in Evanescence), dealing (Load 4 of (Key (Picked unit)) from Evanescence) damage of attack type Conjuros and damage type Normal
Set LEAK = (Position of (Load 1 of (Key (Picked unit)) in Evanescence))
Special Effect - Create a special effect at LEAK using Abilities\Spells\Orc\WarStomp\WarStompCaster.mdl
Special Effect - Destroy (Last created special effect)
Special Effect - Destroy (Load 3 of (Key (Picked unit)) in Evanescence)
Unit - Remove (Load 2 of (Key (Picked unit)) in Evanescence) from the game
Set GroupLEAK = (Units within 400.00 of LEAK matching (((Owner of (Matching unit)) is an enemy of (Owner of (Picked unit))) Igual a True))
Hashtable - Save Handle Of (Random unit from GroupLEAK) as 1 of (Key (Picked unit)) in Evanescence
Custom script: call DestroyGroup(udg_GroupLEAK)
Custom script: call RemoveLocation(udg_LEAK)
Hashtable - Save 0.00 as 5 of (Key (Picked unit)) in Evanescence
Other - Actions


Well, as said in my last post, the graphical part works properly now, but no damage is dealt.
Pharaoh_, I don't clearly understand what you're trying to point... Let's see, obviously, the conflictive part of the trigger is the very last part of the "Evanescence Loop" trigger. If I'm not wrong, you say that when I damage the enemy, that enemy is actually declared in the next line of code...
Well, I'm damaging (Load 1 of (Key (Picked unit)) in Evanescence)... but that enemy is defined in the first trigger as the initial target, Save Handle Of(Target unit of ability being cast) as 1 of (Key (Triggering unit)) in Evanescence.
Later, I use the GroupLEAK variable to choose another random enemy from the area around the previous enemy.
Also, if I make (Picked Unit) damage (Random unit from (GroupLEAK)), wouldn't I be damaging an enemy before the hero actually falls on him?

Sorry, I'm a bit confused about this...

Regards