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

[jasshelper] private constant boolean "3D", not a valid identifier name

Status
Not open for further replies.
Level 6
Joined
Jun 18, 2011
Messages
147
Line 87: Not a valid identifier name: "3D"

  • private constant boolean 3D = true
Is my jassnewgenpack not up to date?

I am unable to save the map I attached, as well as the map I imported the spell to.

This spell uses TimerUtils, BountSentinel, Vector, and Heights
JASS:
scope BurningOrbit initializer init

//*************************************************************************************************************//
//                                                  Burning Orbit                                              //
//                                                        by                                                   //
//                                                      cedi                                                   //
//                                                                                                             //
//                                         needs: TimerUtils by Vexorian                                       //
//                                                Bound Sentinel by Vexorian                                   //
//                                                Dummy Model by                                               //
//                                                Vector lib by                                                //
//                                                Heights by cedi                                              //
//*************************************************************************************************************//

//For use, copy the trigger to your map, copy the dummy create a spell and adjust the values below.

globals
    //ID of the dummy spell
    private constant integer SPELL_ID            = 'A000'
    //ID of the spell which the splits should have. Beware, only unit target spells or passivs.
    private constant integer SPLIT_SPELL         = 'A001'
    //ID of the spell which they mmain orb should have. BEware, only passivs.
    private constant integer MAIN_SPELL          = '0000'
    //ID of the dummy
    private constant integer DUMMY_ID            = 'h000'
    //How many levels does your spell have?
    private constant integer SPELL_LEVEL_COUNT   = 4
    //How many splits do you want?
    private constant integer MAX_SPLITS          = 20
    //How many moves should the spreed out use?
    private constant integer MOVES               = 25
    //Red part of the color of the main orb ( 0 - 255 )
    private constant integer COLOR_RED           = 255
    //Green part of the color of the main orb ( 0 - 255 )
    private constant integer COLOR_GREEN         = 255
    //Blue part of the color of the main orb ( 0 - 255 )
    private constant integer COLOR_BLUE          = 255
    //Alpha part of the color of the main orb ( 0 - 255 )
    private constant integer COLOR_ALPHA         = 255
    //Red part of the color of the split orb ( 0 - 255 )
    private constant integer SPLIT_COLOR_RED     = 255
    //Green part of the color of the split orb ( 0 - 255 )
    private constant integer SPLIT_COLOR_GREEN   = 255
    //Blue part of the color of the split orb ( 0 - 255 )
    private constant integer SPLIT_COLOR_BLUE    = 255
    //Alpha part of the color of the split orb ( 0 - 255 )
    private constant integer SPLIT_COLOR_ALPHA   = 255
    //The move timer interval
    private constant real    TIMER_INTERVAL      = 0.02
    //Max distance of the splits to the main orb.
    private constant real    MAX_DISTANCE        = 300.00
    //Min distance of the splits to the main orb.
    private constant real    MIN_DISTANCE        = 100.00
    //Max rotation speed of the splits in grad.
    private constant real    MAX_SPEED           = 2.00
    //Min rotation speed of the splits in grad.
    private constant real    MIN_SPEED           = 0.50
    //Flyheight of the main orb.
    private constant real    MAIN_FLY_HEIGHT     = 500.00
    //Maximal cooldown add.
    private constant real    MAX_COOLDOWN_ADD    = 3.00
    //Delay between summon and split.
    private constant real    SPLIT_DELAY         = 3.00
    //Size of the main orb 1 == 100% size.
    private constant real    MAIN_SIZE           = 3.00
    //Size of the splits orb 1 == 100% size.
    private constant real    SPLIT_SIZE          = 1.00
    //Model of the splits.
    private constant string  SPLIT_MODEL         = "Abilities\\Weapons\\PhoenixMissile\\Phoenix_Missile.mdl" 
    //Model of the main orb.
    private constant string  MAIN_MODEL          = "Abilities\\Weapons\\RedDragonBreath\\RedDragonMissile.mdl"
    //Effect when the main orb split up.
    private constant string  SPLIT_EFFECT        = "Abilities\\Spells\\Orc\\FeralSpirit\\feralspiritdone.mdl"
    //Effect when the main orb comes to gether.
    private constant string  SPLIT_END_EFFECT    = ""
    //Order string of the split spell.
    private constant string  ORDER_STRING        = "acidbomb"
    //Effect when the main orb appears.
    private constant string  CREATE_EFFECT       = "Abilities\\Spells\\Other\\Incinerate\\FireLordDeathExplode.mdl"
    //Effect when the main orb disappears.
    private constant string  REMOVE_EFFECT       = "Abilities\\Spells\\Other\\Incinerate\\FireLordDeathExplode.mdl"
    //Should the main orb get invisible during splitting?
    private constant boolean HIDE_MAIN           = true
    //Is the split spell targeting enemies?
    private constant boolean TARGET_ENEMY        = true
    //Should the splits fly around on 3d?
    private constant boolean 3D                  = true
    
    private vector           AXISZ //System
    private vector           AXISX //System
    private vector           AXISY //System
    private vector           TEMPVECTOR2 //System
    private real     array   COOLDOWN //System
    private real     array   DURATION //System
    private real     array   AOE //System
    private group            TEMPGROUP           = CreateGroup() //System
