Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
I'm trying to create a spell, that would make units invulnerable for ten seconds and take the half of their HP. (If a unit has less than 50% of his HP - he'll die). In order to make this work for many units simultaneously, I created a group. However, after the spell is applied, it makes a targeted unit invulnerable but it does not become vulnerable ten seconds again. What am I doing wrong here?
P.S: I've searched for a solution here, but many of treads are outdated.
You cannot use GUI wait inside pick every group loops. This is because TriggerSleepAction is not supported inside pick every group loop callback functions, and causes a thread crash at point of execution.
What you want to do is store the group of affected units, make them all invulnerable with a pick every loop, wait 5 seconds outside the loop, and then make them all vulnerable and remove the appropriate life with another pick every group loop.
You might want to cause nearby enemy units to deal fatal damage to units below 50% current life. This is to prevent a kill credit exploit where a player could purposely use the ability to deny enemies kill credit (gold, exp, e.t.c.). Similar to minion kill blocking in DotA.
You cannot use GUI wait inside pick every group loops. This is because TriggerSleepAction is not supported inside pick every group loop callback functions, and causes a thread crash at point of execution.
What you want to do is store the group of affected units, make them all invulnerable with a pick every loop, wait 5 seconds outside the loop, and then make them all vulnerable and remove the appropriate life with another pick every group loop.
You might want to cause nearby enemy units to deal fatal damage to units below 50% current life. This is to prevent a kill credit exploit where a player could purposely use the ability to deny enemies kill credit (gold, exp, e.t.c.). Similar to minion kill blocking in DotA.
But my next problem are special effects, that appear after casting the spell. I have to add them to a store. However, I need arrays this time. I checked the tutorials, but I'm still not sure, which of the variables (effect with/no array and an integer with/no array) and what order to use.
But my next problem are special effects, that appear after casting the spell. I have to add them to a store. However, I need arrays this time. I checked the tutorials, but I'm still not sure, which of the variables (effect with/no array and an integer with/no array) and what order to use.
Turn the array into an array list. Use another global integer variable to track the current end of the list. Every time you add an effect to it, increment this variable by 1. At the end of the ability you loop from the first index to the end of list variable, destroying the effects.
I kinda get it. But how can I connect an effect and an integer variable? On the picture the red one is an array with size. The blue is a normal integer. It's still not working.
Or did I understand you wrong? Am I going to have to use the JASS from this tutorial and this tutorial instead? Oh, Godd*** it! I guess, I'll have to read the flipping manual. Last question: when the code is ready, may I post it here, so somebody would correct it if necessary?
I kinda get it. But how can I connect an effect and an integer variable? On the picture the red one is an array with size. The blue is a normal integer. It's still not working.
Hello. It's me again. I've come this far with the spell code. I used an existing spell and made it harm its target unit or kill it (depends, if it has less or more than 50% of its HP). And then I created global variables and the loop, as you've advised. However, it shows me this syntax error: unexpected "EffectList"?
If it's easy to make this right, you can write it here;
BUT
I it's not, than I ask you to write the while code of the spell. I could pay for it a little, if you want.
"specialEffect" is not a valid JASS type. You probably meant to use effect.
"with initial value 0" is not valid JASS code. You need to write the initial value to the array indices before you use them, but in your case this is not needed since they have an uninitialized value of 0 already.
"with size 1" is not valid JASS code. JASS arrays are dynamic arrays that will automatically allocate space up the the array maximum size constant.
"Set" is not valid JASS. Like a lot of programming languages, JASS is case sensitive. To set a variable you start the line with set.
"(Last created special effect)" is not valid JASS. You either assign the variable to the effect when you create it, or you need to call the function that GUI wraps GetLastCreatedEffectBJ or reference the variable GUI uses internally, bj_lastCreatedEffect, directly.
I do not think calling TriggerSleepAction in the initialization thread is allowed. It is likely to cause a thread crash or unexpected behaviour such as delaying the initialization of unrelated triggers.
"For each Integer A from 1 to EffectListEnd, do (Actions)" is not valid JASS. JASS does not support for loops, you need to emulate them using a conventional loop. This is done by starting the loop with loop, applying the end condition check at the top of the loop body with an exitwhen boolean statement where boolean is replaced with your test logic, and then perform the increment logic to your variable at the bottom of the loop body.
"Special Effect - Destroy" is not valid JASS. You probably meant to call DestroyEffect.
"(Integer A)" is not valid JASS. Reference the variable used internally from the extract below.
Code:
// Utility function vars
integer bj_forLoopAIndex = 0
integer bj_forLoopBIndex = 0
integer bj_forLoopAIndexEnd = 0
integer bj_forLoopBIndexEnd = 0
Hello. It's me again. I've come this far with the spell code. I used an existing spell and made it harm its target unit or kill it (depends, if it has less or more than 50% of its HP). And then I created global variables and the loop, as you've advised.
If you want to use GUI, then stick to using GUI. Otherwise you will need to write everything in JASS. JASS does not understand English text form of GUI, that is not valid JASS code.
Your spell logic does not really make sense. You are not creating any special effects and instead are trying setup and destroy a list once only at map initialisation after stalling the entire map initialisation thread for approximately 10 real time seconds. You probably want to process the special effects in the action function body.
"specialEffect" is not a valid JASS type. You probably meant to use effect.
"with initial value 0" is not valid JASS code. You need to write the initial value to the array indices before you use them, but in your case this is not needed since they have an uninitialized value of 0 already.
"with size 1" is not valid JASS code. JASS arrays are dynamic arrays that will automatically allocate space up the the array maximum size constant.
"Set" is not valid JASS. Like a lot of programming languages, JASS is case sensitive. To set a variable you start the line with set.
"(Last created special effect)" is not valid JASS. You either assign the variable the the effect when you create it, or you need to call the function that GUI wraps GetLastCreatedEffectBJ or reference the variable GUI uses internally, bj_lastCreatedEffect, directly.
I do not think calling TriggerSleepAction in the initialization thread is allowed. It is likely to cause a thread crash or unexpected behaviour such as delaying the initialization of unrelated triggers.
"For each Integer A from 1 to EffectListEnd, do (Actions)" is not valid JASS. JASS does not support for arrays, you need to emulate them using a conventional loop. This is done by starting the loop with loop, applying the end condition check at the top of the loop body with an exitwhen boolean statement where boolean is replaced with your test logic, and then perform the increment logic to your variable at the bottom of the loop body.
"Special Effect - Destroy" is not valid JASS. You probably meant to call DestroyEffect.
"(Integer A)" is not valid JASS. Reference the variable used internally from the extract below.
Code:
// Utility function vars
integer bj_forLoopAIndex = 0
integer bj_forLoopBIndex = 0
integer bj_forLoopAIndexEnd = 0
integer bj_forLoopBIndexEnd = 0
If you want to use GUI, then stick to using GUI. Otherwise you will need to write everything in JASS. JASS does not understand English text form of GUI, that is not valid JASS code.
Your spell logic does not really make sense. You are not creating any special effects and instead are trying setup and destroy a list once only at map initialisation after stalling the entire map initialisation thread for approximately 10 real time seconds. You probably want to process the special effects in the action function body.
You seem to be struggling. There is no reason to try to create a bunch of timed effects that you have to keep track of when you can simply use a buff to do it for you. Create some generic buff ability that doesn't do anything (other than give the buff for 10 seconds), have a dummy caster apply it to the targeted unit, and then check all units with that buff periodically to remove invulnerability from units whose buff has expired. This will work with not only multiple simultaneous casts but also multiple on the same target (if this spell can target invulnerable units).
Events
Unit - A unit starts the effect of an ability
Conditions
(Ability being cast) equal to Unholy Armor
Actions
Set UA_Target = (Target unit of ability being cast)
Set TempPoint = (Position of UA_Target)
Unit - Create 1 DUMMY CASTER UNIT for (Owner of UA_Target) at TempPoint facing (Default building facing) degrees
Set UA_Dummy = (Last created unit)
Unit - Add YOUR BUFF ABILITY to UA_Dummy
Unit - Set level of YOUR BUFF ABILITY for UA_Dummy to (Level of (Ability being cast) for (Triggering Unit))
Unit - Add a 1.00 second generic expiration timer to UA_Dummy
Set UA_Pct = ((Percentage life of UA_Target) - 50.00)
If (All conditions are true) then do (Then actions) else do (Else actions)
If - Conditions
UA_Pct less than or equal to 0.00
Then - Actions
Custom script: set bj_wantDestroyGroup = true
Set UA_Dummy = (Random unit from (Units within 1000.00 of TempPoint matching (((Matching Unit) belongs to an enemy of (Owner of UA_Target)) equal to True)))
If (All conditions are true then do (Then actions) else do (Else actions)
If - Conditions
UA_Dummy equal to (No unit)
Then - Actions
Set UA_Dummy = (Triggering Unit)
Else - Actions
Unit - Set life of UA_Target to 1.00
Unit - Cause UA_Dummy to damage UA_Target, dealing 100.00 damage of attack type Chaos and damage type Universal
Else - Actions
Unit - Remove Invulnerable (Neutral) from UA_Target
Unit - Order UA_Dummy to THE CORRECT ORDER FOR YOUR BUFF ABILITY UA_Target
Unit - Set life of UA_Target to UA_Pct%
Unit - Add Invulnerable (Neutral) to UA_Target
Unit Group - Add UA_Target to UA_Group
Custom script: call RemoveLocation(udg_TempPoint)
Events
Time - Every 0.25 seconds of game-time
Conditions
Actions
Unit Group - Pick every unit in UA_Group and do (Actions)
Loop - Actions
Set UA_Target = (Picked unit)
If (All conditions are true then do (Then actions) else do (Else actions)
If - Conditions
(UA_Target has buff YOUR BUFF ABILITY'S BUFF) equal to False
Then - Actions
Unit - Remove Invulnerable (Neutral) from UA_Target
Unit Group - Remove UA_Target from UA_Group
Else - Actions
For this to work it is very important that your dummy unit is properly configured so that it can cast instantly without turning:
Movement speed base: 0
Movement type: NONE
Cast backswing: 0.00
Cast point: 0.00
Unit ability: Locust ('aloc')
Remove everything that might allow a player to know that the unit exists, like model/shadow/attacks/minimap/icons/classifications
You seem to be struggling. There is no reason to try to create a bunch of timed effects that you have to keep track of when you can simply use a buff to do it for you. Create some generic buff ability that doesn't do anything (other than give the buff for 10 seconds), have a dummy caster apply it to the targeted unit, and then check all units with that buff periodically to remove invulnerability from units whose buff has expired. This will work with not only multiple simultaneous casts but also multiple on the same target (if this spell can target invulnerable units).
Events
Unit - A unit starts the effect of an ability
Conditions
(Ability being cast) equal to Unholy Armor
Actions
Set UA_Target = (Target unit of ability being cast)
Set TempPoint = (Position of UA_Target)
Unit - Create 1 DUMMY CASTER UNIT for (Owner of UA_Target) at TempPoint facing (Default building facing) degrees
Set UA_Dummy = (Last created unit)
Unit - Add YOUR BUFF ABILITY to UA_Dummy
Unit - Set level of YOUR BUFF ABILITY for UA_Dummy to (Level of (Ability being cast) for (Triggering Unit))
Unit - Add a 1.00 second generic expiration timer to UA_Dummy
Set UA_Pct = ((Percentage life of UA_Target) - 50.00)
If (All conditions are true) then do (Then actions) else do (Else actions)
If - Conditions
UA_Pct less than or equal to 0.00
Then - Actions
Custom script: set bj_wantDestroyGroup = true
Set UA_Dummy = (Random unit from (Units within 1000.00 of TempPoint matching (((Matching Unit) belongs to an enemy of (Owner of UA_Target)) equal to True)))
If (All conditions are true then do (Then actions) else do (Else actions)
If - Conditions
UA_Dummy equal to (No unit)
Then - Actions
Set UA_Dummy = (Triggering Unit)
Else - Actions
Unit - Set life of UA_Target to 1.00
Unit - Cause UA_Dummy to damage UA_Target, dealing 100.00 damage of attack type Chaos and damage type Universal
Else - Actions
Unit - Remove Invulnerable (Neutral) from UA_Target
Unit - Order UA_Dummy to THE CORRECT ORDER FOR YOUR BUFF ABILITY UA_Target
Unit - Set life of UA_Target to UA_Pct%
Unit - Add Invulnerable (Neutral) to UA_Target
Unit Group - Add UA_Target to UA_Group
Custom script: call RemoveLocation(udg_TempPoint)
Events
Time - Every 0.25 seconds of game-time
Conditions
Actions
Unit Group - Pick every unit in UA_Group and do (Actions)
Loop - Actions
Set UA_Target = (Picked unit)
If (All conditions are true then do (Then actions) else do (Else actions)
If - Conditions
(UA_Target has buff YOUR BUFF ABILITY'S BUFF) equal to False
Then - Actions
Unit - Remove Invulnerable (Neutral) from UA_Target
Unit Group - Remove UA_Target from UA_Group
Else - Actions
For this to work it is very important that your dummy unit is properly configured so that it can cast instantly without turning:
Movement speed base: 0
Movement type: NONE
Cast backswing: 0.00
Cast point: 0.00
Unit ability: Locust ('aloc')
Remove everything that might allow a player to know that the unit exists, like model/shadow/attacks/minimap/icons/classifications
Yes, I am. Thank you very much! And now I'm so happy I don't need to write those custom scripts - "Custom script: set bj_wantDestroyGroup = true" and "Custom script: call RemoveLocation(udg_TempPoint)" - by myself.
I'd also need another spell - Raise Ded - but it must work like in Warcraft I: the player will have to cast it by himself and also chose a corpse by himself to raise a skeleton from.
C0Memory leaks For a quick lookup on most important actions, read Things That Leak. Introduction Object Leaks Reference Leaks Miscellaneous Conclusion C1Introduction If your computer's memory keeps occupied with stuff you already lost access to, it's called memory leak. It slows down the...
www.hiveworkshop.com
You can learn yourself; it's not difficult or complicated.
Why is manually targeting a corpse necessary for you? WC3 Raise Dead automatically targets a corpse within range when cast for the same functionality.
C0Memory leaks For a quick lookup on most important actions, read Things That Leak. Introduction Object Leaks Reference Leaks Miscellaneous Conclusion C1Introduction If your computer's memory keeps occupied with stuff you already lost access to, it's called memory leak. It slows down the...
www.hiveworkshop.com
You can learn yourself; it's not difficult or complicated.
Why is manually targeting a corpse necessary for you? WC3 Raise Dead automatically targets a corpse within range when cast for the same functionality.
I'd also need another spell - Raise Ded - but it must work like in Warcraft I: the player will have to cast it by himself and also chose a corpse by himself to raise a skeleton from.
Then you'd essentially want to create a dummy ability that lets you select a target area in which a dummy unit casts the Raise Dead ability. Unless you specifically want it to be point-and-click, which makes the issue a lot harder.
You seem to be struggling. There is no reason to try to create a bunch of timed effects that you have to keep track of when you can simply use a buff to do it for you. Create some generic buff ability that doesn't do anything (other than give the buff for 10 seconds), have a dummy caster apply it to the targeted unit, and then check all units with that buff periodically to remove invulnerability from units whose buff has expired. This will work with not only multiple simultaneous casts but also multiple on the same target (if this spell can target invulnerable units).
Events
Unit - A unit starts the effect of an ability
Conditions
(Ability being cast) equal to Unholy Armor
Actions
Set UA_Target = (Target unit of ability being cast)
Set TempPoint = (Position of UA_Target)
Unit - Create 1 DUMMY CASTER UNIT for (Owner of UA_Target) at TempPoint facing (Default building facing) degrees
Set UA_Dummy = (Last created unit)
Unit - Add YOUR BUFF ABILITY to UA_Dummy
Unit - Set level of YOUR BUFF ABILITY for UA_Dummy to (Level of (Ability being cast) for (Triggering Unit))
Unit - Add a 1.00 second generic expiration timer to UA_Dummy
Set UA_Pct = ((Percentage life of UA_Target) - 50.00)
If (All conditions are true) then do (Then actions) else do (Else actions)
If - Conditions
UA_Pct less than or equal to 0.00
Then - Actions
Custom script: set bj_wantDestroyGroup = true
Set UA_Dummy = (Random unit from (Units within 1000.00 of TempPoint matching (((Matching Unit) belongs to an enemy of (Owner of UA_Target)) equal to True)))
If (All conditions are true then do (Then actions) else do (Else actions)
If - Conditions
UA_Dummy equal to (No unit)
Then - Actions
Set UA_Dummy = (Triggering Unit)
Else - Actions
Unit - Set life of UA_Target to 1.00
Unit - Cause UA_Dummy to damage UA_Target, dealing 100.00 damage of attack type Chaos and damage type Universal
Else - Actions
Unit - Remove Invulnerable (Neutral) from UA_Target
Unit - Order UA_Dummy to THE CORRECT ORDER FOR YOUR BUFF ABILITY UA_Target
Unit - Set life of UA_Target to UA_Pct%
Unit - Add Invulnerable (Neutral) to UA_Target
Unit Group - Add UA_Target to UA_Group
Custom script: call RemoveLocation(udg_TempPoint)
Events
Time - Every 0.25 seconds of game-time
Conditions
Actions
Unit Group - Pick every unit in UA_Group and do (Actions)
Loop - Actions
Set UA_Target = (Picked unit)
If (All conditions are true then do (Then actions) else do (Else actions)
If - Conditions
(UA_Target has buff YOUR BUFF ABILITY'S BUFF) equal to False
Then - Actions
Unit - Remove Invulnerable (Neutral) from UA_Target
Unit Group - Remove UA_Target from UA_Group
Else - Actions
For this to work it is very important that your dummy unit is properly configured so that it can cast instantly without turning:
Movement speed base: 0
Movement type: NONE
Cast backswing: 0.00
Cast point: 0.00
Unit ability: Locust ('aloc')
Remove everything that might allow a player to know that the unit exists, like model/shadow/attacks/minimap/icons/classifications
Hello again. I did everything you wrote and it worked!.. Almost. The problem is: Although I delete all the original buffs and create an ability that doesn't do anything - it still manages to apply its original buff. For instance, if I take Sleep - it makes the unit invulnerable and takes half of his HP, but still puts a unit asleep. With Polymorph it turns targeted unit into a sheep.
1. What do I do wrong?
2. What did you mean by " THE CORRECT ORDER FOR YOUR BUFF ABILITY"?
You seem to be struggling. There is no reason to try to create a bunch of timed effects that you have to keep track of when you can simply use a buff to do it for you. Create some generic buff ability that doesn't do anything (other than give the buff for 10 seconds), have a dummy caster apply it to the targeted unit, and then check all units with that buff periodically to remove invulnerability from units whose buff has expired. This will work with not only multiple simultaneous casts but also multiple on the same target (if this spell can target invulnerable units).
Events
Unit - A unit starts the effect of an ability
Conditions
(Ability being cast) equal to Unholy Armor
Actions
Set UA_Target = (Target unit of ability being cast)
Set TempPoint = (Position of UA_Target)
Unit - Create 1 DUMMY CASTER UNIT for (Owner of UA_Target) at TempPoint facing (Default building facing) degrees
Set UA_Dummy = (Last created unit)
Unit - Add YOUR BUFF ABILITY to UA_Dummy
Unit - Set level of YOUR BUFF ABILITY for UA_Dummy to (Level of (Ability being cast) for (Triggering Unit))
Unit - Add a 1.00 second generic expiration timer to UA_Dummy
Set UA_Pct = ((Percentage life of UA_Target) - 50.00)
If (All conditions are true) then do (Then actions) else do (Else actions)
If - Conditions
UA_Pct less than or equal to 0.00
Then - Actions
Custom script: set bj_wantDestroyGroup = true
Set UA_Dummy = (Random unit from (Units within 1000.00 of TempPoint matching (((Matching Unit) belongs to an enemy of (Owner of UA_Target)) equal to True)))
If (All conditions are true then do (Then actions) else do (Else actions)
If - Conditions
UA_Dummy equal to (No unit)
Then - Actions
Set UA_Dummy = (Triggering Unit)
Else - Actions
Unit - Set life of UA_Target to 1.00
Unit - Cause UA_Dummy to damage UA_Target, dealing 100.00 damage of attack type Chaos and damage type Universal
Else - Actions
Unit - Remove Invulnerable (Neutral) from UA_Target
Unit - Order UA_Dummy to THE CORRECT ORDER FOR YOUR BUFF ABILITY UA_Target
Unit - Set life of UA_Target to UA_Pct%
Unit - Add Invulnerable (Neutral) to UA_Target
Unit Group - Add UA_Target to UA_Group
Custom script: call RemoveLocation(udg_TempPoint)
Events
Time - Every 0.25 seconds of game-time
Conditions
Actions
Unit Group - Pick every unit in UA_Group and do (Actions)
Loop - Actions
Set UA_Target = (Picked unit)
If (All conditions are true then do (Then actions) else do (Else actions)
If - Conditions
(UA_Target has buff YOUR BUFF ABILITY'S BUFF) equal to False
Then - Actions
Unit - Remove Invulnerable (Neutral) from UA_Target
Unit Group - Remove UA_Target from UA_Group
Else - Actions
For this to work it is very important that your dummy unit is properly configured so that it can cast instantly without turning:
Movement speed base: 0
Movement type: NONE
Cast backswing: 0.00
Cast point: 0.00
Unit ability: Locust ('aloc')
Remove everything that might allow a player to know that the unit exists, like model/shadow/attacks/minimap/icons/classifications
Hello again. I did everything you wrote and it worked!.. Almost. The problem is: Although I delete all the original buffs and create an ability that doesn't do anything - it still manages to apply its original buff. For instance, if I take Sleep - it makes the unit invulnerable and takes half of his HP, but still puts a unit asleep. With Polymorph it turns targeted unit into a sheep.
1. What do I do wrong?
2. What did you mean by " THE CORRECT ORDER FOR YOUR BUFF ABILITY"?
Those abilities have hardcoded effects, so you just need to pick a different ability. Either one without unique effects or one that can have its effects disabled by editing the spell's OE data fields. For dispellable buffs/debuffs I would use Rejuvenation and Cripple. For non-dispellable buffs/debuffs I'd use ?? and Ensnare. I don't believe Channel can carry a buff past the channel window.
In order to tell the dummy to cast the buff ability, you must give it an order. The order will the the base order for the spell (which you can't change for most abilities except Channel, Charge Gold & Lumber), like this:
Unit - Order YOUR_DUMMY_UNIT to Human Priest - Heal (Target unit of ability being cast)
Those abilities have hardcoded effects, so you just need to pick a different ability. Either one without unique effects or one that can have its effects disabled by editing the spell's OE data fields. For dispellable buffs/debuffs I would use Rejuvenation and Cripple. For non-dispellable buffs/debuffs I'd use ?? and Ensnare. I don't believe Channel can carry a buff past the channel window.
In order to tell the dummy to cast the buff ability, you must give it an order. The order will the the base order for the spell (which you can't change for most abilities except Channel, Charge Gold & Lumber), like this:
Unit - Order YOUR_DUMMY_UNIT to Human Priest - Heal (Target unit of ability being cast)
This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
By continuing to use this site, you are consenting to our use of cookies.