• 🏆 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!
  • 🏆 Hive's 6th HD Modeling Contest: Mechanical is now open! Design and model a mechanical creature, mechanized animal, a futuristic robotic being, or anything else your imagination can tinker with! 📅 Submissions close on June 30, 2024. Don't miss this opportunity to let your creativity shine! Enter now and show us your mechanical masterpiece! 🔗 Click here to enter!

[JASS] Struct remove in this Spell bugged?

Status
Not open for further replies.
Level 8
Joined
Feb 15, 2009
Messages
463
Whenever the spell comes out of the loop before the destroy loop there´s a big delay and then Debugmessages from xedamage appear that i tried to remove null structs, also it seems that my timer cant work faster then 0.01 is there a way to decrease this time ?

Here is the code

JASS:
//******************************************************************************************
//*                                       Hawk Strike 
//*                               by Saia_Djinn (The Holy Order )
//*
//*                     A Spell which is cast on melee Range , afterwards a spiral runs
//*         from a defined distance towards the Position of the Caster , having various effects
//*                                       to units on the Spiral 
//*
//*
//******************************************************************************************

scope HawkStrike initializer Init

//Here are the different Configuration Options
globals
    private constant integer SPELL_ID = 'A000' //The ID of your Base Spell
    
    
    
    private constant real BASE_DAMAGE = 100. // Damage done to units on the spiral  x level
    private constant real EFFECT_AOE = 50. //How far from the current effect units will get damage or be spellargets
    private constant real START_ANGLE = 90. // Currently Facing North when creating 1st effect
    private constant real EFFECT_SCALE = 1. //Scale of the Effect(care 2. is in fact 8x as great as normal )
    private constant integer MAX_TOTAL = 60 // How many Effects can be created overall
    private constant real INITIAL_SPIRAL_RANGE = 1.0 // If u change this ,the movespeed of the unit
                                                                            //will not be used anymore instead this value(should atleast be 300.)
    private constant string DAMAGE_EFFECT = "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl" //Path of the Effect which shows up when units are damaged
    private constant string EFFECT_PATH = "Abilities\\Spells\\NightElf\\BattleRoar\\RoarTarget.mdl" //The Path of the Specialeffect Model used by the Spell 


endglobals

globals
    private xedamage damage 
    private unit TempUnit
endglobals 

private function GroupMatch takes nothing returns boolean 
    return IsUnitEnemy(GetFilterUnit() , GetOwningPlayer(TempUnit) ) == true and GetWidgetLife(GetFilterUnit()) > 0.405 and IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE) == false
endfunction

private function DamageConfig takes nothing returns nothing
    call damage.useSpecialEffect(DAMAGE_EFFECT,"origin")
    set damage.dtype = DAMAGE_TYPE_MAGIC

endfunction 
//BASE_DAMAGE * GetUnitAbilityLevel( caster , SPELL_ID)
private function Callback takes unit caster,unit target returns nothing
    call damage.damageTarget(caster , target , 2.  )
endfunction


private function Conditions takes nothing returns boolean
    return GetSpellAbilityId() == SPELL_ID
endfunction

private function Actions takes nothing returns nothing 
    local unit u = GetTriggerUnit()
    
    local real uX = GetUnitX(u)
    local real uY = GetUnitY(u)
    
    local real angle
    local real distance
    local real multi
    local real add 
    
    local real  SpiralX
    local real  SpiralY
    
    local xefx array Spiral 
    
    local integer N = -1
    
    local timer t = CreateTimer()
    
    local group g = CreateGroup()
    local unit d
    local boolexpr b = Condition( function GroupMatch )
    
    
    
    //Declaring the distance variable
//***  
    if ( INITIAL_SPIRAL_RANGE == 1.0 ) then
        set distance = GetUnitMoveSpeed(u)
    else
        set distance = INITIAL_SPIRAL_RANGE
    endif