endglobals

//Cooldown of the split spell.
private function SET_COOLDOWN takes nothing returns nothing
    set COOLDOWN[1] = 3.00
    set COOLDOWN[2] = 3.00
    set COOLDOWN[3] = 3.00
    set COOLDOWN[4] = 3.00
endfunction

//Duration of the whole spell
private function SET_DURATION takes nothing returns nothing
    set DURATION[1] = 12.00
    set DURATION[2] = 12.00
    set DURATION[3] = 12.00
    set DURATION[4] = 12.00
endfunction

//Range of the dummy spell ( the value in the oe should be bigger then this )
private function SET_AOE takes nothing returns nothing
    set AOE[1] = 550.00
    set AOE[2] = 550.00
    set AOE[3] = 550.00
    set AOE[4] = 550.00
endfunction

//*************************************************************************************************************//
//                                                     !SYSTEM!                                                //
//*************************************************************************************************************//

private keyword SF_Split
private keyword SF_Main

private function IsAliveAndUnitAndNotMagicImmune takes nothing returns boolean
    return GetWidgetLife( GetFilterUnit() ) > 0.405 and IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false and IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE) == false
endfunction

private struct SF_Split
    unit split
    integer movescounter = 0
    real angleZ
    real angleX
    real angleY
    real cd = 0.00
    real nextcast = 0.00
    
    boolean reachedLoc = false
    boolean goinInit = false
    
    effect sfx
    
    SF_Main root
    vector posi
    vector tmpposi
    vector move
    
    method onDestroy takes nothing returns nothing
        call DestroyEffect( .sfx )
        call KillUnit( .split )
        set .sfx = null
        set .split = null
        call .posi.destroy()
        call .move.destroy()
    endmethod
    
    private method GetRandomNextCast takes nothing returns nothing
        set .nextcast = COOLDOWN[.root.level] + GetRandomReal( 0.00, MAX_COOLDOWN_ADD )
    endmethod
    
    private method Cast takes nothing returns nothing
        local unit u
        call .GetRandomNextCast()
        set .cd = 0.00
        call GroupEnumUnitsInRange( TEMPGROUP, GetUnitX( .split ), GetUnitY( .split ), AOE[.root.level], Condition( function IsAliveAndUnitAndNotMagicImmune ) )
        loop
            set u = FirstOfGroup( TEMPGROUP )
            exitwhen u == null
            if IsUnitEnemy( u, .root.owner ) == TARGET_ENEMY then
                call IssueTargetOrder( .split, ORDER_STRING, u )
                set u = null
                call GroupClear( TEMPGROUP )
                exitwhen true
            endif
            call GroupRemoveUnit( TEMPGROUP, u )
        endloop
    endmethod
    
    private method Zangle takes real z returns nothing
        local integer i=R2I(z*bj_RADTODEG+90.5)
        if(i>=180) then
            set i=179
        elseif(i<0) then
            set i=0
        endif
            
        call SetUnitAnimationByIndex(.split, i  )
    endmethod
    
    private method Turn takes nothing returns nothing
        local real z = .posi.z
        local real x = .posi.x
        local real y = .posi.y
        call .posi.rotate( AXISZ, .angleZ )
        set x = ( .root.posi.x + .posi.x ) - ( .root.posi.x + x )
        set y = ( .root.posi.y + .posi.y ) - ( .root.posi.y + y )
        if 3D == true then
            call .posi.rotate( AXISX, .angleX )
            call .posi.rotate( AXISY, .angleY )
            set z = ( .root.posi.z + .posi.z ) - ( .root.posi.z + z )
            call .Zangle( Atan(( z  / (SquareRoot(x*x + y*y))) ) )
            call SetUnitZ( .split, .root.posi.z + .posi.z )
        endif
        call SetUnitX( .split, .root.posi.x + .posi.x )
        call SetUnitY( .split, .root.posi.y + .posi.y )
        call SetUnitFacing(.split,Atan2(y, x)*bj_RADTODEG)
    endmethod
    
     private method SetPositonReturn takes nothing returns nothing
        if .movescounter <= MOVES then
            call .tmpposi.add( .move )
            call SetUnitX( .split, .tmpposi.x )
            call SetUnitY( .split, .tmpposi.y )
            call SetUnitZ( .split, .tmpposi.z )
        else
            call .destroy()
        endif
        set .movescounter = .movescounter + 1
    endmethod
    
    private method SetPositon takes nothing returns nothing
        if .movescounter <= MOVES then
            call .tmpposi.add( .move )
            call SetUnitX( .split, .tmpposi.x )
            call SetUnitY( .split, .tmpposi.y )
            call SetUnitZ( .split, .tmpposi.z )
        else
            set .reachedLoc = true
        endif
        set .movescounter = .movescounter + 1
    endmethod
    
    method control takes nothing returns nothing
        if .root.splitlifetime <= 0.00 then
            call .destroy()
        endif
        if .root.goin == true then
            if .goinInit == false then
                set .movescounter = 0
                set .goinInit = true
                set .tmpposi.x = .root.posi.x + .posi.x
                set .tmpposi.y = .root.posi.y + .posi.y
                set .tmpposi.z = .root.posi.z + .posi.z
                set .move.x = ( .posi.x * -1.00 ) / I2R( MOVES )
                set .move.y = ( .posi.y * -1.00 ) / I2R( MOVES )
                set .move.z = ( .posi.z * -1.00 ) / I2R( MOVES )
                set .movescounter = 0
            endif
            call .SetPositonReturn()
        endif
        if .reachedLoc == false then
            call .SetPositon()
        elseif .root.goin == false then
            call .Turn()
            set .cd = .cd + TIMER_INTERVAL
            if .cd >= .nextcast then
                call .Cast()
            endif
        endif
    endmethod
    
    private method GetRamdomAngle takes nothing returns nothing
        local integer i = GetRandomInt( 0, 1 )
        local real r = GetRandomReal( MIN_SPEED, MAX_SPEED ) * bj_DEGTORAD
        if i == 0 then
            set .angleZ = r * -1
        else
            set .angleZ = r
        endif
        set i = GetRandomInt( 0, 1 )
        set r = GetRandomReal( MIN_SPEED, MAX_SPEED ) * bj_DEGTORAD
        if i == 0 then
            set .angleX = r * -1
        else
            set .angleX = r
        endif
        set i = GetRandomInt( 0, 1 )
        set r = GetRandomReal( MIN_SPEED, MAX_SPEED ) * bj_DEGTORAD
        if i == 0 then
            set .angleY = r * -1
        else
            set .angleY = r
        endif
    endmethod
    
    private method GetRandomPosi takes nothing returns nothing
        local real a = GetRandomReal( 0.00, 360.00 ) * bj_DEGTORAD
        local real b = GetRandomReal( 0.00, 180.00 ) * bj_DEGTORAD
        local real r = GetRandomReal( MIN_DISTANCE, MAX_DISTANCE )
        local real times = I2R( MOVES )
        set .posi = vector.create( r*Cos(a)*Cos(b), r*Cos(a)*Sin(b), r*Sin(a) )
        set .move = vector.create( .posi.x / times , .posi.y / times, .posi.z / times )
    endmethod
    
    static method create takes SF_Main root returns SF_Split
        local SF_Split data = SF_Split.allocate()
        set data.root = root
        call data.GetRandomPosi()
        call data.GetRamdomAngle()
        set data.split = CreateUnit( root.owner, DUMMY_ID, 0.00, 0.00, GetRandomReal( 0.00, 360.00 ) )
        set data.sfx = AddSpecialEffectTarget( SPLIT_MODEL, data.split, "origin" )
        call data.GetRandomNextCast()
        call UnitAddAbility( data.split, SPLIT_SPELL )
        call SetUnitAbilityLevel( data.split, SPLIT_SPELL, data.root.level )
        call data.SetPositon()
        call SetUnitVertexColor( data.split, SPLIT_COLOR_RED, SPLIT_COLOR_GREEN, SPLIT_COLOR_BLUE, SPLIT_COLOR_ALPHA )
        call SetUnitScale( data.split, SPLIT_SIZE, SPLIT_SIZE, SPLIT_SIZE )
        set data.tmpposi = vector.create( root.posi.x, root.posi.y, root.posi.z )
        return data
    endmethod
    
