• 🏆 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] Weird bug.

Status
Not open for further replies.
Level 22
Joined
Dec 31, 2006
Messages
2,216
[SOLVED] Weird bug.

I never thought I had to ask for help on this, but I can't figure it out.
I submitted a spell yesterday and Dynasti found a bug which I thought I had fixed. The bug is really pissing me off because I can't find any reason for why it should happen. The bug is that the footmen suddenly stops in the air, but when I check their flying height it says 0. If someone can find out what's wrong I will give credits and +rep.
I'm not sure if it's any help, but the bug began to show up when I added my knockback system which shouldn't interfere in any way (I think).

Code:


JASS:
library GC

globals
    private constant gamecache gc = InitGameCache("GC.w3v")
endglobals

private function H2I takes handle h returns integer
    return h
    return 0
endfunction

function AttachStruct takes handle h, integer dat, string id returns nothing
    call StoreInteger(gc, I2S(H2I(h)), id, dat)
endfunction

function GetAttachedStruct takes handle h, string id returns integer
    return GetStoredInteger(gc, I2S(H2I(h)), id)
endfunction

endlibrary


JASS:
library Knockback initializer Init

globals
//==========================CONFIGURATION=============================
    private constant real coll = 140. //The collision size of the unit which is knockbacked
    private constant real interval = 0.04 //The interval of the timer
    private constant real grav = 9.81 //The force of gravity
    private constant boolean canfly = true //Can knockbacked units "fly"?
    private constant string gsfx = "Dust.mdx" //The sliding effect on ground
    private constant string wsfx = "Splash.mdx" //The sliding effect on water
//====================================================================
    
    private real MAX_X
    private real MAX_Y
    private real MIN_X
    private real MIN_Y
    
    private integer Total = 0
    private integer array Structs
    private constant timer t = CreateTimer()
    private boolean paused = false
endglobals

private function TreeFilter takes nothing returns boolean
    local integer id = GetDestructableTypeId(GetFilterDestructable())
    return id == 'LTlt' or id == 'ATtr' or id == 'BTtw' or id == 'KTtw' or id == 'YTft' or id == 'JTct' or id == 'YTst' or id == 'YTct' or id == 'YTwt' or id == 'JTtw' or id == 'DTsh' or id == 'FTtw' or id == 'CTtr' or id == 'ITtw' or id == 'NTtw' or id == 'OTtw' or id == 'ZTtw' or id == 'WTst' or id == 'GTsh' or id == 'VTlt' or id == 'WTtw' or id == 'ATtc' or id == 'BTtc' or id == 'CTtc' or id == 'ITtc' or id == 'NTtc' or id == 'ZTtc'
endfunction


