• 🏆 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] If glitch

Status
Not open for further replies.
hey i'm making a diablo 3 spell (seismic slam) but on run of the spell the code skips a part of it (the part with indexing and set variables)
JASS:
library SeismicSlam
    globals
        private constant    integer     SPELL_ID = 'A001'
        private constant    real        REFRESH_TIME = .05  
        private constant    real        DISTANCE_BETWEEN_SLAMS = 80.
        private constant    real        AOE_RANGE = 80.
        private             string      EffectModel = "Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl"
        private             real        Variation = 10.
    endglobals
    
    private struct SeismicWave
        unit Caster
        integer Level
        integer Slams
        real StartX
        real StartY
        real Angle
        
        private integer i
        
        private static timer Tim           = CreateTimer()
        private static integer Total       = 0
        private static thistype array SeismicWaves
        
        static integer StoredLevel
        static unit StoredCaster
        
        //============================ settings ==============================
        private static method NumberOfSlams takes integer lvl returns integer
            return 5+(3*lvl)
        endmethod
        
        private static method GetDamage takes integer lvl returns real
            return 100.+(25.*R2I(lvl))
        endmethod
        //========================== end of settings =========================
        
        private static method Damage takes nothing returns nothing
            //filter here
            //if blabla == lol then
            call UnitDamageTarget(StoredCaster,GetEnumUnit(),thistype.GetDamage(StoredLevel),true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
            //endif
        endmethod
        
        private method onDestroy takes nothing returns nothing
            set Total = Total - 1
            call BJDebugMsg("total = total - 1")
            call BJDebugMsg("total= "+ I2S(Total))
            set SeismicWaves[i] = SeismicWaves[Total]
            set SeismicWaves[i].i=i
            if Total == 0 then
                call PauseTimer(Tim)
            endif
        endmethod
        
        private static method onLoop takes nothing returns nothing
            local thistype dat
            local integer i2 = Total-1
            local group g = CreateGroup()
            local real curx
            local real cury
            local real anglevariation
            call BJDebugMsg(I2S(Total))
            call BJDebugMsg("run loop")
            call BJDebugMsg(I2S(i2))
            loop
                exitwhen i2 < 0
                set dat = SeismicWaves[i2]
                call BJDebugMsg(I2S(NumberOfSlams(dat.Level)))
                if dat.Slams < NumberOfSlams(dat.Level) then
                    call BJDebugMsg("slams smaller then max nr. of slams")
                    set anglevariation = GetRandomReal(Variation*(-1),Variation)
                    set curx = Sin((dat.Angle + anglevariation) * bj_DEGTORAD) * (DISTANCE_BETWEEN_SLAMS * dat.Slams)
                    set cury = Cos((dat.Angle + anglevariation) * bj_DEGTORAD) * (DISTANCE_BETWEEN_SLAMS * dat.Slams)
                    set dat.Slams = dat.Slams+1
                    set StoredLevel = dat.Level
                    set StoredCaster = dat.Caster
                    call GroupEnumUnitsInRange(g,curx,cury,AOE_RANGE,null)
                    call ForGroup(g,function thistype.Damage)
                    call DestroyEffect(AddSpecialEffect(EffectModel,curx,cury))
                    call GroupClear(g)
                else
                    call dat.destroy()
                    call BJDebugMsg("dat.destroy")
                    //call deallocate(dat)
                endif
                set i2 = i2-1
            endloop
            call DestroyGroup(g)
            set g = null
        endmethod
        
        private static method Check takes nothing returns boolean
            local thistype dat
            local real angle
            call BJDebugMsg("check")
            if GetSpellAbilityId() == SPELL_ID then
                call BJDebugMsg("Correct spell")
                if Total==0 then
                    call TimerStart(Tim,REFRESH_TIME,true,function thistype.onLoop)
                endif
                set dat.i=Total
                set Total = Total+1
                set dat = thistype.allocate()
                set dat.Caster = GetTriggerUnit()
                set dat.Level = GetUnitAbilityLevel(dat.Caster,SPELL_ID)
                call BJDebugMsg(I2S(dat.Level))
                set dat.Slams = 0
                set dat.StartX = GetUnitX(dat.Caster)
                call BJDebugMsg(R2S(dat.StartX))
                set dat.StartY = GetUnitY(dat.Caster)
                call BJDebugMsg(R2S(dat.StartY))
                set dat.Angle = Atan2(GetLocationY(GetSpellTargetLoc()) - dat.StartY, GetLocationX(GetSpellTargetLoc()) - dat.StartX)*bj_RADTODEG
                call BJDebugMsg(R2S(dat.Angle))
            endif
            return false
        endmethod
        
        private static method onInit takes nothing returns nothing
            local trigger t = CreateTrigger()
            call BJDebugMsg("init")
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
            call TriggerAddCondition(t, Condition(function thistype.Check))
        endmethod
    endstruct
endlibrary

here the if skips the rest:
JASS:
private static method Check takes nothing returns boolean
            local thistype dat
            local real angle
            call BJDebugMsg("check")
            if GetSpellAbilityId() == SPELL_ID then
                call BJDebugMsg("Correct spell")
                if Total==0 then
                    call TimerStart(Tim,REFRESH_TIME,true,function thistype.onLoop)
                endif
the rest is skipped and so the whole spell bugs and never stops running

plz help and you get +rep ;)
 
