• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

How to make HOT MUI SPELL?

Status
Not open for further replies.
Level 6
Joined
Jul 2, 2013
Messages
153
Hello guys, I want to make a spell where a spell will heal units in 600 AoE each 2 seconds for 10 seconds for x2 int. Can you help me on the MUI part?

EDIT: I use GUI, don't know JASS.
 
Level 6
Joined
Jul 2, 2013
Messages
153
Thanks, I managed to make it myself. BTW, does the special effect leaks? I mean that's not a permanent special effect and it gets sort of "destroyed" by itself. ?

ALSO, I use array size 10 for most of the variables cuz I'm unsure what size to use? Is 10 ok ?
  • Aurora
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Aurora
    • Actions
      • Set Aurora_Index = (Aurora_Index + 1)
      • Set AuroraHero[Aurora_Index] = (Triggering unit)
      • Set AuroraGroup[Aurora_Index] = (Units within 500.00 of (Position of (Triggering unit)) matching (((Matching unit) belongs to an ally of (Owner of (Triggering unit))) Equal to True))
      • Set AuroraHealAmount[Aurora_Index] = (2 x (Intelligence of (Triggering unit) (Include bonuses)))
      • Set AuroraCount[Aurora_Index] = 0
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Aurora_Index Equal to 1
        • Then - Actions
          • Trigger - Turn on Aurora Loop <gen>
        • Else - Actions
  • Aurora Loop
    • Events
      • Time - Every 2.00 seconds of game time
    • Conditions
    • Actions
      • For each (Integer AuroraLoopInteger) from 1 to Aurora_Index, do (Actions)
        • Loop - Actions
          • Set AuroraCount[AuroraLoopInteger] = (AuroraCount[AuroraLoopInteger] + 2)
          • Unit Group - Pick every unit in AuroraGroup[AuroraLoopInteger] and do (Actions)
            • Loop - Actions
              • Unit - Set life of (Picked unit) to ((Life of (Picked unit)) + (Real(AuroraHealAmount[AuroraLoopInteger])))
              • Special Effect - Create a special effect attached to the origin of (Picked unit) using Abilities\Spells\Orc\HealingWave\HealingWaveTarget.mdl
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • AuroraCount[AuroraLoopInteger] Greater than or equal to 10
            • Then - Actions
              • Set AuroraHero[AuroraLoopInteger] = AuroraHero[Aurora_Index]
              • Set AuroraGroup[AuroraLoopInteger] = AuroraGroup[Aurora_Index]
              • Set AuroraCount[AuroraLoopInteger] = AuroraCount[Aurora_Index]
              • Set Aurora_Index = (Aurora_Index - 1)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • Aurora_Index Equal to 0
                • Then - Actions
                  • Trigger - Turn off (This trigger)
                • Else - Actions
            • Else - Actions
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
Special Effects leak so you need to use Destroy Special Effects.

Array initialization size of 10 is more than enough. It's best if you don't change it, just use the default values. In fact, since you're initializing Empty unit groups, using a value of 10 creates 10 unit group leaks. It's mentioned here.

And, it's best to use periodic timeout of 0.03 (in GUI) because using Every 2 sec is not precise. What I mean is, there's an unpredictable value between 0 and 2 sec before the effect starts. Example, if it was casted at time=1.8 sec, after 0.2 sec, the effect will immediately start. However if it was casted at time=2.1 sec, the effect will start after 1.9 sec. So what you have to do is use a time counter, which gets incremented every timeout and if the time counter is greater than 2, start the effect and reset the time counter.
 
