HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Buggy Stuff

02-24-2009, 09:52 AM#1
fX_
This supposed to do this:
When a unit with an ability damages an enemy by attack, for each unit within X range of the stricken unit will be generated a dummy that will attack collateral unit for Y duration or until the collateral unit or generating unit dies.

UPDATE:
This is what happens, more precisely:
1) Dummies do not get removed most of the time, generally.

* by BJDebugMsg(), I have found out that the Fire instances' duration meters get reset whenever they expire...

2) Dummies are able to propagate themselves (FIRE_CAN_PROPAGATE = true) on their own targets (even when FIRE_CAN_STACK = false). This has something to do with the above problem, I think; dummies continue to propagate themselves but they are themselves no longer registered as dummies so there will be no stacking impediments.

What's wrong?

Collapse JASS:
library Wildfire initializer Init requires DamageEvent

//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//
//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//
//  -- Configuration --

    globals
        constant integer WILDFIRE_ABILITY_ID = 'A000'
        private constant integer FIRE_UNIT_ID = 'O002'
        private constant boolean FIRE_CAN_STACK = false
        private constant boolean FIRE_CAN_PROPAGATE = true
        private constant real FIRE_LIGHT_DISTANCE = 200.00
        private constant real FIRE_MONITOR_INTERVAL_DURATION = 0.05
    endglobals

    private constant function GetProcPercentChance takes integer level returns integer
        return 100//level * 10
    endfunction

    private constant function GetSpreadAreaRadius takes integer level returns real
        return 200.00 + level * 100.00
    endfunction

    private constant function GetFireDuration takes integer level returns real
        return 4.00 + level * 2.00
    endfunction