endstruct

private function Control takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local SF_Main data = GetTimerData( t )
    call data.control()
    set t = null
endfunction

private struct SF_Main
    unit main = null
    unit caster = null
    
    integer level = 1
    timer t = null
    
    player owner = null
    
    boolean goin = false
    boolean splitupdone = false
    boolean end = false
    boolean moving = false
    
    real splitlifetime
    real delay = SPLIT_DELAY
    
    effect sfx = null
    
    SF_Main data = 0
    SF_Split array splits[MAX_SPLITS]
    
    vector posi = 0
    vector move = 0
    
    method control takes nothing returns nothing
        local integer i = 0
        if .splitupdone == false then
            set .delay = .delay - TIMER_INTERVAL
            if .delay <= 0.00 then
                set .splitupdone = true
                call DestroyEffect( AddSpecialEffectTarget( SPLIT_EFFECT, .main, "origin" ) )
                if HIDE_MAIN then
                    call SetUnitVertexColor( .main, 255, 255, 255, 0 )
                endif
                loop
                    exitwhen i == MAX_SPLITS
                    set .splits[i] = SF_Split.create( .data )
                    set i = i + 1
                endloop
            endif
        endif
        if .splitlifetime <= 0.00 and .end == false then
            set .delay = SPLIT_DELAY
            set .end = true
            if HIDE_MAIN then
                call SetUnitVertexColor( .main, COLOR_RED, COLOR_GREEN, COLOR_BLUE, COLOR_ALPHA )
                call DestroyEffect( AddSpecialEffectTarget( SPLIT_END_EFFECT, .main, "origin" ) )
                set i = 0
                loop
                    exitwhen i == MAX_SPLITS
                    if .splits[i] != 0 then
                        call .splits[i].control()
                    endif
                    set i = i + 1
                endloop
            endif
        endif
        if .end == true then
            set .delay = .delay - TIMER_INTERVAL
            if .delay <= 0.00 then
                call DestroyEffect( AddSpecialEffectTarget( REMOVE_EFFECT, .main, "origin" ) )
                call .destroy()
            endif
        endif
        if .moving then
            call .posi.add( .move )
            call SetUnitX( .main, .posi.x )
            call SetUnitY( .main, .posi.y )
        endif
        if .splitlifetime <= I2R( MOVES ) * TIMER_INTERVAL and .goin == false then
            set .goin = true
        endif
        set i = 0
        if .splitupdone and not .end then
            set .splitlifetime = .splitlifetime - TIMER_INTERVAL
            loop
                exitwhen i == MAX_SPLITS
                if .splits[i] != 0 then
                    call .splits[i].control()
                endif
                set i = i + 1
            endloop
        endif
    endmethod
    
    method onDestroy takes nothing returns nothing
        call ReleaseTimer( .t )
        call DestroyEffect( .sfx )
        call KillUnit( .main )
        call .posi.destroy()
        if .moving == true then
            call .move.destroy()
        endif
    endmethod
    
    static method create takes unit caster, real x, real y, vector move returns SF_Main
        local SF_Main data = SF_Main.allocate()
        set data.data = data
        set data.t = NewTimer()
        call SetTimerData( data.t, data )
        set data.caster = caster
        set data.owner = GetOwningPlayer( caster )
        set data.main = CreateUnit( data.owner, DUMMY_ID, x, y, GetRandomReal( 0.00, 360.00 ) )
        set data.sfx = AddSpecialEffectTarget( MAIN_MODEL, data.main, "origin" )
        set data.level = GetUnitAbilityLevel( caster, SPELL_ID )
        set data.splitlifetime = DURATION[data.level]
        call SetUnitFlyHeight( data.main, MAIN_FLY_HEIGHT, 0.00 )
        call DestroyEffect( AddSpecialEffectTarget( CREATE_EFFECT, data.main, "origin" ) )
        call UnitAddAbility( data.main, MAIN_SPELL )
        call SetUnitAbilityLevel( data.main, MAIN_SPELL, data.level )
        call SetUnitVertexColor( data.main, COLOR_RED, COLOR_GREEN, COLOR_BLUE, COLOR_ALPHA )
        call SetUnitScale( data.main, MAIN_SIZE, MAIN_SIZE, MAIN_SIZE )
        if move != 0 then
            set data.move = move
            set data.moving = true
        endif
        set data.posi = vector.create( x, y, GetUnitZ( data.main ) )
        call TimerStart( data.t, TIMER_INTERVAL, true, function Control )
        set caster = null
        return data
    endmethod
    
