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

jass]

Level 16
Joined
Dec 15, 2011
Messages
1,423
JASS:
scope spell
    globals
        private constant        integer         SPHERE_UNIT_ID       = 'h000'
        private constant        integer         SPHERE_SPELL_ID      = 'A001'
        private constant        integer         SPHERE_EFFECT_ID     = 'A000'
        private constant        integer         SPHERE_BUFF_ID       = 'B000'
        private constant        integer         SPHERE_SUB_ID        = 'A002'
        private constant        string          SPHERE_CAST_EFFECT   = "Abilities\\Spells\\Other\\Drain\\ManaDrainTarget.mdl"
        private constant        string          SPHERE_SOUL_EFFECT   = "Abilities\\Spells\\Undead\\ReplenishMana\\SpiritTouchTarget.mdl"
        private constant        string          SPHERE_TARGET_EFFECT = "Abilities\\Spells\\Items\\TomeOfRetraining\\TomeOfRetrainingCaster.mdl"
        private constant        real            SPHERE_SIZE          = 2
        private constant        real            SPHERE_DAMAGE_PERCENT = 0.24
        private constant        real            SPHERE_DAMAGE_AOE    = 275
    
        private constant        integer         DATA_DEFAULT         = 2
        private                 integer         Data_Max             = 0
        private                 integer array   Data_Stack 
        private                 hashtable       Data_Storage         = InitHashtable()
    endglobals
    //============================================//
    struct Sphere extends Pulling
            //============================================//
        private              unit        caster
        private              unit        target
        private              unit        sphere
        private              timer       ti
        private              group       soulgroup
        private              effect      sfx_cast

        
        

        
            //=========================================================//
            //===================== SUB ABILITY =======================//
            //=========================================================//
            
    private static method onBurn takes nothing returns nothing
        local thistype d
        local thistype p
        local integer i
        local unit u
        local group g
        local real dx
        local real dy
        local effect sfx
        local real dmg
        
        set i = 0
        loop
            set i = i + 1
            set d = Data_Stack[i]
            if d.caster == GetTriggerUnit() then
                set g = CreateGroup()
                call GroupAddGroup(d.soulgroup, g)
                loop
                    set u = FirstOfGroup(g)
                    exitwhen u == null
                    set dx = GetUnitX(d.sphere) - GetUnitX(u)
                    set dy = GetUnitY(d.sphere) - GetUnitY(u)
                    if SquareRoot( dx * dx + dy * dy ) <= SPHERE_DAMAGE_AOE  then
                        set p = LoadInteger( Data_Storage , 0, GetHandleId(u) )
                        if GetUnitState(p.target, UNIT_STATE_LIFE) > 0 then
                            set dmg = GetUnitState(p.target, UNIT_STATE_MAX_LIFE) * SPHERE_DAMAGE_PERCENT
                            call UnitDamageTarget( d.caster, p.target, dmg, true , false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS ) 
                            call UnitRemoveAbility( p.target, SPHERE_BUFF_ID )
                            set sfx = AddSpecialEffect( SPHERE_TARGET_EFFECT, GetUnitX(p.target), GetUnitY(p.target) )
                            call DestroyEffect(sfx)
                        endif
                        call RemoveUnit(u)
                        set sfx = AddSpecialEffect( SPHERE_SOUL_EFFECT, GetUnitX(u), GetUnitY(u) )
                        call DestroyEffect(sfx)
                        call GroupRemoveUnit(d.soulgroup, u)
                    endif
                    call GroupRemoveUnit(g, u)
                    
                endloop
                call DestroyGroup(g)

            endif
            exitwhen i == Data_Max
        endloop
    endmethod
            
    private static method BurnFilt takes nothing returns boolean
        return (GetSpellAbilityId() == SPHERE_SUB_ID)
    endmethod
            //=========================================================//
            //===================== MAIN ABILITY ======================//
            //=========================================================//
            
    private static method GetFilter takes nothing returns boolean
        return true
    endmethod
    
    private static method onExpired takes nothing returns nothing
        local thistype d = GetTimerData(GetExpiredTimer())
        local thistype p
        local unit     u
        local effect   sfx
        
        call SetUnitTimeScale(d.sphere, 1.0 )
        call KillUnit(d.sphere)
        
        loop
            set u = FirstOfGroup(d.soulgroup)
            exitwhen u == null
            set p = LoadInteger( Data_Storage , 0, GetHandleId(u) )
            set sfx = AddSpecialEffect( SPHERE_SOUL_EFFECT, GetUnitX(u), GetUnitY(u) )
            call DestroyEffect(sfx)
            call RemoveUnit(u)
            
            call UnitRemoveAbility( p.target, SPHERE_BUFF_ID )
            set p.target = null
            call GroupRemoveUnit(d.soulgroup, u)
        endloop
        
        call ReleaseTimer(d.ti)
        call DestroyGroup(d.soulgroup)
        set d.sphere = null
        call d.destroy()
        if d == Data_Max then
            set Data_Stack[d] = Data_Stack[Data_Max]
            set Data_Max = Data_Max - 1
        endif
    endmethod
    
    private static method onDelay takes nothing returns nothing
        local thistype d = GetTimerData(GetExpiredTimer())
        local location loc = GetUnitLoc(d.sphere)
        local group    g = CreateGroup()
        local unit     u
        local unit     soul
        local unit     dummy
        call GroupEnumUnitsInRangeOfLoc( g, loc, 750, function thistype.GetFilter )
        call SetUnitTimeScale(d.sphere, 0)

        loop
            set u = FirstOfGroup(g)
            exitwhen u == null
            if IsUnitEnemy( u, GetOwningPlayer(d.sphere)) == false or GetUnitState(u, UNIT_STATE_LIFE) <= 0 or IsUnitType(u, UNIT_TYPE_SUMMONED) == true or IsUnitType(u, UNIT_TYPE_MECHANICAL) == true or IsUnitType(u, UNIT_TYPE_STRUCTURE) == true then
                call GroupRemoveUnit(g, u)
            else
                set dummy = CreateUnit( GetOwningPlayer(d.sphere), 'h001', 0, 0, 270 )
                set soul = CreateUnitAtLoc( Player(PLAYER_NEUTRAL_PASSIVE), GetUnitTypeId(u), loc, GetUnitFacing(u))
                call SetUnitPathing(soul , false)
                call SetUnitPosition( soul , GetUnitX(u), GetUnitY(u) )
                call UnitAddAbility( soul , 'Aloc' )
                call SetUnitVertexColor( soul , 255, 255, 255, 100 )
                call .setup( u, soul, d.sphere, thistype.create())
                call UnitApplyTimedLife( dummy, 'BTLF', 0.1)
                call UnitAddAbility( dummy, SPHERE_EFFECT_ID )
                call IssueTargetOrder( dummy, "soulburn", u )
                call GroupAddUnit(d.soulgroup, soul)
                call GroupRemoveUnit(g, u)
                
                set dummy = null
            endif
            
        endloop
        call TimerStart( d.ti, 4, false , function Sphere.onExpired )
        call RemoveLocation(loc)
        call DestroyGroup(g)
        set loc = null
        set u = null
        set soul = null
    endmethod
    
    private static method setup takes unit t, unit u, unit s, thistype this returns nothing
        local real ux = GetUnitX(u)
        local real uy = GetUnitY(u)
        local real sx = GetUnitX(s)
        local real sy = GetUnitY(s)
        
        set .target = t
        call SaveInteger( Data_Storage, 0, GetHandleId(u), this)
        call .SetPullUnit(u)
        call .start( ux, uy, sx, sy )
    endmethod
        
    method onPullStart takes nothing returns nothing
        set         .pullSpeed          = 350
        set         .isPulled           = true
    endmethod
    
    private static method Filt takes nothing returns boolean
        return (GetSpellAbilityId() == SPHERE_SPELL_ID)
    endmethod
    
    private static method LearnFilt takes nothing returns boolean
        return (GetLearnedSkill() == SPHERE_SPELL_ID and GetLearnedSkillLevel() == 1)
    endmethod
    
    private static method onSpell takes nothing returns nothing
        local unit u = GetTriggerUnit()
        local location loc = GetSpellTargetLoc()
        local thistype d = create()
        
        set d.caster = u
        set d.ti = NewTimer()
        set d.soulgroup = CreateGroup()
        set d.sphere = CreateUnitAtLoc( GetOwningPlayer(u), SPHERE_UNIT_ID, loc, 270)
        call SetUnitScale( d.sphere, SPHERE_SIZE, 0, 0 )
        call SetUnitTimeScale( d.sphere, 0.5 )
        call UnitAddAbility( d.sphere, 'Amrf' )
        call UnitAddAbility( d.sphere, SPHERE_EFFECT_ID )
        call SetUnitFlyHeight( d.sphere, 100 , 0)
        call SetTimerData(d.ti, d)
        call TimerStart( d.ti, 1.7, false, function Sphere.onDelay )
        set Data_Max = Data_Max + 1
        set Data_Stack[Data_Max] = d
    endmethod
    
    private static method onLearn takes nothing returns nothing
        call UnitAddAbility( GetTriggerUnit(), SPHERE_SUB_ID )
    endmethod
    private static method onInit takes nothing returns nothing
        local trigger t = CreateTrigger()
        local trigger m = CreateTrigger()
        local trigger z = CreateTrigger()
        local integer i
        
        call TriggerAddAction(t, function thistype.onSpell )
        call TriggerAddAction(m, function thistype.onBurn )
        call TriggerAddAction(z, function thistype.onLearn )
        call TriggerAddCondition( t, function thistype.Filt )
        call TriggerAddCondition( m, function thistype.BurnFilt )
        call TriggerAddCondition( z, function thistype.LearnFilt )
        set i = 0
        loop
            call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
            call TriggerRegisterPlayerUnitEvent(m, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
            call TriggerRegisterPlayerUnitEvent(z, Player(i), EVENT_PLAYER_HERO_SKILL, null)
            set i = i + 1
        exitwhen i == bj_MAX_PLAYER_SLOTS
    endloop
        
    endmethod
    endstruct
endscope
Top