//***

    set SpiralX = uX + distance * Cos( START_ANGLE * bj_DEGTORAD )
    set SpiralY = uY + distance * Sin( START_ANGLE * bj_DEGTORAD )

    set angle = START_ANGLE 
    set multi = distance / MAX_TOTAL
    set add = 20
    
    
//***
    loop
        set N = N + 1
        
        set SpiralX = uX + distance * Cos(angle)
        set SpiralY = uY + distance * Sin(angle)
        set angle = ( START_ANGLE + add* N ) *bj_DEGTORAD
        set distance = distance - multi
        
        exitwhen N == MAX_TOTAL
        
        set Spiral [N]= xefx.create( SpiralX, SpiralY, angle )
        set Spiral[N].fxpath = EFFECT_PATH
        set Spiral[N].scale = EFFECT_SCALE
        
        
        set TempUnit = u
        call GroupEnumUnitsInRange( g , SpiralX , SpiralY, EFFECT_AOE , b )
            loop
                set d = FirstOfGroup(g)
                exitwhen d == null
                    call Callback( u ,d )
                    call GroupRemoveUnit(g, d)
            endloop
            
        call TimerStart(t,0.01,false,null)
        loop
            exitwhen TimerGetRemaining(t) == 0.
            call TriggerSleepAction(0.0)
        endloop
        
    endloop
    
    set N = -1
    
    loop 
        exitwhen N == MAX_TOTAL
        call Spiral[N].destroy()
    endloop
    
    call DestroyGroup(g)
    call DestroyBoolExpr(b)
    call DestroyTimer(t)
    set t = null
    set g = null
    set b = null
    set u = null
endfunction

private function Init takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition(t, Condition( function Conditions ) )
    call TriggerAddAction( t, function Actions )
    set t = null
    
    set damage = xedamage.create()
endfunction
endscope
 
Level 8
Joined
Feb 15, 2009
Messages
463
Edit:
New Problem:
what do u suggest to go faster trough the loop?
the problem is if i dont use TSA the loop only goes trough once and then the spell bugs
if i use TSA its too slow so what to do ?

Old Post:(See new prob above )
Eyyy im so silly thanks for destroy but plz guys look the tSA Problem anyway + Rep
 
Level 14
Joined
Nov 18, 2007
Messages
816
Meh, i just updated a spell of mine, where you only have to modify some globals, the effect paths for example.

Feel free to use it.

JASS:
//Credits:
//    - Blaxor for the inspiration
//    - cohadar for his PUI library
//    - Rising_Dusk for his GroupUtils library
//    - Vexorian for JassHelper and TimerUtils
//    - PipeDream for Grimoire and all his help with spirals
//    - PitzerMike for JassNewGenPack
//    - SFilip for TESH

// How to import:
//    - Copy the code into a trigger on your map, adjust the constants below (especially AID) and youre done.
//    - Note that you have to copy over the required libraries as well