endstruct

private function IsSpell takes nothing returns boolean
    if GetSpellAbilityId() == SPELL_ID then
        call SF_Main.create( GetTriggerUnit(), GetSpellTargetX(), GetSpellTargetY(), 0 )
    endif
    return false
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 IsSpell ) )
    
    set AXISX = vector.create( 1.00, 0.00, 0.00 )
    set AXISY = vector.create( 0.00, 1.00, 0.00 )
    set AXISZ = vector.create( 0.00, 0.00, 1.00 )
    set TEMPVECTOR2 = vector.create( 0.00, 0.00, 0.00 )
    
    call SET_COOLDOWN()
    call SET_DURATION()
    call SET_AOE()
    
    set t = null
endfunction

endscope
 

Attachments

  • Burning Orbit v0.06.w3x
    62.3 KB · Views: 32
Last edited:
Level 6
Joined
Jun 18, 2011
Messages
147
I wonder how the creator got it to save then... Gonna rename it i3D...
That worked. THANK YOU :D

Edit: New problem... So, I was able to save the original map with the private constant boolean 3D after re-downloading the file from the Spells archive of the hive. I do not get these debug messages in that map, but in my map (where I changed the label to "i3D" and then just "G") I get them as the spell ends and the fireballs fly back together and create an explosion...

