HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Error in NovaSpell (structproblem)

01-11-2009, 09:24 AM#1
akolyt0r
Hey i got a strange problem in a Novaspell i made, i get an "unable to allocate id for struct"-error when i use following nova struct:

Collapse JASS:
private struct Nova
    unit caster
    unit array targets[UNIT_MAX]
    group g
    integer sizeofg
    real timerdata
    static method create takes unit u returns Nova
        local Nova n=.allocate()
        local integer i=0
        set n.caster=u
        set n.g=CreateGroup()
        set n.sizeofg=0
        set n.timerdata=0
        loop
        exitwhen i>UNIT_MAX
            set n.targets[i]=null
            set i=i+1
        endloop
        return n
    endmethod
    private method onDestroy takes nothing returns nothing
        local integer i=0
        call DestroyGroup(.g)
        loop
            exitwhen i>.sizeofg
            set .targets[i]=null
            set i=i+1
        endloop
        set .caster=null
        set .g=null
    endmethod
endstruct

Full Spell:
Expand JASS:

The strange thing about is, the spell itself works as it should but i always get thos struct errors ..."error to allocate" and "attempt to destry a null struct"
..

Another question regarding the spell, i use a global to get the struct data in the EnumUnitsInArray function (a ForGroup callback), ...should i use some attachment system to do that, or is that ok as is (which sure would be worse performance wise, but safer) ?

And before you say something...yeah i will move the unitfilter (which is currently in the TimerCallback) to the groupenum ..some day
01-11-2009, 09:49 AM#2
Vestras
It's Nova.allocate not .allocate.
01-11-2009, 10:02 AM#3
Blackroot
Quote:
Another question regarding the spell, i use a global to get the struct data in the EnumUnitsInArray function (a ForGroup callback), ...should i use some attachment system to do that, or is that ok as is (which sure would be worse performance wise, but safer) ?

I didin't look over the system, but generaly it isin't a poor practice to do. The exceptions are things you know are going to be being called very rapidly. In almost all cases it's acceptable, unless a wait or timer is involved. If there's one of thoes, attach the variables to the timer or some other method.

Reguarding the actual problem, Vestras is right. Static methods are outside the scope of the struct and it's variables. It's best to treat Static methods as functions, essentialy that's what they are.
01-11-2009, 11:11 AM#4
akolyt0r
Quote:
Originally Posted by Vestras
It's Nova.allocate not .allocate.

No, it doesnt matter, both "would" work, but doesnt 0.o

Quote:
Originally Posted by Blackroot
I didin't look over the system, but generaly it isin't a poor practice to do. The exceptions are things you know are going to be being called very rapidly. In almost all cases it's acceptable, unless a wait or timer is involved. If there's one of thoes, attach the variables to the timer or some other method.

Hmm, currently i have the problem, that units which are at cast time out of nova range, but step into nova range while missile is flying, and which are being hit by the missile arent effected by the Nova.
To Fix this i would have to EnumTheUnits each TIME_OUT=0.05 seconds, and then start a ForGroup Call for them.
Is it still arguable to use a global in a timer callback each 0.05 seconds to get the struct in the ForGroupCallback ?
Expand JASS:
01-11-2009, 01:06 PM#5
Zerzax
First off: What is your UNIT_MAX? Struct instance limits are severely hampered by the use of arrays. Instance limit becomes: 8100 / Highest array limit. Use a HandleTable if you are going to store units (or even a group if it refers to each instance). Otherwise, use a global group and damage the units inside your filter.

EDIT: If you have a lot of struct members to reference in the callback, use a temporary instance. If you have two or three struct members to reference, use individual globals.
01-11-2009, 01:33 PM#6
akolyt0r
yeah just noticed that it works when i reduce UNIT_MAX to a reasonable ammount like 200 :>
Pretty unlikely that there are 8190 units in a area with a radius of 575 ^^