//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//
//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//
//  -- Script Operation Functions --

    globals
        private group gUG = CreateGroup()
        private player gP = null
    endglobals

    private function IsAbility takes nothing returns boolean
        return IsEventDamageAttack() and GetUnitAbilityLevel(GetDamagingUnit(), WILDFIRE_ABILITY_ID) > 0 and IsUnitEnemy(GetDamagedUnit(), GetOwningPlayer(GetDamagingUnit())) and GetRandomInt(1, 100) <= GetProcPercentChance(GetUnitAbilityLevel(GetDamagingUnit(), WILDFIRE_ABILITY_ID))
    endfunction

    private keyword Fire

    private function ValidateTarget takes nothing returns boolean
        local boolean BOOL = GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) > 0.00 and IsUnitType(GetFilterUnit(), UNIT_TYPE_GROUND) and IsUnitEnemy(GetFilterUnit(), gP)

        if FIRE_CAN_STACK == false then
            set BOOL = BOOL and Fire.IsUnitOnFire(GetFilterUnit()) == false
        endif

        return BOOL
    endfunction

    private struct Fire[8191]

        private unit u
        private unit uFire
        private unit uTarget
        private real rDuration
        private boolean boolLit = false

        public static method Create takes unit u, player owner, real x, real y, real facing, integer heroLevel, unit target, integer level, real duration returns nothing
            if Fire.intCountInst < 8191 then
                set Fire.Inst[Fire.intCountInst] = Fire.allocate()
                set Fire.Inst[Fire.intCountInst].u = u
                set Fire.Inst[Fire.intCountInst].uFire = CreateUnit(owner, FIRE_UNIT_ID, x, y, facing)
                call SetHeroLevel(Fire.Inst[Fire.intCountInst].uFire, heroLevel, false)
                if FIRE_CAN_PROPAGATE then
                    call UnitAddAbility(Fire.Inst[Fire.intCountInst].uFire, WILDFIRE_ABILITY_ID)
                    call SetUnitAbilityLevel(Fire.Inst[Fire.intCountInst].uFire, WILDFIRE_ABILITY_ID, level)
                endif
                set Fire.Inst[Fire.intCountInst].uTarget = target
                set Fire.Inst[Fire.intCountInst].rDuration = duration

                set Fire.Inst[Fire.intCountInst].intInstIndex = Fire.intCountInst
                set Fire.intCountInst = Fire.intCountInst + 1
                call Fire.ManageTimer(true)

                call IssueTargetOrder(Fire.Inst[Fire.intCountInst - 1].uFire, "attack", target)
            endif
        endmethod

        private method Destroy takes nothing returns nothing
            call RemoveUnit(.uFire)

            set Fire.intCountInst = Fire.intCountInst - 1
            set Fire.Inst[Fire.intCountInst].intInstIndex = .intInstIndex
            set this = 0
            set Fire.Inst[.intInstIndex] = Fire.Inst[Fire.intCountInst]
            set Fire.Inst[Fire.intCountInst] = 0
            call Fire.ManageTimer(false)
        endmethod

        private integer intInstIndex
        private static Fire array Inst[8191]
        private static integer intCountInst = 0

        private static method MonitorAll takes nothing returns nothing
            local integer INT_Index = 0
            local boolean BOOL_InFireLightRange
            local real R_Angle

            loop
                exitwhen INT_Index == Fire.intCountInst
                if GetUnitState(Fire.Inst[INT_Index].u, UNIT_STATE_LIFE) > 0.00 and GetUnitState(Fire.Inst[INT_Index].uTarget, UNIT_STATE_LIFE) > 1.00 then
                    set Fire.Inst[INT_Index].rDuration = Fire.Inst[INT_Index].rDuration - FIRE_MONITOR_INTERVAL_DURATION
                    if Fire.Inst[INT_Index].rDuration > 0.00 then
                        set BOOL_InFireLightRange = IsUnitInRange(Fire.Inst[INT_Index].uFire, Fire.Inst[INT_Index].uTarget, FIRE_LIGHT_DISTANCE)
                        if Fire.Inst[INT_Index].boolLit == false and BOOL_InFireLightRange then
                            set Fire.Inst[INT_Index].boolLit = true
                        endif
                        if Fire.Inst[INT_Index].boolLit and BOOL_InFireLightRange == false then
                            set R_Angle = Atan2(GetUnitY(Fire.Inst[INT_Index].uFire) - GetUnitY(Fire.Inst[INT_Index].uTarget), GetUnitX(Fire.Inst[INT_Index].uFire) - GetUnitX(Fire.Inst[INT_Index].uTarget))
                            call SetUnitX(Fire.Inst[INT_Index].uFire, GetUnitX(Fire.Inst[INT_Index].uTarget) + FIRE_LIGHT_DISTANCE * Cos(R_Angle))
                            call SetUnitY(Fire.Inst[INT_Index].uFire, GetUnitY(Fire.Inst[INT_Index].uTarget) + FIRE_LIGHT_DISTANCE * Sin(R_Angle))
                            call SetUnitFacing(Fire.Inst[INT_Index].uFire, (R_Angle * bj_RADTODEG) + 180.00)
                        endif
                        call IssueTargetOrder(Fire.Inst[INT_Index].uFire, "attack", Fire.Inst[INT_Index].uTarget)
                    else
                        call Fire.Inst[INT_Index].Destroy()
                        set INT_Index = INT_Index - 1
                    endif
                else
                    call Fire.Inst[INT_Index].Destroy()
                    set INT_Index = INT_Index - 1
                endif
                set INT_Index = INT_Index + 1
            endloop
        endmethod

        private static timer tim = CreateTimer()

        private static method ManageTimer takes boolean add returns nothing
            if Fire.intCountInst == 0 then
                call PauseTimer(Fire.tim)
            elseif add and Fire.intCountInst == 1 then
                call TimerStart(Fire.tim, FIRE_MONITOR_INTERVAL_DURATION, true, function Fire.MonitorAll)
            endif
        endmethod

        public static method IsUnitOnFire takes unit target returns boolean
            local integer INT_Index = 0

            loop
                exitwhen INT_Index == Fire.intCountInst
                if Fire.Inst[INT_Index].uTarget == target then
                    return true
                endif
                set INT_Index = INT_Index + 1
            endloop

            return false
        endmethod

    endstruct

    private function ApplyAbility takes nothing returns nothing
        local unit U = GetDamagingUnit()
        local integer INT_HeroLevel = GetHeroLevel(U)
        local integer INT_Level = GetUnitAbilityLevel(U, WILDFIRE_ABILITY_ID)
        local unit U_Target = GetTriggerUnit()
        local real R_XTarget = GetUnitX(U_Target)
        local real R_YTarget = GetUnitY(U_Target)
        local real R_Duration = GetFireDuration(INT_Level)
        set gP = GetOwningPlayer(U)

        call GroupEnumUnitsInRange(gUG, R_XTarget, R_YTarget, GetSpreadAreaRadius(INT_Level), Filter(function ValidateTarget))
        loop
            set U_Target = FirstOfGroup(gUG)
            exitwhen U_Target == null
            call Fire.Create(U, gP, R_XTarget, R_YTarget, bj_RADTODEG * Atan2(GetUnitY(U_Target) - R_YTarget, GetUnitX(U_Target) - R_XTarget), INT_HeroLevel, U_Target, INT_Level, R_Duration)
            call GroupRemoveUnit(gUG, U_Target)
        endloop

        set U = null
        set gP = null
        set U_Target = null
        call GroupClear(gUG)
    endfunction

    private function Init takes nothing returns nothing
        local trigger TRIG = CreateTrigger()

        call TriggerRegisterDamageEvent(TRIG)
        call TriggerAddCondition(TRIG, Condition(function IsAbility))
        call TriggerAddAction(TRIG, function ApplyAbility)

        set TRIG = null
    endfunction

endlibrary
03-01-2009, 10:15 AM#2
fX_
bump
03-02-2009, 10:33 AM#3
fX_
nobody?
03-02-2009, 10:42 AM#4
Anachron
Collapse JASS:
    
private struct Fire[8191]
Why are you doing that? (Sorry, I am new to structs)