struct knock
    private unit u
    private real xvel
    private real yvel
    private real xvelred
    private real yvelred
    private real zred
    private real z
    private boolean killtrees
    private integer i
    private integer sfx
    
    private static method TreeKill takes nothing returns nothing
        local destructable d = GetEnumDestructable()
        if GetWidgetLife(d) > 0.405 then
            call KillDestructable(d)
        endif
        set d = null
    endmethod
    
    static method Move takes nothing returns nothing
        local knock k
        local integer i = 1
        local real x
        local real y
        local boolexpr b
        local rect r
        local location stupid
        if Total == 0 then
            debug call BJDebugMsg("Timer paused.")
            call PauseTimer(t)
            set paused = true
        endif
        loop
            exitwhen i > Total
            set k = Structs[i]
            if k.i != null and k.i != 0 then
                set x = GetUnitX(k.u) + k.xvel
                set y = GetUnitY(k.u) + k.yvel
                if canfly then
                    set stupid = Location(x, y)
                    set k.z = k.z - GetLocationZ(stupid)
                    call SetUnitFlyHeight(k.u, k.z, 0.)
                    set k.z = k.z - k.zred
                    if k.z > GetUnitDefaultFlyHeight(k.u) then
                        set k.zred = k.zred + (grav / (1./interval)) * 2.
                    else
                        set k.zred = 0.
                        call SetUnitFlyHeight(k.u, GetUnitDefaultFlyHeight(k.u), 500.)
                    endif
                    if k.z < 0. then
                        set k.z = 0.
                        set k.zred = 0.
                    endif
                    set k.z = k.z + GetLocationZ(stupid)
                    call RemoveLocation(stupid)
                    set stupid = null
                endif
                call SetUnitX(k.u, x)
                call SetUnitY(k.u, y)
                
                set k.sfx = k.sfx + 1
                if k.sfx == 1 and GetUnitFlyHeight(k.u) < 5. then
                    if IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) then
                        call DestroyEffect(AddSpecialEffect(gsfx, x, y))
                    else
                        call DestroyEffect(AddSpecialEffect(wsfx, x, y))
                    endif
                endif
                if k.sfx == 5 then
                    set k.sfx = 0
                endif
                
                if k.xvel * k.xvel + k.yvel * k.yvel < 2. then
                    if (GetUnitFlyHeight(k.u) - GetUnitDefaultFlyHeight(k.u)) * (GetUnitFlyHeight(k.u) - GetUnitDefaultFlyHeight(k.u)) < 5. then
                        set Structs[i] = Structs[Total]
                        set Total = Total - 1
                        set i = i - 1
                        set k.i = 0
                        call k.destroy()
                    endif
                else
                    set k.xvel = k.xvel - k.xvelred
                    set k.yvel = k.yvel - k.yvelred
                endif
                if k.killtrees then
                    set b = Condition(function TreeFilter)
                    set r = Rect(x - coll, y - coll, x + coll, y + coll)
                    call EnumDestructablesInRect(r, b, function knock.TreeKill)
                    call DestroyBoolExpr(b)
                    set b = null
                    call RemoveRect(r)
                    set r = null
                endif
                if x > MAX_X or x < MIN_X or y > MAX_Y or y < MIN_Y then
                    set Structs[i] = Structs[Total]
                    set Total = Total - 1
                    set i = i - 1
                    set k.i = 0
                    call SetUnitFlyHeight(k.u, GetUnitDefaultFlyHeight(k.u), 500.)
                    call k.destroy()
                endif
                set i = i + 1
            endif
        endloop
    endmethod
    
    static method Knockback takes unit u, real dist, real a, real tim, boolean killtrees returns nothing
        local knock k = knock.allocate()
        local location stupid = Location(GetUnitX(u), GetUnitY(u))
        set k.u = u
        set k.xvel = 2 * (dist * Cos(a)) / (tim/interval+1)
        set k.yvel = 2 * (dist * Sin(a)) / (tim/interval+1)
        set k.xvelred = k.xvel / (tim/interval)
        set k.yvelred = k.yvel / (tim/interval)
        set k.zred = 0.
        set k.z = GetUnitFlyHeight(u) + GetLocationZ(stupid)
        set k.killtrees = killtrees
        set k.i = 1
        set k.sfx = 0
        set Total = Total + 1
        set Structs[Total] = k
        if paused then
            debug call BJDebugMsg("Timer resumed.")
            call TimerStart(t, interval, true, function knock.Move)
            set paused = false
        endif
        call RemoveLocation(stupid)
        set stupid = null
        if canfly then
            call UnitAddAbility(u, 'Amrf')
            call UnitRemoveAbility(u, 'Amrf')
        endif
        debug call BJDebugMsg("Knockback started!")
    endmethod
    
    private method onDestroy takes nothing returns nothing
        set .u = null
        debug call BJDebugMsg("Knockback stopped!")
    endmethod
endstruct

private function Init takes nothing returns nothing
    local rect r = bj_mapInitialPlayableArea
    call TimerStart(t, interval, true, function knock.Move)
    set MAX_X = GetRectMaxX(r)
    set MAX_Y = GetRectMaxY(r)
    set MIN_X = GetRectMinX(r)
    set MIN_Y = GetRectMinY(r)
    set r = null
endfunction
endlibrary