Level 12
Joined
Jan 2, 2016
Messages
973
Personally I am a fan of hashtables. They make life easier (at least for me) :D
Here is a version, where units can have unlimited amount of AuRoar buffs. The healing is done every 2 seconds, (between 0 and 0,1 seconds) after casting.
  • Heal Init
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to AuRoar
    • Actions
      • Set point = (Position of (Triggering unit))
      • Unit Group - Pick every unit in (Units within 500.00 of point matching (((Triggering player) is an ally of (Owner of (Matching unit))) Equal to True)) and do (Actions)
        • Loop - Actions
          • Set integer = (Load 0 of (Key (Picked unit)) from Table)
          • Hashtable - Save (Intelligence of (Triggering unit) (Include bonuses)) as ((integer x 2) + 2) of (Key (Picked unit)) in Table
          • Hashtable - Save 10.10 as ((integer x 2) + 3) of (Key (Picked unit)) in Table
          • Hashtable - Save (integer + 1) as 0 of (Key (Picked unit)) in Table
          • Hashtable - Save ((Load 1 of (Key (Picked unit)) from Table) + 1) as 1 of (Key (Picked unit)) in Table
          • Unit Group - Add (Picked unit) to auroar
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (AuRoar <gen> is on) Equal to False
        • Then - Actions
          • Trigger - Turn on AuRoar <gen>
        • Else - Actions
      • Custom script: call RemoveLocation(udg_point)
  • AuRoar
    • Events
      • Time - Every 0.10 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in auroar and do (Actions)
        • Loop - Actions
          • For each (Integer loop) from ((Load 1 of (Key (Picked unit)) from (Last created hashtable)) - 1) to ((Load 0 of (Key (Picked unit)) from Table) - 1), do (Actions)
            • Loop - Actions
              • Set real = ((Load ((loop x 2) + 2) of (Key (Picked unit)) from Table) - 0.10)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (real mod 2.00) Equal to 0.00
                  • real Greater than or equal to 0.00
                • Then - Actions
                  • Unit - Set life of (Picked unit) to ((Life of (Picked unit)) + (Load ((loop x 2) + 2) of (Key (Picked unit)) from Table))
                  • Special Effect - Create a special effect attached to the origin of (Picked unit) using Abilities\Spells\Orc\HealingWave\HealingWaveTarget.mdl
                  • Special Effect - Destroy (Last created special effect)
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • real Equal to 0.00
                    • Then - Actions
                      • Hashtable - Save ((Load 1 of (Key (Picked unit)) from Table) - 1.00) as 1 of (Key (Picked unit)) in Table
                    • Else - Actions
                • Else - Actions
              • Hashtable - Save real as ((loop x 2) + 3) of (Key (Picked unit)) in Table
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Load 1 of (Key (Picked unit)) from Table) Equal to 0
                • Then - Actions
                  • Hashtable - Clear all child hashtables of child (Key (Picked unit)) in Table
                  • Unit Group - Remove (Picked unit) from auroar
                • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (auroar is empty) Equal to True
        • Then - Actions
          • Trigger - Turn off (This trigger)
        • Else - Actions
 
Level 6
Joined
Jul 2, 2013
Messages
153
Thanks all, btw elf, do u have that spell in a sample map? I dont know how to work with hashtables.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
This is one of the reasons I made Spell System:

  • Config
    • Events
      • Map Initialization
    • Conditions
    • Actions
      • Set Spell__Ability = Aurora
      • Set Spell__Filter_AllowAllies = True
      • Set Spell__Filter_AllowEnemies = False
      • Set Spell__OnEffect = OnEffect <gen>
      • Set Spell__OnLoop = DoT <gen>
      • Trigger - Run Spell System <gen>
  • OnEffect
    • Events
    • Conditions
    • Actions
      • Set Spell__Time = 2.00
      • Set AuroraCount[Spell__Index] = 5
      • Set AuroraHealAmount[Aurora_Index] = (2 x (Intelligence of Spell__Caster (Include bonuses)))
  • DoT
    • Events
    • Conditions
    • Actions
      • Set AuroraCount[Spell__Index] = AuroraCount[Spell__Index] - 1
      • If (All conditions are true) then
        • If - Conditions
          • AuroraCount[Spell__Index] Greater than 0
        • Then - Actions
          • Set Spell__Time = 2.00
          • Set Spell__InRangePoint = Spell__CastPoint
          • Set Spell__InRange = 600.00
          • Unit Group - Pick every unit in Spell__InRangeGroup and do (Actions)
            • Loop - Actions
              • Unit - Set life of (Picked unit) to ((Life of (Picked unit)) + (Real(AuroraHealAmount[Spell__Index])))
              • Special Effect - Create a special effect attached to the origin of (Picked unit) using Abilities\Spells\Orc\HealingWave\HealingWaveTarget.mdl
              • Special Effect - Destroy (Last Created Special Effect)
        • Else - Actions
 
Level 6
Joined
Jul 2, 2013
Messages
153
Thanks elf, and Bribe, nice system you have there. I'll consider using it, but it seems a little hard/confusing for me, I'm not advanced at GUI enough.
 
