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

vJass - Struct Handle problem

Status
Not open for further replies.
Level 18
Joined
Oct 18, 2007
Messages
930
Ok im working on my new spell now and i implemented some H2I codes for checking if the unit has the "orbs" around it or not.

If cast twice it works flawless by replacing the old ones.

But if i let the time run out and let them be destroyed in the MotionLoop the game fucks up and i get the "Dubble Free!" message spammed on my face... Any ideas`??
And YES i know what Dubble Free! is


Code:
JASS:
scope ElementalShield initializer Init

    globals
        // General Globals
        private constant integer AID = 'A000'
        private constant integer DID = 'n000'
        
        private constant integer FID = 'Amrf'
        
        private constant string CastCasterEffect = "Abilities\\Spells\\Items\\AIda\\AIdaCaster.mdl"
        private constant string CastCasterEffectAttach = "origin"
        
        private constant real Interval = 0.030
        
        private constant integer OrbAmount = 5 // Verry important for the spells core!

        // Sphere/Ball/Missile/Orb(Or whatever you would call it) Globals, keyword is Orb
        private constant real Orb_AreaOfEffect = 50.
        private constant real Orb_AreaOfEffectInc = 10.
        
        private constant real Orb_Speed = 10.
        
        private constant real Orb_Height = 55.

        private constant real Orb_Offset = 100.
        private constant real Orb_OffsetInc = 22.

        private constant integer Orb_AmountOfOrbs = 3
        private constant integer Orb_AOOInc = 1
        
        private constant real Orb_Damage = 55.
        private constant real Orb_DamageInc = 15.
        
        private constant real Orb_Duration = 20.
        private constant real Orb_DurationInc = 10.
        
        private constant real Orb_EnemyGroupReset = 1.5
        
        private constant integer Orb_Charges = 8
        private constant integer Orb_ChargesInc = 2
        
        private constant string Orb_DamageEffectAttach = "chest"
        
        private constant integer Orb_AngleOfAttack = 90
        
        // Knockback globals, keyword is Knock. ( Read the Knockback manual in the Knockback trigger for more info )
        private constant real Knock_Distance = 250.
        private constant real Knock_DistanceInc = 50.

        private constant real Knock_Time = 0.7
        private constant real Knock_TimeInc = 0.2
        
        private constant real Knock_TreeRadius = 100.
        
        private constant boolean Knock_Pause = false
        
        private constant integer Knock_EffectSpawn = 4
        
        private constant integer Knock_EffectType = 1
        
        private constant string Knock_EffectAttach = "origin"

        // Array for setup of different elements, you dont need to change this
        private attacktype array Element_Attacktype
        private damagetype array Element_Damagetype
        private weapontype array Element_Weapontype
        
        private real array Element_Scale
        private real array Element_ScaleInc
        
        private string array Element_Look
        private string array Element_DamageEx
        private string array Element_KnockEx
        
        // Misc globals, you should not change theese
        private player tmpP = null
        private unit tmpU = null
        private group tmpG = CreateGroup()
        private group tmpG2 = null
        private integer tmpI = 0
        private boolexpr EnemyFilter = null
    endglobals
    
    private function SetupElements takes nothing returns nothing
        // Electric
        set Element_Attacktype[1] = ATTACK_TYPE_MAGIC
        set Element_Damagetype[1] = DAMAGE_TYPE_LIGHTNING
        set Element_Weapontype[1] = null
        
        set Element_Scale[1] = 1.2
        set Element_ScaleInc[1] = 0.1
        
        set Element_Look[1] = "Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl"
        set Element_DamageEx[1] = "Abilities\\Weapons\\Bolt\\BoltImpact.mdl"
        set Element_KnockEx[1] = "Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl"

        // Ice
        set Element_Attacktype[2] = ATTACK_TYPE_MAGIC
        set Element_Damagetype[2] = DAMAGE_TYPE_COLD
        set Element_Weapontype[2] = null
        
        set Element_Scale[2] = 0.08
        set Element_ScaleInc[2] = 0.04
        
        set Element_Look[2] = "Abilities\\Weapons\\FrostWyrmMissile\\FrostWyrmMissile.mdl"
        set Element_DamageEx[2] = "Abilities\\Weapons\\FrostWyrmMissile\\FrostWyrmMissile.mdl"
        set Element_KnockEx[2] = "Abilities\\Weapons\\ZigguratFrostMissile\\ZigguratFrostMissile.mdl"

        // Fire
        set Element_Attacktype[3] = ATTACK_TYPE_MAGIC
        set Element_Damagetype[3] = DAMAGE_TYPE_FIRE
        set Element_Weapontype[3] = null
        
        set Element_Scale[3] = 0.8
        set Element_ScaleInc[3] = 0.03
        
        set Element_Look[3] = "Abilities\\Weapons\\RedDragonBreath\\RedDragonMissile.mdl"
        set Element_DamageEx[3] = "Abilities\\Weapons\\RedDragonBreath\\RedDragonMissile.mdl"
        set Element_KnockEx[3] = "Abilities\\Weapons\\LavaSpawnMissile\\LavaSpawnBirthMissile.mdl"

        // Earth
        set Element_Attacktype[4] = ATTACK_TYPE_SIEGE
        set Element_Damagetype[4] = DAMAGE_TYPE_FORCE
        set Element_Weapontype[4] = null
        
        set Element_Scale[4] = 0.8
        set Element_ScaleInc[4] = 0.04
        
        set Element_Look[4] = "Abilities\\Weapons\\AncientProtectorMissile\\AncientProtectorMissile.mdl"
        set Element_DamageEx[4] = "Abilities\\Weapons\\AncientProtectorMissile\\AncientProtectorMissile.mdl"
        set Element_KnockEx[4] = "Objects\\Spawnmodels\\Undead\\ImpaleTargetDust\\ImpaleTargetDust.mdl"

        // Chaos
        set Element_Attacktype[5] = ATTACK_TYPE_CHAOS
        set Element_Damagetype[5] = DAMAGE_TYPE_DEATH
        set Element_Weapontype[5] = null
        
        set Element_Scale[5] = 0.8
        set Element_ScaleInc[5] = 0.04

        set Element_Look[5] = "Abilities\\Weapons\\DemonHunterMissile\\DemonHunterMissile.mdl"
        set Element_DamageEx[5] = "Abilities\\Weapons\\GreenDragonMissile\\GreenDragonMissile.mdl"
        set Element_KnockEx[5] = "Abilities\\Weapons\\IllidanMissile\\IllidanMissile.mdl"
        
        // If you want any more elements then just add them below as did in over here. Remmember to always have a higher int on the array!
    endfunction
    
    private constant function GetKnock_Distance takes integer lvl returns real
        return Knock_Distance + ( Knock_DistanceInc * ( lvl - 1 ) )
    endfunction
    
    private constant function GetKnock_Time takes integer lvl returns real
        return Knock_Time + ( Knock_TimeInc * ( lvl - 1 ) )
    endfunction
    
    private constant function GetOrb_Scale takes integer orb, integer lvl returns real
        return Element_Scale[orb] + ( Element_ScaleInc[orb] * ( lvl - 1 ) )
    endfunction
    
    private constant function GetOrb_AreaOfEffect takes integer lvl returns real
        return Orb_AreaOfEffect + ( Orb_AreaOfEffectInc * ( lvl - 1 ) )
    endfunction
    
    private constant function GetOrb_Offset takes integer lvl returns real
        return Orb_Offset + ( Orb_OffsetInc * ( lvl - 1 ) )
    endfunction
    
    private constant function GetOrb_AmountOfOrbs takes integer lvl returns integer
        return Orb_AmountOfOrbs + ( Orb_AOOInc * ( lvl - 1 ) )
    endfunction
    
    private constant function GetOrb_Damage takes integer lvl returns real
        return Orb_Damage + ( Orb_DamageInc * ( lvl - 1 ) )
    endfunction
    
    private constant function GetOrb_Duration takes integer lvl returns real
        return Orb_Duration + ( Orb_DurationInc * ( lvl - 1 ) )
    endfunction 
    
    private constant function GetOrb_Charges takes integer lvl returns integer
        return Orb_Charges + ( Orb_ChargesInc * ( lvl - 1 ) )
    endfunction
    
// End of setup
//==================================================================================
    
    private function H2I takes handle h returns integer
        return h
        return 0
    endfunction
    
    private keyword Orb
    
    globals
        private integer array Orbs [10000] [OrbAmount]
    endglobals
    
    private function Check takes integer x returns nothing
        local Orb dat
        local integer i = 1
        loop
            exitwhen i > OrbAmount
            set dat = Orbs[x][i]

            if dat.Orb != null then
                call dat.destroy()
            endif
            
            set i = i + 1
        endloop
    endfunction
    
    private function GroupFilter takes nothing returns boolean
        return IsUnitEnemy(GetFilterUnit(), tmpP) and GetWidgetLife(GetFilterUnit()) > .405 and IsUnitType(GetFilterUnit(), UNIT_TYPE_GROUND) and not IsUnitInGroup(GetFilterUnit(), tmpG2)
    endfunction
    
    private struct Orb
        unit u
        player p
        integer l
        
        unit Orb
        
        effect OrbLook
        
        integer OrbType
        
        group Check = CreateGroup()
        
        real Turn = 0
        
        real Offset
        
        real Duration = 0
        real EndDuration
        
        real Refresh = 0
        
        real Damage
        real KnockDistance
        real KnockTime
        real Aoe
        
        integer Charges
        
        static real nX = 0
        static real nY = 0
        
        static integer array Index
        static integer Total = 0
        static timer Tim = CreateTimer()
        
        static method Loop takes nothing returns nothing
            local Orb dat
            local integer i = 0
            
            loop
                exitwhen i >= dat.Total
                set dat = dat.Index[i]
                
                if dat.Duration < dat.EndDuration and GetWidgetLife(dat.u) > .405 then
                    set dat.Turn = dat.Turn + ( Orb_Speed * bj_DEGTORAD )
                    set dat.nX = GetUnitX(dat.u) + dat.Offset * Cos(dat.Turn)
                    set dat.nY = GetUnitY(dat.u) + dat.Offset * Sin(dat.Turn)
                    
                    call SetUnitFacing(dat.Orb, Atan2(dat.nY - GetUnitY(dat.Orb), dat.nX - GetUnitX(dat.Orb)) * bj_RADTODEG)
                    call SetUnitX(dat.Orb, dat.nX)
                    call SetUnitY(dat.Orb, dat.nY)
                    
                    set tmpP = dat.p
                    set tmpG2 = dat.Check
                    call GroupEnumUnitsInRange(tmpG, dat.nX, dat.nY, dat.Aoe, EnemyFilter)
                    
                    loop
                        set tmpU = FirstOfGroup(tmpG)
                        exitwhen tmpU == null

                        if Element_DamageEx[dat.OrbType] != "" then
                            call DestroyEffect(AddSpecialEffectTarget(Element_DamageEx[dat.OrbType], tmpU, Orb_DamageEffectAttach))
                        endif

                        call UnitDamageTarget(dat.u, tmpU, dat.Damage, false, false, Element_Attacktype[dat.OrbType], Element_Damagetype[dat.OrbType], Element_Weapontype[dat.OrbType])
                        call KnockbackEx(tmpU, dat.KnockDistance, Atan2(GetUnitY(tmpU) - dat.nY, GetUnitX(tmpU) - dat.nX), dat.KnockTime, Knock_TreeRadius, Knock_Pause, Knock_EffectSpawn, Knock_EffectType, Element_KnockEx[dat.OrbType], Knock_EffectAttach)
                        
                        call GroupAddUnit(dat.Check, tmpU)
                        call GroupRemoveUnit(tmpG, tmpU)
                        
                        set tmpI = 1
                    endloop
                    
                    if dat.Refresh > Orb_EnemyGroupReset then
                        call GroupClear(dat.Check)
                        set dat.Refresh = 0
                    else
                        set dat.Refresh = dat.Refresh + Interval
                    endif

                    set dat.Duration = dat.Duration + Interval

                    if tmpI > 0 then
                        if dat.Charges > 0 then
                            set dat.Charges = dat.Charges - 1
                        else
                            call dat.destroy()
                            
                            set i = i - 1
                        endif
                        set tmpI = 0
                    endif
                else
                    call dat.destroy()
                    
                    set i = i - 1
                endif
                
                set i = i + 1
            endloop
            
            if dat.Total == 0 then
                call PauseTimer(dat.Tim)
            endif
        endmethod
        
        static method Start takes unit u, player p, integer l, integer t, real a returns Orb
            local Orb dat = Orb.allocate()
            local real s = GetOrb_Scale(t, l)
            
            set dat.u = u
            set dat.p = p
            set dat.l = l
            set dat.OrbType = t
            set dat.Turn = a
            set dat.Offset = GetOrb_Offset(l)
            set dat.EndDuration = GetOrb_Duration(l)
            set dat.Damage = GetOrb_Damage(l)
            set dat.KnockDistance = GetKnock_Distance(l)
            set dat.KnockTime = GetKnock_Time(l)
            set dat.Aoe = GetOrb_AreaOfEffect(l)
            set dat.Charges = GetOrb_Charges(l)
            
            set dat.Orb = CreateUnit(p, DID, GetUnitX(u) + dat.Offset * Cos(a), GetUnitY(u) + dat.Offset * Sin(a), a * bj_RADTODEG)
            
            call UnitAddAbility(dat.Orb, FID)
            call UnitRemoveAbility(dat.Orb, FID)
            call SetUnitFlyHeight(dat.Orb, Orb_Height, 0)
            
            call SetUnitAnimationByIndex(dat.Orb, Orb_AngleOfAttack)
            call SetUnitScale(dat.Orb, s, s, s)
            
            if Element_Look[t] != "" then
                set dat.OrbLook = AddSpecialEffectTarget(Element_Look[t], dat.Orb, "origin")
            endif
            
            if dat.Total == 0 then
                call TimerStart(dat.Tim, Interval, true, function Orb.Loop)
            endif
            
            set dat.Index[dat.Total] = dat
            set dat.Total = dat.Total + 1
            
            return dat
        endmethod
        
        method onDestroy takes nothing returns nothing
            call DestroyGroup(this.Check)
            call DestroyEffect(this.OrbLook)
            call KillUnit(this.Orb)
                    
            set this.Check = null
            set this.OrbLook = null
            set this.Orb = null
            set this.u = null
            set this.p = null
                    
            set this.Total = this.Total - 1
            set this.Index[this] = this.Index[this.Total]
        endmethod
    endstruct

    private function Conditions takes nothing returns boolean
        return GetSpellAbilityId() == AID
    endfunction
    
    private function Actions takes nothing returns nothing
        local unit u = GetTriggerUnit()
        local player p = GetOwningPlayer(u)
        local integer l = GetUnitAbilityLevel(u, AID)
        local integer i = 1
        local integer e = GetOrb_AmountOfOrbs(l)
        local real a = 360/e
        local integer x = H2I(u) - 0x100000
        
        call Check(x)
        loop
            exitwhen i > e
            
            set Orbs[x][i] = Orb.Start(u, p, l, i, (a*i+GetUnitFacing(u)) * bj_DEGTORAD)
            
            set i = i + 1
        endloop
        
        if CastCasterEffect != "" then
            call DestroyEffect(AddSpecialEffectTarget(CastCasterEffect, u, CastCasterEffectAttach))
        endif
        
        set u = null
        set p = null
    endfunction
    
    private function Init takes nothing returns nothing
        local trigger trg = CreateTrigger()
        local integer i = 1
        
        call TriggerRegisterAnyUnitEventBJ(trg, EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddAction(trg, function Actions)
        call TriggerAddCondition(trg, Condition(function Conditions))
        
        set trg = null

        call SetupElements()
        
        // Preloading the effects
        loop // Array Preloading ;)
            exitwhen Element_Look[i] == "" or Element_Look[i] == null
            call Preload(Element_Look[i])
            set i = i + 1
        endloop
        loop // Array Preloading ;)
            exitwhen Element_DamageEx[i] == "" or Element_DamageEx[i] == null
            call Preload(Element_DamageEx[i])
            set i = i + 1
        endloop
        loop // Array Preloading ;)
            exitwhen Element_KnockEx[i] == "" or Element_KnockEx[i] == null
            call Preload(Element_KnockEx[i])
            set i = i + 1
        endloop
        
        call Preload(CastCasterEffect)
        call PreloadStart()
        // End of Preloading
        
        set EnemyFilter = Condition(function GroupFilter)
    endfunction

endscope

Map:
 

Attachments

  • Elemental Shield.w3x
    46.6 KB · Views: 70
Status
Not open for further replies.
Top