JASS:
globals
    constant integer abil = 'A000'//The raw code of the spell.
    constant integer dummyid = '1234'//The raw code of the dummy.
    constant real mass = 20.//The mass of the footmen.
    constant real aoe = 600.//The radius of the spell.
    constant real aoeinc = 100.//The increment of radius each level.
    constant real dmg = 100.//The damage each footman will deal.
    constant real dmginc = 100.//The increment of damage each level.
    constant integer waves = 4//The number of waves.
    constant integer waveinc = 1//The increment of waves each level.
    constant real wavelenght = 1.5//The wait between each wave.
    constant real height = 600.//The height the footmen will fall from.
    constant boolean stun = true//Is stun enabled?
    constant real stundur = 0.5//How many seconds should the units be stunned.
    constant real stundurinc = 0.//The increment of stun duration each level.
    constant boolean homing = true//Is homing enabled?
    constant boolean channeling = true//Is the spell channeling?
    
    constant boolean knock = true//Should knockback be enabled?
    constant boolean killtrees = true//Should trees be destroyed if hit by knockbacked units?
    constant real coll = 120.//The radius around the unit that may be knockbacked.
    constant real knockd = 150.//The distance units will be knockbacked.
    constant real time = 1.//How many seconds it will take to get knockbacked that distance.
    
//=====================================
    constant real grav = 9.81//The force of gravity.
    constant real interval = 0.04//The interval of the timer.
endglobals

//======================================================================================
//================DON'T TOUCH BELOW UNLESS YOU KNOW WHAT YOU'RE DOING!!!================
//======================================================================================

struct un
    unit u
    real i
    real i2
endstruct

function RemoveUnitTimed_child takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local un r = GetAttachedStruct(t, "rut")
    call RemoveUnit(r.u)
    set r.u = null
    call r.destroy()
    call DestroyTimer(t)
    set t = null
endfunction

function RemoveUnitTimed takes unit u, real time returns nothing
    local un r = un.create()
    local timer t = CreateTimer()
    set r.u = u
    call AttachStruct(t, r, "rut")
    call TimerStart(t, time, false, function RemoveUnitTimed_child)
    set t = null
endfunction

function FadeInUnit_child takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local un r = GetAttachedStruct(t, "fiu")
    set r.i = r.i + r.i2
    call SetUnitVertexColor(r.u, 255, 255, 255, R2I(r.i))
    if r.i >= 255. then
        call PauseTimer(t)
        call DestroyTimer(t)
        set t = null
        set r.u = null
        call r.destroy()
    endif
    set t = null
endfunction

function FadeInUnit takes unit u, real time returns nothing
    local un r = un.create()
    local timer t = CreateTimer()
    set r.u = u
    set r.i = 0.
    set r.i2 = 255. / (time/0.04)
    call AttachStruct(t, r, "fiu")
    call SetUnitVertexColor(u, 255, 255, 255, 0)
    call TimerStart(t, 0.04, true, function FadeInUnit_child)
    set t = null
endfunction

globals
    constant integer stunnerid = 'h002'
    unit array uni
endglobals

function Stun_child takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local un r = GetAttachedStruct(t, "s")
    call AttachStruct(r.u, 0, "ss")
    call UnitRemoveAbility(r.u, 'BPSE')
    set r.u = null
    call r.destroy()
    call DestroyTimer(t)
    set t = null
endfunction

function Stun takes unit u, real dur returns nothing
    local un r = un.create()
    local timer t = CreateTimer()
    local integer i = GetAttachedStruct(u, "ss")
    local integer n = 0
    if i == 1 then
        call DestroyTimer(t)
        call r.destroy()
    else
        set r.u = u
        loop
            exitwhen OrderId2String(GetUnitCurrentOrder(uni[n])) != "thunderbolt"
            exitwhen n == 91
            set n = n + 1
        endloop
        if n == 91 then
            call BJDebugMsg("\n\n\nERROR:\n Code: 375939\n Please send this error report to The_Reborn_Devil\n:)\n\n\n\n")//Hehehe