Level 37
Joined
Jul 22, 2015
Messages
3,485
Hey, you kind of got the hang of it, but there are some issues.
  • You shouldn't create Unit Groups using the (Matching unit) function. It makes them extremely hard to read, they are suuper inefficient, and they are a pain to edit when you want to add and or remove filters. Below is an example of a much better way of doing it.
    • Unit Group - Pick every unit in (Units within 500.00 of Location) and do (Actions)
      • Loop - Actions
        • Set TempUnit = (Picked unit)
        • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • (TempUnit belongs to an ally of Player) Equal to True
            • (TempUnit is alive) Equal to True
            • -------- add more conditions easily here --------
          • Then - Actions
            • -------- actions --------
          • Else - Actions
            • -------- TempUnit did not pass filters; do nothing -------
    Keep note that you will have to remove the group and location leak created here.​
  • If you're going to store the triggering unit into a variable, use them! I still see you using the GetTriggerUnit() function.
  • You leak a location when you initialize AuroraGroup[]
  • You should store the player into a variable for efficiency!
  • To improve the efficiency of your trigger, you should store the picked unit into a variable
  • Instead of converting AuroraHealAmount[] into a real every single time you pick a unit, just convert Intelligence of AuroraHero[] into a real when you start the spell
  • When you deindex, you need to decrement both Aurora_Index and AuroraLoopInteger
  • Follow Flux's suggestion for the Special effect leak + keeping your loop timers at 0.03 seconds
 
Level 13
Joined
Mar 19, 2010
Messages
870
You can use my vJass Version if u want.

JASS:
library HealOverTime initializer Init

    globals
        // This is how many times the struct loop will run in a single second. 30-40 is recomended
        private constant integer FPS = 40 
        // DO NOT TUCH! =)
        private constant real Interval = (1.0 / FPS)
    endglobals
    
    struct HOT
        unit Target
        real Health
        integer EndCount
        effect Effect
        static integer array Index
        static integer Total = 0
        static timer Tim = null
        static integer Count = -2147483648 // Just a random low number, it is needed
        
        static method Loop takes nothing returns nothing
            local HOT dat
            local integer i = 0

            set HOT.Count = HOT.Count + 1
            
            loop
                exitwhen i >= HOT.Total
                set dat = HOT.Index[i]

                if HOT.Count > dat.EndCount or GetUnitStatePercent(dat.Target, UNIT_STATE_LIFE, UNIT_STATE_MAX_LIFE) == 100 then
                    call DestroyEffect(dat.Effect)

                    set dat.Effect     = null
                    set dat.Target     = null
                
                    call dat.destroy()
                    
                    set HOT.Total = HOT.Total - 1
                    set HOT.Index[i] = HOT.Index[HOT.Total]

                    set i = i - 1
                else
                    call SetUnitState( dat.Target, UNIT_STATE_LIFE, RMaxBJ(0,GetUnitState(dat.Target, UNIT_STATE_LIFE) + dat.Health) )
                endif
                
                set i = i + 1
            endloop
            
            if HOT.Total == 0 then
                call PauseTimer(HOT.Tim)
            endif
        endmethod
        
        static method start takes unit Target, real Health, real Time, string Effect, string EffectAttach returns HOT
            local HOT dat = HOT.allocate()
            
            set dat.Target     = Target
            
            if Effect != "" and Effect != null then
                if EffectAttach != "" and EffectAttach != null then
                    set dat.Effect = AddSpecialEffectTarget(Effect, Target, EffectAttach)
                endif
            endif
            
            set dat.Health   = Health * Interval / Time
            set dat.EndCount = HOT.Count + R2I(Time / Interval)
            
            if HOT.Total == 0 then
                call TimerStart(HOT.Tim, Interval, true, function HOT.Loop)
            endif
            
            set HOT.Index[HOT.Total] = dat
            set HOT.Total = HOT.Total + 1
            
            return dat
        endmethod
    endstruct
    
//=========================================================================================*/

    private function Init takes nothing returns nothing
        set HOT.Tim = CreateTimer()
    endfunction

endlibrary


How to use?

JASS:
call HOT.start(target, HEAL_AMOUNT, HEAL_DURATION, EFFECT, ATT_POINT )

If u need help, just let me know ;)
 
Status
Not open for further replies.
Top