Level 14
Joined
Nov 18, 2007
Messages
1,084
This probably won't help too much, but shouldn't
JASS:
set dat.i=Total
set Total = Total+1
set dat = thistype.allocate()
be
JASS:
set dat = thistype.allocate()
set dat.i=Total
set Total = Total+1
This is a bit unrelated, but why didn't use the create method instead?

More unrelated: You should use GetSpellTargetX()/GetSpellTargetY() instead. I could point out more things you could improve with your code, but it's off-topic.

Edit:
I just went over your entire code. It should work now.
l
JASS:
ibrary SeismicSlam
    globals
        private constant    integer     SPELL_ID = 'A001'
        private constant    real        REFRESH_TIME = .05  
        private constant    real        DISTANCE_BETWEEN_SLAMS = 80.
        private constant    real        AOE_RANGE = 80.
        //I made them constants:
        private constant    string      EffectModel = "Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl"
        private constant    real        Variation = 10. 
    endglobals
    
    private struct SeismicWave
        unit Caster
        integer Level
        integer Slams   = 0 //Set this initially.
        real StartX
        real StartY
        real Angle
        
        private integer i
        
        private static timer Tim           = CreateTimer()
        private static integer Total       = 0
        private static thistype array SeismicWaves
        private static group g             = CreateGroup() //Use a global instead of always making new groups all the time.
        private static thistype temp                       //To temporarily hold the struct's members instead of having separate ones.
        
        //============================ settings ==============================
        private static method NumberOfSlams takes integer lvl returns integer
            return 5+(3*lvl)
        endmethod
        
        private static method GetDamage takes integer lvl returns real
            return 100.+(25.*lvl)
        endmethod
        //========================== end of settings =========================
        
        private static method Damage takes nothing returns nothing
            //filter here
            //if blabla == lol then
            call UnitDamageTarget(temp.Caster,GetEnumUnit(),thistype.GetDamage(temp.Level),true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
            //endif
        endmethod
        
        private method onDestroy takes nothing returns nothing
            call BJDebugMsg("Total = total - 1")
            set Total = Total - 1            
            call BJDebugMsg("Total = " + I2S(Total))
            set SeismicWaves[i] = SeismicWaves[Total]
            set SeismicWaves[i].i=i
            if Total == 0 then
                call PauseTimer(Tim)
            endif
        endmethod
        
        private static method onLoop takes nothing returns nothing
            local thistype dat
            local integer i2 = 0 //I used a different way of looping
            local real curx
            local real cury
            local real anglevariation
            call BJDebugMsg("Total is " + I2S(Total))            
            loop
                exitwhen i2 > Total - 1
                call BJDebugMsg("i2 is " + I2S(i2))
                set dat = SeismicWaves[i2]
                if dat.Slams < NumberOfSlams(dat.Level) then
                    call BJDebugMsg("Slams smaller then max # of slams")
                    set anglevariation = GetRandomReal(-Variation,Variation)*bj_DEGTORAD
                    set curx = dat.StartX + DISTANCE_BETWEEN_SLAMS*dat.Slams*Cos(dat.Angle+ anglevariation) //You switched cos and sin.
                    set cury = dat.StartY + DISTANCE_BETWEEN_SLAMS*dat.Slams*Sin(dat.Angle+ anglevariation) 
                    set dat.Slams = dat.Slams+1
                    set temp = dat
                    call GroupEnumUnitsInRange(g,curx,cury,AOE_RANGE,null)
                    call ForGroup(g,function thistype.Damage)
                    call DestroyEffect(AddSpecialEffect(EffectModel,curx,cury))                    
                else
                    call BJDebugMsg("dat should be destroyed")
                    call dat.destroy()                    
                endif
                set i2 = i2+1
            endloop
        endmethod
        
        private static method Check takes nothing returns boolean
            local thistype dat
            if GetSpellAbilityId() == SPELL_ID then
                set dat = thistype.allocate() //Changed the order
                if Total==0 then
                    call TimerStart(Tim,REFRESH_TIME,true,function thistype.onLoop)
                endif
                set dat.i=Total
                set SeismicWaves[dat.i] = dat //You forgot to do this.
                set Total = Total+1               
                set dat.Caster = GetTriggerUnit()
                set dat.Level = GetUnitAbilityLevel(dat.Caster,SPELL_ID)
                set dat.StartX = GetUnitX(dat.Caster)
                set dat.StartY = GetUnitY(dat.Caster)
                set dat.Angle = Atan2(GetSpellTargetY() - dat.StartY,GetSpellTargetX() - dat.StartX) //Use coordinates instead of locs!
                if dat.Angle == 0 then //In case the caster casted it on himself.
                    set dat.Angle = GetUnitFacing(dat.Caster)*0.017453293
                endif                
                debug call BJDebugMsg("Angle: " + R2S(dat.Angle))
            endif
            return false
        endmethod
        
        private static method onInit takes nothing returns nothing
            local trigger t = CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
            call TriggerAddCondition(t, Condition(function thistype.Check))
            //Preload(EffectModel) You should preload effects.
        endmethod
    endstruct
endlibrary
 
Last edited:

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
Watermelon beat me to it. But this has been tested and I can assure you that it syntaxes perfectly and works perfectly as well. I used the ability Shockwave (I increased the group enum radius because 80. is pretty short, even against a large group of gnolls)

JASS:
//|||||||||||||||||||||||
scope SeismicSlam initializer onInit
//|||||||||||||||||||||||
globals
    private constant    integer     SPELL_ID = 'A001'
    private constant    real        TIMEOUT = .05
    private constant    real        DISTANCE_BETWEEN_SLAMS = 80.
    private constant    real        AOE_RANGE = 130.
    private constant    real        RAND_VAR = 10.
endglobals
//|||||||||||||||||||||||
private struct S
    unit Caster
    player p
    integer Level
    integer Slams = 0
    real Angle
    real x
    real y
    //*
    static timer t = CreateTimer()
    static group g = CreateGroup()
    static integer tot = -1
    static S array Dex
    static integer i
    //*
    method onDestroy takes nothing returns nothing
        if(.tot == 0)then
            call PauseTimer(.t)
        endif
        if(.i < .tot)then
            set .Dex[.i] = .Dex[.tot]
            set .i = .i - 1
        endif
        set .tot = (.tot - 1)
    endmethod
    //*
    static method onLoop takes nothing returns nothing
        local S this
        local real AngVar
        local real x
        local real y
        local unit u
        set .i = 0
        loop
            set this = .Dex[i]
            if(.Slams < 5 + 3*.Level)then
                set .Slams = (.Slams + 1)
                set AngVar = GetRandomReal(-RAND_VAR,RAND_VAR)
                set x = .x + Cos((.Angle + AngVar))*DISTANCE_BETWEEN_SLAMS*.Slams
                set y = .y + Sin((.Angle + AngVar))*DISTANCE_BETWEEN_SLAMS*.Slams
                call GroupEnumUnitsInRange(.g,x,y,AOE_RANGE,null)
                loop
                    set u = FirstOfGroup(.g)
                    exitwhen(u == null)
                    call GroupRemoveUnit(.g,u)
                    if IsUnitEnemy(u,.p) then
                        call UnitDamageTarget(.Caster,u,(100. + 25.*.Level),true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
                    endif
                endloop
                call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl",x,y))
            else
                call .destroy()
            endif
            set .i = (.i + 1)
            exitwhen(.i >= .tot)
        endloop
    endmethod
    //*
    static method create takes nothing returns S
        local S this = .allocate()
        set .tot = (.tot + 1)
        set .Dex[tot] = this
        if(.tot == 0)then
            call TimerStart(.t,TIMEOUT,true,function S.onLoop)
        endif
        return this
    endmethod
//|||||||||||||||||||||||
endstruct
//|||||||||||||||||||||||
private function Actions takes unit u returns nothing
    local S s = S.create()
    set s.Caster = u
    set s.p = GetTriggerPlayer()
    set s.x = GetUnitX(u)
    set s.y = GetUnitY(u)
    set s.Level = GetUnitAbilityLevel(u,SPELL_ID)
    set s.Angle = Atan2(GetSpellTargetY() - s.y,GetSpellTargetX() - s.x)
endfunction
//*
private function Conditions takes nothing returns nothing
    if(GetSpellAbilityId() == SPELL_ID)then
        call Actions(GetTriggerUnit())
    endif
endfunction
//*
private function onInit takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddAction(t,function Conditions)
endfunction
//|||||||||||||||||||||||
endscope
//|||||||||||||||||||||||
 
Last edited:
Status
Not open for further replies.
Top