207143-albums4889-picture56149.jpg


The only trigger I could find Double free in is TimerUtils, and the only one with SF_Split is the Burning Orbit trigger.

JASS:
library_once TimerUtils initializer redInit
//*********************************************************************
//* TimerUtils (Red flavor)
//* ----------
//*
//*  To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//*  To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass)   More scripts: htt://www.wc3campaigns.net
//*
//* For your timer needs:
//*  * Attaching
//*  * Recycling (with double-free protection)
//*
//* set t=NewTimer()      : Get a timer (alternative to CreateTimer)
//* ReleaseTimer(t)       : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2)     : Attach value 2 to timer
//* GetTimerData(t)       : Get the timer's value.
//*                         You can assume a timer's value is 0
//*                         after NewTimer.
//*
//* Red flavor: Fastest, method in existence for timer attaching,
//*             only takes an array lookup, H2I and subtraction. 
//*             However, all the code in your map requires extra care
//*             not to forget to call ReleaseTimer. It also requires
//*             to preload a lot of timers at map init, they use
//*             memory and handle ids.
//*
//*             I recommend you run your map in debug mode the first
//* time after adding it, make sure you can see map init messages
//* if nothing appears, all is done, if an error appears, it might
//* suggest you a value with OFFSET, in that case, update that value
//* if it still does not work after updating (rare), try a bigger
//* OFFSET by 1000 for example. (Sounds hard? Then use blue or purple
//* timerutils that are friendlier though not as fast)
//*
//********************************************************************

