• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[JASS] Spell works not, please help.

Status
Not open for further replies.
Level 21
Joined
Aug 9, 2006
Messages
2,384
This Script creates 8 rocks which !should! rotate and get faster and faster, but it does not work. And i have no Idea why.

JASS:
scope MagmaBarricade

public struct Data
    real x1
    real y1
    real facing
    integer RockCount = 0
    unit array RockUnit [8]
    unit MagmaCaster = GetTriggerUnit()
    real y = GetUnitY(.MagmaCaster)
    real x = GetUnitX(.MagmaCaster)
    player MagmaCasterOwner = GetOwningPlayer(.MagmaCaster)
    real cangle = 2
    real knockbackr = 200
    timer t = CreateTimer()
endstruct

function MagmaBarricadeConditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A000'
endfunction

function MagmaBarricadeRotate takes nothing returns nothing
    local Data kd
    local integer count = 0
    set kd.facing = 0
    set kd.y = GetUnitY(kd.MagmaCaster)
    set kd.x = GetUnitX(kd.MagmaCaster)
    loop
        exitwhen count == 8
        set kd.x1 = kd.x + 100.00 * Cos((kd.facing + kd.cangle) * bj_DEGTORAD )
        set kd.y1 = kd.y + 100.00 * Sin((kd.facing + kd.cangle) * bj_DEGTORAD )
        call SetUnitPosition(kd.RockUnit[count], kd.x1, kd.y1)
        set kd.facing = kd.facing + 45
        set count = count + 1
    endloop
    set count = 0
    if kd.cangle < 20 then
        set kd.cangle = kd.cangle + 0.02
        set kd.knockbackr = kd.knockbackr + 0.1
    endif
    if (GetUnitAbilityLevel(kd.MagmaCaster, 'B000') == 0) then
        loop
            exitwhen count == 8
            call RemoveUnit(kd.RockUnit[count])
            set count = count + 1
        endloop
        call kd.destroy()
    endif
endfunction

function MagmaBarricadeSetUp takes nothing returns nothing
    local Data kd = Data.create()
    loop
        exitwhen kd.RockCount == 8
        set kd.x1 = kd.x + 100.00 * Cos(kd.facing * bj_DEGTORAD )
        set kd.y1 = kd.y + 100.00 * Sin(kd.facing * bj_DEGTORAD )
        call DestroyEffect(AddSpecialEffect("Abilities\\Weapons\\DemolisherFireMissile\\DemolisherFireMissile.mdl", kd.x1, kd.y1))
        set kd.RockUnit[kd.RockCount] = CreateUnit(kd.MagmaCasterOwner, 'n000', kd.x1, kd.y1, 0.00)
        call SetUnitTimeScale(kd.RockUnit[kd.RockCount], 0 * 0.01)
        set kd.RockCount = kd.RockCount + 1
        set kd.facing = kd.facing + 45
    endloop
    call TimerStart(kd.t, 0.02, true, function MagmaBarricadeRotate)
endfunction