//==========I have an urge to screw with people ^^
            call DestroyTimer(t)
            set t = null
            call r.destroy()
            return
        endif
        call SetUnitX(uni[n], GetUnitX(u))
        call SetUnitY(uni[n], GetUnitY(u))
        call IssueTargetOrder(uni[n], "thunderbolt", u)
        call AttachStruct(t, r, "s")
        call AttachStruct(u, 1, "ss")
        call TimerStart(t, dur, false, function Stun_child)
    endif
    set t = null
endfunction

globals
    integer array structs
endglobals

struct man
    unit u
    unit u2
    real xvel
    real yvel
    real zvel
    real dmg
    real stundur
    
    integer i
    
    static integer n
    static timer t
    
    method move takes nothing returns nothing
        local real x1 = GetUnitX(.u)
        local real y1 = GetUnitY(.u)
        local real z1 = GetUnitFlyHeight(.u)
        local real x2 = GetUnitX(.u2)
        local real y2 = GetUnitY(.u2)
        local real z2 = GetUnitFlyHeight(.u2)
        local group g
        local unit u
        local player p = GetOwningPlayer(.u)
        set .zvel = .zvel + (mass * grav) / ((.zvel+1) * 10.)
        call SetUnitFlyHeight(.u, z1 - .zvel, 0.)
        if homing then
            set .xvel = .xvel + (x2 - x1) / ((z1 - z2) / .zvel)
            set .yvel = .yvel + (y2 - y1) / ((z1 - z2) / .zvel)
            call SetUnitPosition(.u, x1 + .xvel, y1 + .yvel)
            set .xvel = .xvel / 1.5
            set .yvel = .yvel / 1.5
        endif
        if z1 - z2 < 30. then
            if .stundur > 0. then
                call Stun(.u2, .stundur)
            endif
            call UnitDamageTarget(.u, .u2, .dmg, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, null)
            if knock then
                set g = CreateGroup()
                call GroupEnumUnitsInRange(g, x2, y2, coll, null)
                loop
                    set u = FirstOfGroup(g)
                    exitwhen u == null
                    if GetWidgetLife(u) > 0.405 and IsUnitEnemy(u, p) and u != .u2 then
                        call knock.Knockback(u, knockd, Atan2(GetUnitY(u) - y2, GetUnitX(u) - x2), time, killtrees)
                    endif
                    call GroupRemoveUnit(g, u)
                    set u = null
                endloop
                call DestroyGroup(g)
                set g = null
            endif
            call .destroy()
        endif
        set p = null
    endmethod
    
    static method create takes player p, unit target, real z, real damg, real stundur returns man
        local man m = man.allocate()
        local real x = GetUnitX(target)
        local real y = GetUnitY(target)
        local location stupid = Location(x, y)
        set m.u = CreateUnit(p, dummyid, x, y, 0.)
        set m.u2 = target
        set m.xvel = 0.
        set m.yvel = 0.
        set m.zvel = 0.
        set m.dmg = damg
        set m.stundur = stundur
        set man.n = man.n + 1
        set structs[man.n] = m
        set m.i = man.n
        call FadeInUnit(m.u, 0.6)
        call UnitAddAbility(m.u, 'Amrf')
        call UnitRemoveAbility(m.u, 'Amrf')
        call SetUnitPathing(m.u, false)
        call SetUnitFlyHeight(m.u, z - GetLocationZ(stupid), 0.)
        call RemoveLocation(stupid)
        set stupid = null
        return m
    endmethod
    
    static method Loop takes nothing returns nothing
        local man m
        local integer i = 0
        loop
            exitwhen i > man.n
            set m = structs[i]
            if m.i != null then
                call m.move()
            endif
            set i = i + 1
        endloop
    endmethod
    
    method onDestroy takes nothing returns nothing
        local man m
        call KillUnit(.u)
        call RemoveUnitTimed(.u, 3.)
        set .u = null
        set .u2 = null
        set structs[.i] = structs[man.n]
        set m = structs[.i]
        set m.i = .i
        set man.n = man.n - 1
    endmethod
endstruct