//================================================================
    globals
        private constant integer OFFSET     = 0x100000
        private constant integer QUANTITY   = 256
        private constant integer ARRAY_SIZE = 8191 //changing this to a higher value would effectively
                                                   //cripple the performance making this thing irrelevant

    endglobals

    //=================================================================================================
    private function H2I takes handle h returns integer
        return GetHandleId( h )
    endfunction

    //==================================================================================================
    globals
        private integer array data[ARRAY_SIZE]
    endglobals

    //It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
    function SetTimerData takes timer t, integer value returns nothing
        debug if(H2I(t)-OFFSET<0) then
        debug     call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
        debug endif
        set data[H2I(t)-OFFSET]=value
    endfunction

    function GetTimerData takes timer t returns integer
        debug if(H2I(t)-OFFSET<0) then
        debug     call BJDebugMsg("GetTimerData: Wrong handle id, only use GetTimerData on timers created by NewTimer")
        debug endif

        return data[H2I(t)-OFFSET]
    endfunction

    //==========================================================================================
    globals
        private timer array tT
        private integer tN = 0
        private constant integer HELD=0x28829022
        //use a totally random number here, the more improbable someone uses it, the better.
    endglobals

    //==========================================================================================
    function NewTimer takes nothing returns timer
        if (tN==0) then
            //If this happens then the QUANTITY rule has already been broken, try to fix the
            // issue, else fail.
            debug call BJDebugMsg("NewTimer: Warning, Exceeding TimerUtils_QUANTITY, please increase it for your map, fix your map's timer leaks or switch to blue flavor when applicable")
            set tT[0]=CreateTimer()
            if (H2I(tT[0])-OFFSET<0) or (H2I(tT[0])-OFFSET>=ARRAY_SIZE) then
                //all right, couldn't fix it
                call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably switch to the blue flavor or fix timer leaks.")
                return null
            endif
        else
            set tN=tN-1
        endif
        call SetTimerData(tT[tN],0)
     return tT[tN]
    endfunction

    //==========================================================================================
    function ReleaseTimer takes timer t returns nothing
        if(t==null) then
            debug call BJDebugMsg("Warning: attempt to release a null timer")
            return
        endif
        if (tN==8191) then
            debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")

            //stack is full, the map already has much more troubles than the chance of bug
            call DestroyTimer(t)
        else
            call PauseTimer(t)
            if(GetTimerData(t)==HELD) then
                debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
                return
            endif
            call SetTimerData(t,HELD)
            set tT[tN]=t
            set tN=tN+1
        endif    
    endfunction

    private function redInit takes nothing returns nothing
     local integer i=0
     local integer bestoffset=-1

        loop
            exitwhen (i==QUANTITY)
            set tT[i] = CreateTimer()
            if(i==0) then
                set bestoffset=H2I(tT[i])
            endif
            if (H2I(tT[i])-OFFSET>=ARRAY_SIZE) then
                debug call BJDebugMsg("TimerUtils_redInit: Failed a initializing attempt")
                debug call BJDebugMsg("The timer limit is "+I2S(i))
                debug call BJDebugMsg("This is a rare ocurrence, if the timer limit is too low, to change OFFSET to "+I2S(bestoffset) )
                exitwhen true
            endif
            if (H2I(tT[i])-OFFSET>=0)  then
                set i=i+1
            endif
        endloop

        set tN=i
    endfunction

endlibrary
 
Last edited:

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
As 3D is private it does not pre-compile to start with a number (a private prefix is applied) thus it should work. On the other hand, if the libary or scope it belongs to starts with a number it will not work.

The messages you are getting are because you are deallocating a jasshelper struct index more than 1 time before allowing it to be reallocated.
 
Level 6
Joined
Jun 18, 2011
Messages
147
I'm sorry, I researched reallocating/deallocating struct indexes a bit, but I am unfamiliar with programming, and can't figure out how to fix the problem with the information you gave me.

Could you find the problem in the code and tell me what to change.

Thank you

I don't understand why the library or scope it belongs to would only start with a number in my map.

The only 2 occurances of 3D are...

JASS:
globals...
private constant boolean 3D                  = true...
endglobals

JASS:
private method Turn takes nothing returns nothing
        local real z = .posi.z
        local real x = .posi.x
        local real y = .posi.y
        call .posi.rotate( AXISZ, .angleZ )
        set x = ( .root.posi.x + .posi.x ) - ( .root.posi.x + x )
        set y = ( .root.posi.y + .posi.y ) - ( .root.posi.y + y )
        if 3D == true then
            call .posi.rotate( AXISX, .angleX )
            call .posi.rotate( AXISY, .angleY )
            set z = ( .root.posi.z + .posi.z ) - ( .root.posi.z + z )
            call .Zangle( Atan(( z  / (SquareRoot(x*x + y*y))) ) )
            call SetUnitZ( .split, .root.posi.z + .posi.z )
        endif
        call SetUnitX( .split, .root.posi.x + .posi.x )
        call SetUnitY( .split, .root.posi.y + .posi.y )
        call SetUnitFacing(.split,Atan2(y, x)*bj_RADTODEG)
    endmethod