EDIT: Totally rewrote it ..no arrays anymore..now i have GroupEnums every TIME_OUT, but since TIME_OUT=0.15 still looks good thats ok.
Collapse JASS:
scope Nova initializer Init
//// Nova Spell by Akolyt0r
/// Requirements: JassNewGen,TimerUtils
globals
private constant integer    spellid = 'A000'        //Nova (Hero) Ability Rawcode
private constant integer    dummyid = 'u000'        //Dummy Unit Rawcode
private constant integer    fxspellid = 'A001'      //Custom Ability Rawcode

private constant integer    fxspellradius = 575     //AoE Range of Custom Wave Ability (maybe add some more)
private constant integer    fxstartdistbonus = 100  //blah debug for fine adjustment
private constant integer    fxmissilespeed = 225    //Missile Speed of Custom Wave Ability
private constant real       TIME_OUT = 0.15         //
endglobals

private function theDamage takes integer level returns real
return I2R(level*50)
endfunction

private function NovaEffectFilter takes unit u, unit caster returns boolean
return (IsPlayerEnemy(GetOwningPlayer(u),GetOwningPlayer(caster))and(GetUnitTypeId(u)!=dummyid) )
endfunction

//// Do Not Edit Below //// 
//// Do Not Edit Below //// 
private struct Nova
    unit caster
    group g
    group alreadyHit
    real totalElapsed
    real cx
    real cy
    static method create takes unit u returns Nova
        local Nova n=Nova.allocate()
        set n.caster=u
        set n.cx=GetUnitX(u)
        set n.cy=GetUnitY(u)
        set n.g=CreateGroup()
        set n.alreadyHit=CreateGroup()
        set n.totalElapsed=0
        return n
    endmethod
    private method onDestroy takes nothing returns nothing
        call DestroyGroup(.g)
        call DestroyGroup(.alreadyHit)
        set .caster=null
        set .g=null
    endmethod
endstruct

globals
private Nova TMP
endglobals

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

private function NovaEffectCallback takes nothing returns nothing
local Nova n=TMP
local unit u=GetEnumUnit()
local real dist = 0
    set dist = GetUnitToLocXYDistance(u,n.cx,n.cy)
    if(NovaEffectFilter(u,n.caster)and dist<fxspellradius and dist<fxstartdistbonus+n.totalElapsed*fxmissilespeed)and(IsUnitInGroup(u,n.alreadyHit)==false)then
        call GroupAddUnit(n.alreadyHit,u)
        call UnitDamageTarget(n.caster,u,theDamage(GetUnitAbilityLevel(n.caster,spellid)),true,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_FIRE,WEAPON_TYPE_WHOKNOWS)
    endif        
set u=null
endfunction

private function NovaTimerCallback takes nothing returns nothing
local Nova n=GetTimerData(GetExpiredTimer())
    set n.totalElapsed=n.totalElapsed+TIME_OUT
    call GroupEnumUnitsInRange(n.g,n.cx,n.cy,fxspellradius,Condition(function True))
    set TMP=n //
    call ForGroup(n.g,function NovaEffectCallback)
    call GroupClear(n.g)
endfunction

private function Actions takes nothing returns nothing
local Nova n=Nova.create(GetTriggerUnit())
local player p=GetOwningPlayer(n.caster)
local integer i=0
local unit dummy
local timer t=NewTimer()
    loop
        exitwhen i>360
        set dummy=CreateUnit(p,dummyid,n.cx,n.cy,0)
        call UnitApplyTimedLife(dummy,'BTLF',0.3)
        call IssuePointOrder(dummy,"breathoffire",n.cx+100*Cos(i*bj_DEGTORAD),n.cy+100*Sin(i*bj_DEGTORAD))
        set i=i+30
    endloop
    //
    call SetTimerData(t, n)
    call TimerStart(t,TIME_OUT,true,function NovaTimerCallback)
    //
    call PolledWait2(fxspellradius/fxmissilespeed+2*TIME_OUT)
//cleanup
call ReleaseTimer(t)
call n.destroy()
set t=null
set dummy=null
set p=null
endfunction

//===========================================================================
private function Init takes nothing returns nothing
    local trigger t=CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddAction(t,function Actions )
    call TriggerAddCondition( t,Condition(function Conditions))
endfunction
endscope