struct fallofmen
    unit u
    real x
    real y
    real z
    real aoe
    real dmg
    real stundur
    integer waves
    timer t
    boolean first
    trigger tr
    
    static method wave takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local fallofmen fom = GetAttachedStruct(t, "w")
        local player p = GetOwningPlayer(fom.u)
        local group g = CreateGroup()
        local unit u
        if fom.first then
            call TimerStart(fom.t, wavelenght, true, function fallofmen.wave)
        endif
        call GroupEnumUnitsInRange(g, fom.x, fom.y, fom.aoe, null)
        loop
            set u = FirstOfGroup(g)
            exitwhen u == null
            if GetWidgetLife(u) > 0.405 and IsUnitEnemy(u, p) then
                call man.create(p, u, fom.z, fom.dmg, fom.stundur)
            endif
            call GroupRemoveUnit(g, u)
            set u = null
        endloop
        call DestroyGroup(g)
        set g = null
        set fom.waves = fom.waves - 1
        if fom.waves == 0 then
            call fom.destroy()
        endif
        set t = null
        set p = null
    endmethod
    
    static method stop takes nothing returns nothing
        local trigger t = GetTriggeringTrigger()
        local fallofmen fom = GetAttachedStruct(t, "stop")
        call fom.destroy()
        set t = null
    endmethod
    
    static method create takes unit u returns fallofmen
        local fallofmen fom = fallofmen.allocate()
        local player p = GetOwningPlayer(u)
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local location stupid = Location(x, y)
        local real z = GetLocationZ(stupid)
        local integer lvl = GetUnitAbilityLevel(u, abil)
        call RemoveLocation(stupid)
        set fom.u = u
        set fom.x = x
        set fom.y = y
        set fom.z = z + height
        set fom.aoe = aoe + (aoeinc * (lvl - 1))
        set fom.dmg = dmg + (dmginc * (lvl - 1))
        set fom.stundur = stundur + (stundurinc * (lvl - 1))
        set fom.waves = waves + (waveinc * (lvl - 1))
        set fom.t = CreateTimer()
        set fom.first = true
        if channeling then
            set fom.tr = CreateTrigger()
            call TriggerRegisterUnitEvent(fom.tr, u, EVENT_UNIT_ISSUED_ORDER)
            call TriggerRegisterUnitEvent(fom.tr, u, EVENT_UNIT_ISSUED_TARGET_ORDER)
            call TriggerRegisterUnitEvent(fom.tr, u, EVENT_UNIT_ISSUED_POINT_ORDER)
            call TriggerAddAction(fom.tr, function fallofmen.stop)
            call AttachStruct(fom.tr, fom, "stop")
        endif
        call AttachStruct(fom.t, fom, "w")
        call TimerStart(fom.t, 0., false, function fallofmen.wave)
        return fom
    endmethod
    
    method onDestroy takes nothing returns nothing
        call PauseTimer(.t)
        call DestroyTimer(.t)
        set .u = null
        set .t = null
        if channeling then
            call DestroyTrigger(.tr)
            set .tr = null
        endif
    endmethod
endstruct

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

function Cast takes nothing returns nothing
    local unit u = GetSpellAbilityUnit()
    call fallofmen.create(u)
    set u = null
endfunction

function InitTrig_Fall_of_Men takes nothing returns nothing
    local trigger t = CreateTrigger()
    local player p
    local integer i = 0
    set man.n = 0
    set man.t = CreateTimer()
    call TimerStart(man.t, interval, true, function man.Loop)
    call RemoveUnit(CreateUnit(Player(12), dummyid, 0., 0., 0.))
    loop
        exitwhen i > 90
        set uni[i] = CreateUnit(Player(12), stunnerid, 0., 0., 0.)
        set i = i + 1
    endloop
    set i = 0
    loop
        exitwhen i == bj_MAX_PLAYER_SLOTS
        set p = Player(i)
        call TriggerRegisterPlayerUnitEvent(t, p, EVENT_PLAYER_UNIT_SPELL_CAST, null)
        set p = null
        set i = i + 1
    endloop
    call TriggerAddCondition(t, Condition(function Conditions))
    call TriggerAddAction(t, function Cast)
    set t = null
endfunction


Edit: Code added.

Edit: Solved!
 
Last edited:
Status
Not open for further replies.
Top