So, these scopes [(globals and Turn)?] do not begin with a number, and the trigger [(,or library)?] is called Burning Orbit. Thus it should pre-compile, correct?
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
You are calling the .destroy() method of the struct on an instance which has already had the .destroy() method called on it.

To track down, comment out .destroy() methods 1 at a time (this will cause leaks but is only for debugging) until you find the .destroy method that is causing the message. Fix the code so that it only runs once per instance instead of twice or more (which is what it is doing now and why those messages get generated).
 
Level 6
Joined
Jun 18, 2011
Messages
147
Here is the method...

207143-albums4889-picture56153.jpg


JASS:
method control takes nothing returns nothing
        if .root.splitlifetime <= 0.00 then
            call .destroy()
            debug call BJDebugMsg("#4 .posi.destroy")
        endif
        if .root.goin == true then
            if .goinInit == false then
                set .movescounter = 0
                set .goinInit = true
                set .tmpposi.x = .root.posi.x + .posi.x
                set .tmpposi.y = .root.posi.y + .posi.y
                set .tmpposi.z = .root.posi.z + .posi.z
                set .move.x = ( .posi.x * -1.00 ) / I2R( MOVES )
                set .move.y = ( .posi.y * -1.00 ) / I2R( MOVES )
                set .move.z = ( .posi.z * -1.00 ) / I2R( MOVES )
                set .movescounter = 0
            endif
            call .SetPositonReturn()
        endif
        if .reachedLoc == false then
            call .SetPositon()
        elseif .root.goin == false then
            call .Turn()
            set .cd = .cd + TIMER_INTERVAL
            if .cd >= .nextcast then
                call .Cast()
            endif
        endif
    endmethod

I'm not sure how to fix it so that it only runs it once. :/
I like learning on my own, but if you wouldn't mind, I'd like your help to get it over with.
 
Last edited:
Level 6
Joined
Jun 18, 2011
Messages
147
I don't think he is active anymore. Any more tips on how to fix it? I've tried deleting/changing a few lines here and there.

My first attempt, I created a huge increasing leak (changing PauseTimer to ReleaseTimer in TimerUtils), because of a comment I read on the Spell's hive page.

Second try, I deleted the if/endif statement of the method in question containing the debug messaged .destroy, and got a few minor special effect leaks, but no debug message.

207143-albums4999-picture56156.jpg


P.S. the earlier (debug message) screenshot is misleading (I was CnPing the debug messages and forgot to change it from .posi.destroy to .destroy), but it is the fourth instance of .destroy using the finder and is the .destroy shown in the method I hid above.

P.S. 2 I think the reason that the struct is being called in the same method might be related to the reason I can't save the index 3D. Do you think the spell is not using arrays where it should be. Could my jasshelper be out of date, because when opening a new downloaded map, the WE almost always warns me that the map was saved with a newer version of WE. I mean I don't really think that my JASS structs are not being compiled/indexed as arrays, otherwise I would think I would have a lot more problems than this little issue. I am just expressing this crazy idea for you to build upon.

Cedi said:
Structs variables are only arrays with a special name. The struct is only an integer which stays for the index of the variable. Because of that you need to write in a constant array lenght for array variables in structs. Then this value representate the offset.

For example.

struct A
integer i
integer array i2[20]
endstruct

when you create a struct it has a number for example 0.
Yet there exist an integer array variable with the name A__i or something like that. When you set i == a value wc3 sets A__i[0] == the value.
On struct variable arrays they have reserved places. A__i2[0 - 20] is reserved for the struct.
The next struct has the places 21 - 41 and so on. Because of that you can have only 8191 / constant array size structs.

The result is, all struct members are globals. And globals can't leak.

So you see, caster is a local variable == Needs to be nulled. Main is a global variable == you don't have to null it. And where is there a debug msg?
RMX said:
Well i understand, this is very good info for me :D.

About the Debug message .. it said ( Double free something... ) don't know where it is ...

Then they never discussed it further >.>

Another thought: Two different methods are both named "control" [First is the method with .destroy() #4. The second method control also has a .destroy() that I have tried removing and it did the same thing as when I changed PauseTimer to ReleaseTimer (created a really big increasing leak)] and there is even a function named "Control".

Last but not least... Does the "Double Free" message even mean that the spell is leaking? Could I just get rid of the debug message in TimerUtils and forget about this whole ordeal?
 
Last edited:
Status
Not open for further replies.
Top