//===========================================================================
function InitTrig_MagmaBarricade takes nothing returns nothing
    local integer index = 0
    set gg_trg_MagmaBarricade = CreateTrigger(  )
    loop
        call TriggerRegisterPlayerUnitEvent(gg_trg_MagmaBarricade, Player(index), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
        set index = index + 1
        exitwhen index == bj_MAX_PLAYER_SLOTS
    endloop
    call TriggerAddCondition( gg_trg_MagmaBarricade, Condition( function MagmaBarricadeConditions ) )
    call TriggerAddAction( gg_trg_MagmaBarricade, function MagmaBarricadeSetUp )
endfunction
endscope
 
Level 5
Joined
Oct 27, 2007
Messages
158
In MagmaBarricadeRotate you only declare a pointer type of Data. You also have to create the object before using the reference variable. You have two different local references to a Data struct. Just because they're the same name doesn't mean they both automatically point to the same Data struct.

Furthermore you have a conditional struct destroy. This can lead to leaking Data objects.
 
Level 5
Joined
Oct 27, 2007
Messages
158
I also see that you use already created rockunits. This won't work without attaching the struct to the timer. That will also solve the issue of a non initialized local kd reference variable. I will post some code in a minute....

JASS:
scope MagmaBarricade
public struct Data
    real x1
    real y1
    real facing
    integer RockCount = 0
    unit array RockUnit [8]
    unit MagmaCaster = GetTriggerUnit()
    real y = GetUnitY(.MagmaCaster)
    real x = GetUnitX(.MagmaCaster)
    player MagmaCasterOwner = GetOwningPlayer(.MagmaCaster)
    real cangle = 2
    real knockbackr = 200
endstruct

function MagmaBarricadeConditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A000'
endfunction

function MagmaBarricadeRotate takes nothing returns nothing
    local timer t = GetExpiredTimer() // Get the timer with the attached struct Data
    local Data kd = GetHandleInt(t) // Get the Data struct from the timer handle index reference.
    set kd.RockCount = 0
    set kd.facing = 0
    set kd.y = GetUnitY(kd.MagmaCaster)
    set kd.x = GetUnitX(kd.MagmaCaster)
    loop
        exitwhen kd.RockCount == 8 // No need for an extra local indexing variable, you can reuse kd.RockCount.
        set kd.x1 = kd.x + 100.00 * Cos((kd.facing + kd.cangle) * bj_DEGTORAD )
        set kd.y1 = kd.y + 100.00 * Sin((kd.facing + kd.cangle) * bj_DEGTORAD )
        call SetUnitPosition(kd.RockUnit[kd.RockCount], kd.x1, kd.y1)
        set kd.facing = kd.facing + 45
        set kd.RockCount = kd.RockCount + 1
    endloop
    if kd.cangle < 20 then
        set kd.cangle = kd.cangle + 0.02
        set kd.knockbackr = kd.knockbackr + 0.1
    endif
    if (GetUnitAbilityLevel(kd.MagmaCaster, 'B000') == 0) then
        set kd.RockCount = 0
        loop
            exitwhen kd.RockCount == 8
            call RemoveUnit(kd.RockUnit[kd.RockCount])
            set kd.RockCount = kd.RockCount + 1
        endloop
        call PauseTimer(t) // Destroy the timer when you're done with it.
        call DestroyTimer(t)
        call kd.destroy() // Are you sure the condition is always met when the spell is done? If not this will leak a Timer object and a pointer.
    endif
    set t = null
endfunction

function MagmaBarricadeSetUp takes nothing returns nothing
    local timer t = CreateTimer() // It's not necessary to include the timer in the Data struct.
    local Data kd = Data.create()
    loop
        exitwhen kd.RockCount == 8
        set kd.x1 = kd.x + 100.00 * Cos(kd.facing * bj_DEGTORAD )
        set kd.y1 = kd.y + 100.00 * Sin(kd.facing * bj_DEGTORAD )
        call DestroyEffect(AddSpecialEffect("Abilities\\Weapons\\DemolisherFireMissile\\DemolisherFireMissile.mdl", kd.x1, kd.y1))
        set kd.RockUnit[kd.RockCount] = CreateUnit(kd.MagmaCasterOwner, 'n000', kd.x1, kd.y1, 0.00)
        call SetUnitTimeScale(kd.RockUnit[kd.RockCount], 0 * 0.01)
        set kd.RockCount = kd.RockCount + 1
        set kd.facing = kd.facing + 45
    endloop
    call SetHandleInt(t, kd) // Attach the struct to the handle index of the timer
    call TimerStart(t, 0.02, true, function MagmaBarricadeRotate)
    set t = null
endfunction

//===========================================================================
function InitTrig_MagmaBarricade takes nothing returns nothing
    local integer index = 0
    set gg_trg_MagmaBarricade = CreateTrigger( )
    loop
        call TriggerRegisterPlayerUnitEvent(gg_trg_MagmaBarricade, Player(index), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
        set index = index + 1
        exitwhen index == bj_MAX_PLAYER_SLOTS
    endloop
    call TriggerAddCondition( gg_trg_MagmaBarricade, Condition( function MagmaBarricadeConditions ) )
    call TriggerAddAction( gg_trg_MagmaBarricade, function MagmaBarricadeSetUp )
endfunction
endscope
This uses the handle var array attach system. Easy to use and easy to setup.
SetHandleInt(handle h, integer value) is used to attach a struct to a handle reference.
GetHandleInt(handle h) is used to get a previously attached structure from a handle reference.

What I mean with leaking objects is that you forgot to destroy and null the timer when you're done with it. Furthermore are you sure the code that checks for ability level 0 is always guaranteed to execute? In that case it won't leak a timer or a pointer.
 
Last edited:
Status
Not open for further replies.
Top