1. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  2. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  3. The Lich King demands your service! We've reached the 19th edition of the Icon Contest. Come along and make some chilling servants for the one true king.
    Dismiss Notice
  4. The 4th SFX Contest has started. Be sure to participate and have a fun factor in it.
    Dismiss Notice
  5. The poll for the 21st Terraining Contest is LIVE. Be sure to check out the entries and vote for one.
    Dismiss Notice
  6. The results are out! Check them out.
    Dismiss Notice
  7. Don’t forget to sign up for the Hive Cup. There’s a 555 EUR prize pool. Sign up now!
    Dismiss Notice
  8. The Hive Workshop Cup contest results have been announced! See the maps that'll be featured in the Hive Workshop Cup tournament!
    Dismiss Notice
  9. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

[Spell] Complex Spells with Triggers

Discussion in 'World Editor Help Zone' started by Abyssion, Feb 11, 2018.

  1. Abyssion

    Abyssion

    Joined:
    Jan 19, 2018
    Messages:
    126
    Resources:
    0
    Resources:
    0
    Hi all,
    I am making most of the Hero abilities on my map deal damage via trigger because I need dynamic damage as some of their spells are affected by Hero Stats. I know how to trigger the easy ones like single target damage or heals, and circle AOE damage or heals.

    The problem is when I want to trigger cone AOE damage or line AOE damage or chain damage or chain healing. How do I do this?

    I've read up a bit and it is said to use dummies with locust ability but I don't see it on the ability list.
    So how do I go about making dummies with this ever elusive "locust" ability and how to I trigger dynamic non-circle AOE damage?

    Hope I'm making sense.
    Thanks in advance.
     
  2. Wareditor

    Wareditor

    Joined:
    Jan 16, 2009
    Messages:
    681
    Resources:
    3
    Maps:
    3
    Resources:
    3
    A missile system would help tremendously to create fancy spells like that but it's quite complicated to use for newcomers.

    The best way to use dummies is to have a single unit dedicated to dummy casting. The unit is invisible, can cast any spell from any point and is unselectable by anyone (meaning it has Locust - the rawcode of the spell is 'Aloc'). You create it, add the spell you want it to cast, order to cast it and then remove (or recycle) it.
    Anyway, using dummy won't help you make scaling spells as dummies are only useful to cast vanilla spells. Meaning you can't make new effect by using dummies but only combination of vanilla effects. For instance a dummy can be used to turn a single target vanilla spell into an aoe spell. However a dummy won't help you make shockwave or chain lightning scale with a Hero's stat. For that, you would need a custom projectile system.
     
  3. Chaosy

    Chaosy

    Joined:
    Jun 9, 2011
    Messages:
    10,623
    Resources:
    18
    Maps:
    1
    Spells:
    11
    Tutorials:
    6
    Resources:
    18
    If it is an instant thing without missile it is still quite easy.
    There is a backstab tutorial on wc3c.net which is more or less what you want for a cone spell.
     
  4. Abyssion

    Abyssion

    Joined:
    Jan 19, 2018
    Messages:
    126
    Resources:
    0
    Resources:
    0
    For missile spells I do not use dummies at all, I just use a wait in game action before damaging the unit after the spell is cast. Like so:
    • Arcane Blast
      • Events
        • Unit - A unit Begins casting an ability
      • Conditions
        • (Ability being cast) Equal to Arcane Blast (Modera)
      • Actions
        • -------- StoreTarget Unit --------
        • Set ArcaneBlastTarget = (Target unit of ability being cast)
        • -------- Special Effect Based on Level --------
        • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • (Level of (Ability being cast) for (Casting unit)) Greater than or equal to 2
          • Then - Actions
            • Special Effect - Create a special effect attached to the weapon of (Casting unit) using Abilities\Spells\NightElf\Blink\BlinkTarget.mdl
          • Else - Actions
        • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • (Level of (Ability being cast) for (Casting unit)) Equal to 3
          • Then - Actions
            • Special Effect - Create a special effect attached to the origin of (Casting unit) using ArcaneExplosion.mdx
          • Else - Actions
        • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • (ArcaneBlastTarget has buff Spell Shield) Equal to False
          • Then - Actions
            • -------- Wait Ingame to Compensate for Missile Travel (Waiting TIme = Distance Between Units/Missile Speed) --------
            • Wait ((Distance between (Position of (Casting unit)) and (Position of ArcaneBlastTarget)) / 1200.00) game-time seconds
            • -------- Damage Target Unit (Damage = (Ability Level x 150) + (Hero Intelligence x Ability Level)) --------
            • Unit - Cause (Casting unit) to damage ArcaneBlastTarget, dealing ((150.00 x (Real((Level of (Ability being cast) for (Casting unit))))) + ((Real((Intelligence of (Casting unit) (Include bonuses)))) x (Real((Level of (Ability being cast) for (Casting unit)))))) damage of attack type Spells and damage type Magic
            • -------- Level 3 Target Special Effect --------
            • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
              • If - Conditions
                • (Level of (Ability being cast) for (Casting unit)) Equal to 3
              • Then - Actions
                • Special Effect - Create a special effect attached to the origin of ArcaneBlastTarget using ArcaneExplosion.mdx
              • Else - Actions
          • Else - Actions
            • -------- Wait Ingame to Compensate for Missile Travel (Waiting TIme = Distance Between Units/Missile Speed) --------
            • Wait ((Distance between (Position of (Casting unit)) and (Position of ArcaneBlastTarget)) / 1200.00) game-time seconds
            • -------- Level 3 Target Special Effect --------
            • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
              • If - Conditions
                • (Level of (Ability being cast) for (Casting unit)) Equal to 3
              • Then - Actions
                • Special Effect - Create a special effect attached to the origin of ArcaneBlastTarget using ArcaneExplosion.mdx
              • Else - Actions
            • -------- Remove Spell Shield Buff --------
            • Unit - Remove Spell Shield buff from ArcaneBlastTarget


    It's a bit clustered I know sorry but I find that a wait in-game does the job just fine. Do you think doing it this way is problematic?
    Can you elaborate on what a custom projectile system is?

    Thanks for getting back to me!

    Thanks I'll try to look it up.
     
    Last edited by a moderator: Feb 11, 2018
  5. Wareditor

    Wareditor

    Joined:
    Jan 16, 2009
    Messages:
    681
    Resources:
    3
    Maps:
    3
    Resources:
    3
    There are several problems with your trigger:
    - The event should be Unit - A unit Starts the effect of an ability because begins casting fires before mana is consumed and can be abused by players (casting without cost). For more information check out this.
    - You are not cleaning your special effects, meaning that they are kept in memory. If enough of them are made, your map will crash. This is what is called a memory leak. If you want to display an effect animation (meaning not keep the effect over time) you can destroy it as soon as it is created: it will still play its base or death animation. For more information on memory leaks, read this.
    - Using wait is never recommended. For spells it's really a bad idea because on multiple casts you are gonna have some serious problems (your spell will bug). You should use timer and hastables.
    - Your technique make it impossible for the targeted unit to dodge the projectile and if the unit moves after the spell is casted, it will get hit before the missile hits it.


    EDIT: please don't double post. use the Edit function
     
    Last edited: Feb 11, 2018
  6. Abyssion

    Abyssion

    Joined:
    Jan 19, 2018
    Messages:
    126
    Resources:
    0
    Resources:
    0
    And just when I thought my triggers weren't half bad! Thanks for the insight!
    Can I revise my trigger and show it to you when I feel I have corrected its problems?

    PS: Sorry for the double post... I thought I deleted it though.

    Edit:
    Also with regards to multiple casts, this map has unique heroes for all players so will it still be a problem for multiple spell casts? (In other words no hero appears twice and no hero has the same abilities as another).
     
    Last edited: Feb 11, 2018
  7. Wareditor

    Wareditor

    Joined:
    Jan 16, 2009
    Messages:
    681
    Resources:
    3
    Maps:
    3
    Resources:
    3
    Of course. Post it when you have corrected everything. Though as I told you, you are trying to do something very complex. To make it correctly you would need a projectile system which is something only an experience mapmaker could handle. So it's gonna be imperfect but at least you cna improve it ;)
     
    Last edited: Feb 11, 2018
  8. Abyssion

    Abyssion

    Joined:
    Jan 19, 2018
    Messages:
    126
    Resources:
    0
    Resources:
    0
    Thank you so much!
    I'm not scared of messing up, I will eventually move away from GUI and learn Jass and vJass, with nice people
    like you on the hive to help out it can't be too bad.

    This has gotten me a little concerned though if my one trigger has this many problems... what about the other 200+ triggers I have on this map? LOL
    They're not all spells of course some are very simple but others are kind of complicated (at least for me).

    They seem to work in test mode but what happens if I try to get a few community members to test my map on multiplayer? Oh boy!
     
  9. Wareditor

    Wareditor

    Joined:
    Jan 16, 2009
    Messages:
    681
    Resources:
    3
    Maps:
    3
    Resources:
    3
    We all have to start somewhere so it's normal to make mistakes when you don't have a full understanding of what is happening really when you do something with a trigger. I would recommend vising the tutorial section more often. It's a gold mine of knowledge!
    Glad we can help you improve!
     
  10. Licheus

    Licheus

    Joined:
    Apr 18, 2009
    Messages:
    562
    Resources:
    0
    Resources:
    0
    I usually try to build a mental image of a desirable geometric shape built with circles.

    A cone-shape could be a small circle at the position of the caster followed by progressively larger circles in the direction of the target point of the ability. Aggregate a temporary unit group with every alive, non-invulnerable enemy units in all of these circles and you have your targets.

    A line could be a lot of small circles from the position of the caster towards the target direction.

    Create a loop iterating over 1 to 10 for instance. In every loop iteration, you set a temporary point a certain distance from the caster in a certain direction. Use "Point With Polar Offset" for this. Your angle will be "Math - Angle Between Points": angle between (caster point) to (target point). So the new point will be a certain distance ("offset by distance") in the direction from the caster to the target.

    Your offset will be something like (LoopCounterVariable * 50). The first loop iteration will make a point 50 range in front of the caster in the direction of the target. Next will make a point 100 range in front, next 150 range etc. until you made 10 points with the last one being 500 range away. Pick units around every point every loop iteration and add them to a temporary unit group for target units. Lastly, pick every unit in this target group and damage them. Should look something like this:

    Trigger example without comments:
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Custom Point-Targeted Ability
    • Actions
      • Set Temp_Point_A = (Position of (Triggering unit))
      • Set Temp_Point_B = (Target point of ability being cast)
      • Set Temp_UnitGroup_B = (Units of type No Unit (Anti-Bug) (Dummy))
      • For each (Integer Temp_LoopCounter_A) from 1 to 10, do (Actions)
        • Loop - Actions
          • Set Temp_Point_C = (Temp_Point_A offset by ((Real(Temp_LoopCounter_A)) x 50.00) towards (Angle from Temp_Point_A to Temp_Point_B) degrees)
          • Set Temp_UnitGroup_A = (Units within 100.00 of Temp_Point_C matching ((((Matching unit) is alive) Equal to True) and ((((Matching unit) is A structure) Equal to False) and ((((Owner of (Matching unit)) is an ally of (Owner of (Triggering unit))) Equal to False) and ((((Matching uni
          • Custom script: call RemoveLocation( udg_Temp_Point_C )
          • Unit Group - Add all units of Temp_UnitGroup_A to Temp_UnitGroup_B
          • Custom script: call DestroyGroup( udg_Temp_UnitGroup_A )
      • Custom script: call RemoveLocation( udg_Temp_Point_B )
      • Custom script: call RemoveLocation( udg_Temp_Point_A )
      • Unit Group - Pick every unit in Temp_UnitGroup_B and do (Actions)
        • Loop - Actions
          • Unit - Cause (Triggering unit) to damage (Picked unit), dealing 200.00 damage of attack type Spells and damage type Unknown
      • Custom script: call DestroyGroup( udg_Temp_UnitGroup_B )
    Trigger example with comments:
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Custom Point-Targeted Ability
    • Actions
      • Set Temp_Point_A = (Position of (Triggering unit))
      • Set Temp_Point_B = (Target point of ability being cast)
      • -------- Anit-Bug: reset unit group b to a group with no units. Units cannot be added to a destroyed group --------
      • Set Temp_UnitGroup_B = (Units of type No Unit (Anti-Bug) (Dummy))
      • -------- Line AoE will start at the feet of the caster and reach for 600 range at the edge of the last circle --------
      • For each (Integer Temp_LoopCounter_A) from 1 to 10, do (Actions)
        • Loop - Actions
          • -------- Basic range is 10 · 50 = 500 in the direction of the target. Full AoE range is 500 + 100 = 600 (see unit group circle size further down below) --------
          • Set Temp_Point_C = (Temp_Point_A offset by ((Real(Temp_LoopCounter_A)) x 50.00) towards (Angle from Temp_Point_A to Temp_Point_B) degrees)
          • -------- AoE width is 100 range. Conditions determinates targets --------
          • Set Temp_UnitGroup_A = (Units within 100.00 of Temp_Point_C matching ((((Matching unit) is alive) Equal to True) and ((((Matching unit) is A structure) Equal to False) and ((((Owner of (Matching unit)) is an ally of (Owner of (Triggering unit))) Equal to False) and ((((Matching uni
          • Custom script: call RemoveLocation( udg_Temp_Point_C )
          • Unit Group - Add all units of Temp_UnitGroup_A to Temp_UnitGroup_B
          • Custom script: call DestroyGroup( udg_Temp_UnitGroup_A )
      • Custom script: call RemoveLocation( udg_Temp_Point_B )
      • Custom script: call RemoveLocation( udg_Temp_Point_A )
      • Unit Group - Pick every unit in Temp_UnitGroup_B and do (Actions)
        • Loop - Actions
          • Unit - Cause (Triggering unit) to damage (Picked unit), dealing 200.00 damage of attack type Spells and damage type Unknown
      • Custom script: call DestroyGroup( udg_Temp_UnitGroup_B )
     
  11. Abyssion

    Abyssion

    Joined:
    Jan 19, 2018
    Messages:
    126
    Resources:
    0
    Resources:
    0
    Hello There!
    Thanks for responding to my thread. I like the idea very much for an impale type ability, but for a shockwave type ability it looks
    like targets will not take damage when the shockwave missile actually hits them, unless I missed something? Unless there is a way
    to make a temp location circle around the missile?

    Thanks
     
  12. millzy

    millzy

    Joined:
    Jul 9, 2008
    Messages:
    1,540
    Resources:
    6
    Maps:
    5
    Spells:
    1
    Resources:
    6
    well for triggering missile spells like shockwave your going to have to go more advanced and get into MUI looping/periodic triggers witch is using 2 triggers 1 being the setup of variables your spell uses and the other being a periodic looping trigger that uses these variables.
    i know you said MUI wont be a issue for you in this map but it helps for the future and makes these triggers smoother and easyer to use in a way.

    MUI (Muilti Unit Instability) is basicly your trigger supporting more then 1 unit casting the spell with out it breaking. witch is done by using arrays or hashtables
    heres a MUI guide that uses arrays Visualize: Dynamic Indexing \
    heres a MUI guide that uses hashtables Hashtables and MUI

    im not great at explaining stuff so ill just give you a EXAMPLE from my map witch is a frost wave that freezes the units hit by it. break it up for you


    so you have your casting trigger setting up the variables for the spell (how far, damage , casting unit, ect)

    • frost Blast On
      • Events
        • Unit - A unit Starts the effect of an ability
      • Conditions
        • (Ability being cast) Equal to Frost Blast
      • Actions
        • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • (Number of units in WB) Equal to 0
          • Then - Actions
            • Trigger - Turn on Frost Blast Loop <gen>
          • Else - Actions
        • Set Times3 = (Times3 + 1)
        • Set WB_Hero[Times3] = (Casting unit)
        • Set WB_Point[1] = (Position of WB_Hero[Times3])
        • Set WB_Point[2] = (Target point of ability being cast)
        • Set WB_Distance[Times3] = 0.00
        • Set Reached_D[Times3] = 1005.00
        • Set WB_Speed[Times3] = 20.00
        • Set WB_Damage[Times3] = ((Real((Level of Frost Blast for WB_Hero[Times3]))) x 60.00)
        • Set WB_angel[Times3] = (Angle from WB_Point[1] to WB_Point[2])
        • Custom script: call RemoveLocation(udg_WB_Point[1])
        • Custom script: call RemoveLocation(udg_WB_Point[2])
        • Set WB_X[Times3] = (Position of WB_Hero[Times3])
        • Unit Group - Add WB_Hero[Times3] to WB


    more details of whats happening in this trigger and the variables
    the if then else at the start is turning on the looping trigger if not already turned on.
    Times3 - Setting up the array integer for each cast of the spell
    WB_Distance - how far the missile has traveled
    Reached_D - how far the missile will travel
    WB_speed - speed the missile will travel per loop
    WB - is a unit group is used for all the units casting the spell and turning it off when its not used (there are other ways of doing this)
    the rest i believe is self explanatory

    notic how each variable has a array that uses the integer that is set at the start



    then you have your looping/periodic trigger witch will use the variables you set up

    • Frost Blast Loop
      • Events
        • Time - Every 0.02 seconds of game time
      • Conditions
      • Actions
        • For each (Integer WB_Loop) from 1 to Times3, do (Actions)
          • Loop - Actions
            • Set WB_Distance[WB_Loop] = (WB_Distance[WB_Loop] + WB_Speed[WB_Loop])
            • Set XWB[1] = (WB_X[WB_Loop] offset by WB_Distance[WB_Loop] towards WB_angel[WB_Loop] degrees)
            • Special Effect - Create a special effect at XWB[1] using Abilities\Weapons\FrostWyrmMissile\FrostWyrmMissile.mdl
            • Special Effect - Destroy (Last created special effect)
            • Set WB_Group[WB_Loop] = (Units within 175.00 of XWB[1] matching (((Owner of (Matching unit)) Not equal to (Owner of WB_Hero[WB_Loop])) and ((((Matching unit) is alive) Equal to True) and (((Matching unit) is in Freezed[WB_Loop]) Equal to False))))
            • Unit Group - Pick every unit in WB_Group[WB_Loop] and do (Actions)
              • Loop - Actions
                • Unit - Cause WB_Hero[WB_Loop] to damage (Picked unit), dealing WB_Damage[WB_Loop] damage of attack type Spells and damage type Normal
                • Unit - Create 1 Dummy Arrow for (Owner of WB_Hero[WB_Loop]) at XWB[1] facing Default building facing degrees
                • Unit - Add Dummy Freeze to (Last created unit)
                • Unit - Hide (Last created unit)
                • Unit - Add a 1.00 second Generic expiration timer to (Last created unit)
                • Unit - Order (Last created unit) to Human Mountain King - Storm Bolt (Picked unit)
                • Unit Group - Add (Picked unit) to Freezed[WB_Loop]
            • Custom script: call DestroyGroup(udg_WB_Group[udg_WB_Loop])
            • Custom script: call RemoveLocation(udg_XWB[1])
            • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
              • If - Conditions
                • WB_Distance[WB_Loop] Greater than or equal to Reached_D[WB_Loop]
              • Then - Actions
                • Custom script: call RemoveLocation(udg_WB_X[udg_WB_Loop])
                • Unit Group - Pick every unit in Freezed[WB_Loop] and do (Actions)
                  • Loop - Actions
                    • Unit Group - Remove (Picked unit) from Freezed[WB_Loop]
                • Unit Group - Remove WB_Hero[WB_Loop] from WB
                • Set WB_Hero[WB_Loop] = No unit
                • Set WB_Distance[WB_Loop] = 0.00
                • Set WB_angel[WB_Loop] = 0.00
                • Set WB_Speed[WB_Loop] = 0.00
                • Set Reached_D[WB_Loop] = 0.00
                • Set WB_Damage[WB_Loop] = 0.00
                • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                  • If - Conditions
                    • (Number of units in WB) Equal to 0
                  • Then - Actions
                    • Set Times3 = 0
                    • Trigger - Turn off Water Blast Loop <gen>
                  • Else - Actions
              • Else - Actions


    details of whats going on

    -at the start you use a loop that goes though all the arrays
    -so first off we are adding how far the missile has travelled so far with WB_distance
    -XWB is the location the missle is atm
    -then we are creating the group of units you want the effect/damage to happen on that point. notice we check if they are in the freezed unit group witch is a unit group of the units already it by the spell other wise the units will be hit more then once and hit every 0.02 seconds. after the effects are done to the unit they are added to the freezed group.
    -then you have the if then else checking if the distance of the spell is finished if so null the variables and remove the caster from the WB unit group
    -then you have the last if then else checking if any units are using the trigger if not turn it off and reset the array integer.


    for your question about dummy units they a invisible unit that cast spells for you for effects basicly and dont have much tho do with what your asking for here. heres another guide u may find helpfull and it also explains the basics of dummy units and how to make 1 Basics of Trigger Enhancing Spells
     
    Last edited: Feb 13, 2018
  13. Licheus

    Licheus

    Joined:
    Apr 18, 2009
    Messages:
    562
    Resources:
    0
    Resources:
    0
    You're welcome.

    You're right. Coding spells to take effect after a delay rather than instantly is harder, as you can see from the responses of the nice people here who try to explain MUI. Generally you'll want to learn one of the traditional MUI solutions if you want it perfect. There are workarounds which might make life easier for you, but they're not perfect and are only suited to certain types of spells. Both solutions below have the following problems:
    • They do not retain the caster of the spell as the damage source, but rather let the dummy unit deal damage. The damage will still come from the right player, but not from the right unit.
    • They do not check if the unit is already damaged, and will damage targets several times if they are within range of the projectile at several interval checks. You can do a shockwave which explodes at impact or something smoothly, but not a shockwave which works like the default one.

    1) At spellcast, just create a dummy unit which will act like a projectile (give it the Locust ability). The dummy is created at the position of the caster and is facing the target point of ability being cast. Add an expiration timer to last created unit which will determine how long the missile will exist. Add the dummy to a unit group "Abi_Shockwave_Projectiles" or something. Then there's another trigger that is ran every x seconds which picks every unit in this unit group and moves picked unit forward to a point offset by some number in the facing direction of picked unit. Pick every enemy around this point and damage them. Preferably you'll want to turn off the trigger which runs every x second when Abi_Shockwave_Projectiles is empty, and turn it on again when Abi_Shockwave_Projectiles is not empty.

    2) You can do a loop like I did, but instead of picking units around a point every loop iteration you create a dummy unit with no model (set the model field to .mdl) at the point instead. Give this unit an expiration timer when it's created. Make the timer expire dynamicaly based on the LoopCounter variable to simulate delay: (LoopCounter * 0.1) seconds would make the first dummy die after 0.1 seconds, second after 0.2 etc and make the entire process take 1 second. Then you make another trigger with the event unit-type of dummy unit dies, and pick a temporary unit group around the dummy timer to damage.

    Tell me if you want examples of workarounds like these. Otherwise I think you should look into the traditional MUI stuff.
     
    Last edited: Feb 13, 2018