library FireSpiral uses TimerUtils, GroupUtils, PUI, xefx
    
    globals
        private constant    integer                 AID                     = 'A000' // rawcode of the triggering abiltiy (press Ctrl+D to display the rawcode of objects, in the object editor)
        private constant    real                    FX_INTERVAL             = 0.15 // effects are spawned in this interval
        private constant    string                  FIRE_FX                 = "Abilities\\Spells\\Human\\FlameStrike\\FlameStrikeEmbers.mdl" // this is the effect the spiral consits of
        private constant    real                    FIRE_FX_RADIUS          = 24. // collision size of the beforementioned effect
        private constant    real                    FIRE_FX_SCALE           = 1. // scale of beforementioned effect
        private             real            array   FIRE_DMG                // Units receive this much damage per second
        private constant    real                    FIRE_DMG_RADIUS         = 64 // this is the radius in which units around the effects get receive damage
        private constant    real                    FIRE_DMG_TICK           = 1./32 // this is the granulation of damage
        private constant    string                  FIRE_DMG_FX             = "Environment\\LargeBuildingFire\\LargeBuildingFire2.mdl" // this is the effect spawned on units receiving damage by the spiral
        private constant    string                  FIRE_DMG_FX_ATTPT       = "head" // this is the attachmentpoint where the beforementioned effect gets attached to
        private constant    real                    FIRE_DMG_FX_STAY        = 2. // the beforementioned effect stays on units this long after they receive no more damage
        private constant    attacktype              FIRE_DMG_ATTACKTYPE     = ATTACK_TYPE_MAGIC // attacktype of the damage units receive
        private constant    damagetype              FIRE_DMG_DAMAGETYPE     = DAMAGE_TYPE_MAGIC // damagetype of the damage units receive
        private             real            array   SPIRAL_INITIAL_RADIUS   // initial radius of the spiral
        private             real            array   SPIRAL_END_RADIUS       // radius of the spiral
        private             real            array   SPIRAL_CIRCLES          // how often does a spiral reach ((angle) modulo (2*PI))==0
        private             integer         array   SPIRAL_ENDINGS          // number of spirals spawned
        private             real            array   DURATION                // Duration of the spiral after all effects have been spawned
        
        private constant    integer                 MAX_FIRE_FX_PER_INSTANCE = 255
    endglobals
    
    private function SetUpFIRE_DMG takes nothing returns nothing
        set FIRE_DMG[1]=50.
        set FIRE_DMG[2]=75.
        set FIRE_DMG[3]=100.
    endfunction
    
    private function SetUpSPIRAL_INITIAL_RADIUS takes nothing returns nothing
        set SPIRAL_INITIAL_RADIUS[1]=200
        set SPIRAL_INITIAL_RADIUS[2]=200
        set SPIRAL_INITIAL_RADIUS[3]=200
    endfunction
    
    private function SetUpSPIRAL_END_RADIUS takes nothing returns nothing
        set SPIRAL_END_RADIUS[1]=400.
        set SPIRAL_END_RADIUS[2]=500.
        set SPIRAL_END_RADIUS[3]=600.
    endfunction
    
    private function SetUpSPIRAL_CIRCLES takes nothing returns nothing
        set SPIRAL_CIRCLES[1]=0.6
        set SPIRAL_CIRCLES[2]=0.8
        set SPIRAL_CIRCLES[3]=1.0
    endfunction
    
    private function SetUpSPIRAL_ENDINGS takes nothing returns nothing
        set SPIRAL_ENDINGS[1]=3
        set SPIRAL_ENDINGS[2]=3
        set SPIRAL_ENDINGS[3]=3
    endfunction
    
    private function SetUpDURATION takes nothing returns nothing
        set DURATION[1]=5.
        set DURATION[2]=7.
        set DURATION[3]=9.
    endfunction
    
    // proxy functions
    // if you want to use formulae, edit these
    
    private function Fire_Dmg takes integer level returns real
        return FIRE_DMG[level]
    endfunction
    
    private function Spiral_Initial_Radius takes integer level returns real
        return SPIRAL_INITIAL_RADIUS[level]
    endfunction
    
    private function Spiral_End_Radius takes integer level returns real
        return SPIRAL_END_RADIUS[level]
    endfunction
    
    private function Spiral_Circles takes integer level returns real
        return SPIRAL_CIRCLES[level]
    endfunction
    
    private function Spiral_Endings takes integer level returns integer
        return SPIRAL_ENDINGS[level]
    endfunction
    
    private function Duration takes integer level returns real
        return DURATION[level]
    endfunction
    
    // I wouldnt edit anything below this line, if i were you
    
    private struct Data
        unit c
        integer level
        integer i
        timer t
        real x
        real y
        real a
        real b
        real f
        real d
        integer fxcount
        xefx array FX[MAX_FIRE_FX_PER_INSTANCE]
        real array FXX[MAX_FIRE_FX_PER_INSTANCE]
        real array FXY[MAX_FIRE_FX_PER_INSTANCE]
        
        static Data array Structs
        static integer Count=0
        static timer T=CreateTimer()
        static Data tmps
        static boolexpr FireDmg
        
        static timer array ImmoT
        static effect array ImmoFX
        
        static method ImmoCallback takes nothing returns nothing
        local timer t=GetExpiredTimer()
        local integer i=GetTimerData(t)
            call DestroyEffect(Data.ImmoFX[i])
            set Data.ImmoFX[i]=null
            call ReleaseTimer(t)
        endmethod
        
        static method FireDmgFunc takes nothing returns boolean
        local unit u=GetFilterUnit()
        local integer i
        local timer t
            if IsUnitEnemy(u, GetOwningPlayer(Data.tmps.c)) and (not IsUnitInGroup(u, ENUM_GROUP)) and IsUnitType(u, UNIT_TYPE_DEAD)==false and IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE)==false and IsUnitType(u, UNIT_TYPE_STRUCTURE)==false then
                call UnitDamageTarget(Data.tmps.c, u, Fire_Dmg(Data.tmps.level)*FIRE_DMG_TICK, false, false, FIRE_DMG_ATTACKTYPE, FIRE_DMG_DAMAGETYPE, WEAPON_TYPE_WHOKNOWS)
                set i=GetUnitIndex(u)
                if Data.ImmoFX[i]==null then
                    set Data.ImmoFX[i]=AddSpecialEffectTarget(FIRE_DMG_FX, u, FIRE_DMG_FX_ATTPT)
                    set t=NewTimer()
                    call SetTimerData(t, i)
                    call TimerStart(t, FIRE_DMG_FX_STAY, false, function Data.ImmoCallback)
                    set Data.ImmoT[i]=t
                else
                    call TimerStart(Data.ImmoT[i], FIRE_DMG_FX_STAY, false, function Data.ImmoCallback)
                endif
                set u=null
                return true
            endif
            set u=null
            return false
        endmethod
        
        method onDestroy takes nothing returns nothing
            set .c=null
            call ReleaseTimer(.t)
            set Data.Count=Data.Count-1
            set Data.Structs[.i]=Data.Structs[Data.Count]
            set Data.Structs[.i].i=.i
            if Data.Count==0 then
                call PauseTimer(Data.T)
            endif
        endmethod
        
        static method EndingCB takes nothing returns nothing
        local Data s=GetTimerData(GetExpiredTimer())
        local integer i=0
            loop
                exitwhen i>=Spiral_Endings(s.level)
                set s.fxcount=s.fxcount-1
                call s.FX[s.fxcount].destroy()
                set i=i+1
            endloop
            if s.fxcount<=0 then
                call s.destroy()
            endif
        endmethod
        
        static method Ending takes nothing returns nothing
            call TimerStart(GetExpiredTimer(), FX_INTERVAL, true, function Data.EndingCB)
        endmethod
        
        static method SpawnCB takes nothing returns nothing
        local Data s=GetTimerData(GetExpiredTimer())
        local integer i=0
        local real d=2*bj_PI/Spiral_Endings(s.level)
        local real f=s.a+(bj_PI/2)
            loop
                exitwhen i>=Spiral_Endings(s.level)
                debug if s.fxcount>=MAX_FIRE_FX_PER_INSTANCE then
                debug     call BJDebugMsg("FireSpiral: Array overflow! Try increasing MAX_FIRE_FX_PER_INSTANCE!")
                debug     exitwhen true
                debug endif
                set s.FXX[s.fxcount]=s.x+(s.d*Cos(s.f+s.a+(i*d)))
                set s.FXY[s.fxcount]=s.y+(s.d*Sin(s.f+s.a+(i*d)))
                set s.FX[s.fxcount]=xefx.create(s.FXX[s.fxcount], s.FXY[s.fxcount], f)
                set s.FX[s.fxcount].fxpath=FIRE_FX
                set s.FX[s.fxcount].scale=FIRE_FX_SCALE
                set s.fxcount=s.fxcount+1
                set i=i+1
            endloop
            set s.a=2*Asin((2*FIRE_FX_RADIUS)/(2*s.d))+s.a
            set s.d=s.b*s.a
            if s.d>Spiral_End_Radius(s.level) then
                call TimerStart(s.t, Duration(s.level), false, function Data.Ending)
            endif
        endmethod
        
        static method Callback takes nothing returns nothing
        local Data s
        local integer i=0
        local integer j=0
            loop
                exitwhen i>=Data.Count
                set s=Data.Structs[i]
                loop
                    exitwhen j>=s.fxcount
                    set Data.tmps=s
                    call GroupEnumUnitsInRange(ENUM_GROUP, s.FXX[j], s.FXY[j], FIRE_DMG_RADIUS, Data.FireDmg)
                    set j=j+1
                endloop
                call GroupClear(ENUM_GROUP)
                set i=i+1
            endloop
        endmethod
        
        static method Cond takes nothing returns boolean
            return GetSpellAbilityId()==AID
        endmethod
        
        static method Create takes nothing returns nothing
        local Data s=Data.allocate()
        local real d
        local integer i=0
        local real f
            set s.c=GetTriggerUnit()
            set s.level=GetUnitAbilityLevel(s.c, AID)
            set s.t=NewTimer()
            set s.f=GetUnitFacing(s.c)*bj_DEGTORAD
            set s.x=GetUnitX(s.c)
            set s.y=GetUnitY(s.c)
            set s.b=(Spiral_End_Radius(s.level)-Spiral_Initial_Radius(s.level))/(2*bj_PI*Spiral_Circles(s.level))
            set s.d=Spiral_Initial_Radius(s.level)
            set s.a=s.d/s.b
            set d=2*bj_PI/Spiral_Endings(s.level)
            set f=s.a+(bj_PI/2)
            loop
                exitwhen i>=Spiral_Endings(s.level)
                set s.FXX[s.fxcount]=s.x+(s.d*Cos(s.f+s.a+(i*d)))
                set s.FXY[s.fxcount]=s.y+(s.d*Sin(s.f+s.a+(i*d)))
                set s.FX[s.fxcount]=xefx.create(s.FXX[s.fxcount], s.FXY[s.fxcount], f)
                set s.FX[s.fxcount].fxpath=FIRE_FX
                set s.FX[s.fxcount].scale=FIRE_FX_SCALE
                set s.fxcount=s.fxcount+1
                set i=i+1
            endloop
            if s.d==0 then
                set s.a=2*FIRE_FX_RADIUS/s.b
            else
                set s.a=2*Asin((2*FIRE_FX_RADIUS)/(2*s.d))+s.a
            endif
            set s.d=s.b*s.a
            call SetTimerData(s.t, s)
            call TimerStart(s.t, FX_INTERVAL, true, function Data.SpawnCB)
            set Data.Structs[Data.Count]=s
            set s.i=Data.Count
            if Data.Count==0 then
                call TimerStart(Data.T, FIRE_DMG_TICK, true, function Data.Callback)
            endif
            set Data.Count=Data.Count+1
        endmethod
        
        static method onInit takes nothing returns nothing
        local trigger t=CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
            call TriggerAddAction(t, function Data.Create)
            call TriggerAddCondition(t, Condition(function Data.Cond))
            
            set Data.FireDmg=Condition(function Data.FireDmgFunc)
            
            call SetUpFIRE_DMG()
            call SetUpSPIRAL_INITIAL_RADIUS()
            call SetUpSPIRAL_END_RADIUS()
            call SetUpSPIRAL_CIRCLES()
            call SetUpSPIRAL_ENDINGS()
            call SetUpDURATION()
        endmethod
    endstruct
    
endlibrary
 

Attachments

  • FireSpiral_1.1.0.w3x
    47.6 KB · Views: 36
Status
Not open for further replies.
Top