• 🏆 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!

Holy Orb v1.1

  • Like
Reactions: Kam
Creates an orb spinning around a hero. When the orb finds a target it will move to it and explode, dealing damage around the target.

JASS:
//#####################################################################
//#                          Holy Orb v1.1                            #
//#                                                                   #
//#  -Fixed leak in function StopShaking                              #
//#  -Fixed bug with multiple orbs                                    #
//#  -Tnx to SirNikolas for help                                      #
//#                                                                   #
//#####################################################################

//                  Aditional functions                  //
function HolyOrb_PreloadUnit takes integer i returns nothing
    call RemoveUnit(CreateUnit(Player(15), i, 0., 0., 0.))
endfunction

function HolyOrb_StopShakingTimed_Timer takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer hid = GetHandleId(t)
    if GetLocalPlayer() == Player(LoadInteger(udg_hash, hid, 0)) then
        call CameraSetTargetNoise(0., 0.)
        call CameraSetSourceNoise(0., 0.)
    endif
    call FlushChildHashtable(udg_hash, hid)
    call DestroyTimer(t)
    set t = null
endfunction

function HolyOrb_StopShakingTimed takes player p, real time returns nothing
    local timer t = CreateTimer()
    local integer hid = GetHandleId(t)
    call SaveInteger(udg_hash, hid, 0, GetPlayerId(p))
    call TimerStart(t, time, false, function HolyOrb_StopShakingTimed_Timer)
    set t = null
endfunction

//                  Spell settings                    //
function HolyOrb_SpellID takes nothing returns integer
    return 'A000' //Spell raw code
endfunction

function HolyOrb_BuffID takes nothing returns integer
    return 'B000' //Buff raw code
endfunction

function HolyOrb_DummyID takes nothing returns integer
    return 'e000' //Dummy raw code
endfunction

function HolyOrb_MaxDummy takes nothing returns integer
    return 5 //Amount of dummies
endfunction

function HolyOrb_SpellDamage takes nothing returns real
    return 120. //Damage
endfunction

function HolyOrb_OrbSpeed takes nothing returns real
    return 20. //Orb moving speed
endfunction

function HolyOrb_SpellEffect takes nothing returns string
    return "LightNova.mdx" //Final explode model
endfunction
//                          END                         //

function Trig_HolyOrb_Timer takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer hid = GetHandleId(t)
    local unit caster = LoadUnitHandle(udg_hash, hid, 0)
    local unit dummy
    local unit target = LoadUnitHandle(udg_hash, hid, -3)
    local real x = GetWidgetX(caster)
    local real y = GetWidgetY(caster)
    local integer index = 1
    local integer maxindex = HolyOrb_MaxDummy()
    local real angle = LoadReal(udg_hash, hid, maxindex + 1)
    local real tangle
    local real speed = HolyOrb_OrbSpeed()
    local real dist
    if LoadBoolean(udg_hash, hid, -2) then
        loop
            exitwhen index > maxindex
                set dummy = LoadUnitHandle(udg_hash, hid, index)
                set tangle = Atan2(GetWidgetY(target) - GetWidgetY(dummy), GetWidgetX(target) - GetWidgetX(dummy))
                set x = GetWidgetX(dummy) + speed * Cos(tangle)
                set y = GetWidgetY(dummy) + speed * Sin(tangle)
                call SetUnitPosition(dummy, x, y)
                set index = index + 1
        endloop
        set dist = SquareRoot((GetWidgetX(target) - GetWidgetX(dummy)) * (GetWidgetX(target) - GetWidgetX(dummy)) + (GetWidgetY(target) - GetWidgetY(dummy)) * (GetWidgetY(target) - GetWidgetY(dummy)))
        if dist <= 30. then
            set index = 1
            loop
                exitwhen index > maxindex
                    call RemoveUnit(LoadUnitHandle(udg_hash, hid, index))
                    set index = index + 1
            endloop
            if GetLocalPlayer() == GetOwningPlayer(caster) then
                call CameraSetTargetNoise(10., 300.)
                call CameraSetSourceNoise(10., 300.)
                call HolyOrb_StopShakingTimed(GetOwningPlayer(caster), .8)
            endif
            call DestroyEffect(AddSpecialEffect(HolyOrb_SpellEffect(), x, y))
            call GroupEnumUnitsInRange(udg_HolyOrbGroup, x, y, 500., null)
            loop
                set target = FirstOfGroup(udg_HolyOrbGroup)
                exitwhen target == null
                    if IsUnitEnemy(target, GetOwningPlayer(caster)) and not IsUnitType(target, UNIT_TYPE_DEAD) and not IsUnitType(target, UNIT_TYPE_STRUCTURE) and not IsUnitType(target, UNIT_TYPE_MAGIC_IMMUNE) then
                        call UnitDamageTarget(caster, target, GetUnitAbilityLevel(caster, HolyOrb_SpellID()) * HolyOrb_SpellDamage(), true, false, ATTACK_TYPE_HERO, DAMAGE_TYPE_MAGIC, WEAPON_TYPE_WHOKNOWS)
                        if GetLocalPlayer() == GetOwningPlayer(target) then
                            call CameraSetTargetNoise(10., 300.)
                            call CameraSetSourceNoise(10., 300.)
                            call HolyOrb_StopShakingTimed(GetOwningPlayer(target), .8)
                        endif
                    endif
                    call GroupRemoveUnit(udg_HolyOrbGroup, target)
            endloop
            call PauseTimer(t)
            call DestroyTimer(t)
            call FlushChildHashtable(udg_hash, hid)
        endif
    else
        call GroupEnumUnitsInRange(udg_HolyOrbGroup, x, y, 500., null)
        loop
            set target = FirstOfGroup(udg_HolyOrbGroup)
            exitwhen target == null
                if IsUnitEnemy(target, GetOwningPlayer(caster)) and not IsUnitType(target, UNIT_TYPE_DEAD) and not IsUnitType(target, UNIT_TYPE_STRUCTURE) and not IsUnitType(target, UNIT_TYPE_MAGIC_IMMUNE) then
                    call SaveUnitHandle(udg_hash, hid, -3, target)
                    call SaveBoolean(udg_hash, hid, -2, true)
                    exitwhen true
                endif
                call GroupRemoveUnit(udg_HolyOrbGroup, target)
        endloop
        loop
            exitwhen index > maxindex
                call SetUnitPosition(LoadUnitHandle(udg_hash, hid, index), x + 100. * Cos(angle), y + 100. * Sin(angle))
                set angle = angle + .06
                set index = index + 1
        endloop
    endif
    if GetUnitAbilityLevel(caster, HolyOrb_BuffID()) <= 0 then
        set index = 1
        loop
            exitwhen index > maxindex
                call RemoveUnit(LoadUnitHandle(udg_hash, hid, index))
                set index = index + 1
        endloop
        call PauseTimer(t)
        call DestroyTimer(t)
        call FlushChildHashtable(udg_hash, hid)
    endif
    call SaveReal(udg_hash, hid, maxindex + 1, angle)
    set caster = null
    set target = null
    set dummy = null
    set t = null
endfunction

function Trig_HolyOrb_Conditions takes nothing returns boolean
    local timer t
    local integer hid
    local unit caster
    local real x
    local real y
    local integer index = 1
    if GetSpellAbilityId() == HolyOrb_SpellID() then
        set t = CreateTimer()
        set hid = GetHandleId(t)
        set caster = GetTriggerUnit()
        set x = GetWidgetX(caster)
        set y = GetWidgetY(caster)
        call SaveAgentHandle(udg_hash, hid, 0, caster)
        loop
            exitwhen index > HolyOrb_MaxDummy()
                call SaveAgentHandle(udg_hash, hid, index, CreateUnit(GetTriggerPlayer(), HolyOrb_DummyID(), x, y, 0.))
                set index = index + 1
        endloop
        call TimerStart(t, .04, true, function Trig_HolyOrb_Timer)
    endif
    set caster = null
    set t = null
    return false
endfunction

function InitTrig_HolyOrb takes nothing returns nothing
    set gg_trg_HolyOrb = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(gg_trg_HolyOrb, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(gg_trg_HolyOrb, Condition(function Trig_HolyOrb_Conditions))
    call HolyOrb_PreloadUnit(HolyOrb_DummyID())
    call Preload(HolyOrb_SpellEffect())
    set udg_hash = InitHashtable()
endfunction

Keywords:
Holy Orb
Contents

Holy Orb / Священная сфера (Map)

Reviews
31 Jan 2012 Bribe: Rating amended to 4/5. Thanks for making the changes.

Moderator

M

Moderator

31 Jan 2012
Bribe: Rating amended to 4/5. Thanks for making the changes.
 
Level 10
Joined
Sep 19, 2011
Messages
527
Why are you using Widget instead of Unit?.

call GroupEnumUnitsInRange(udg_HolyOrbGroup, x, y, 500., null)
To enumerate, you can use bj_lastCreatedGroup.

I think that loops like this:
exitwhen index > maxindex

Should be:

JASS:
set index = value of maxindex
// ...
exitwhen index == 0
// Actions here
set index = index - 1
In the Trig_HolyOrb_Conditions function:
GetOwningPlayer(caster)

->

GetTriggerPlayer()

IsUnitEnemy(target, GetOwningPlayer(caster)) and not IsUnitType(target, UNIT_TYPE_DEAD) and not IsUnitType(target, UNIT_TYPE_STRUCTURE) and not IsUnitType(target, UNIT_TYPE_MAGIC_IMMUNE)

Maybe you can make filters like this configurables for the user.

call GroupClear(udg_HolyOrbGroup)
When you work with group-loops, you don't need this. Remember, the loop exits when the group is empty.

JASS:
//                  Spell settings                    //
function HolyOrb_SpellID takes nothing returns integer
    return 'A000' //Spell raw code
endfunction

function HolyOrb_BuffID takes nothing returns integer
    return 'B000' //Buff raw code
endfunction

function HolyOrb_DummyID takes nothing returns integer
    return 'e000' //Dummy raw code
endfunction

function HolyOrb_MaxDummy takes nothing returns integer
    return 5 //Amount of dummies
endfunction

function HolyOrb_SpellDamage takes nothing returns real
    return 500. //Damage
endfunction

function HolyOrb_OrbSpeed takes nothing returns real
    return 20. //Orb moving speed
endfunction

function HolyOrb_SpellEffect takes nothing returns string
    return "LightNova.mdx" //Final explode model
endfunction
//                          END                         //
This will be better on the top.

GetOwningPlayer(caster)

If you use something more time than twice, you should create a new variable. Is more easy to work and more efficient (you don't need to call the same functions two+ times).

I think that's all. Nice work.
 
Level 1
Joined
Dec 21, 2010
Messages
3
i try this skill with no cooldown, and create 3 orbs together.
then when they target the enemy unit (explode), the damage inflicted is still 1 orb.
i hope you can change the trigger so when 3 orbs explode together, the damage inflicted would be from the 3 orbs.
 
Top