HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Interface condition working weird

05-16-2009, 01:02 PM#1
wraithseeker
Collapse JASS:
    if .chain == 1 or .chain == 2 then
            set .data = this
            call GroupClear(ENUM_GROUP)
            call GroupEnumUnitsInRange(ENUM_GROUP,x,y,CHAINRADIUS,ChainFilter)
            loop
                set t = FirstOfGroup(ENUM_GROUP)
                exitwhen t == null
                    if not IsUnitInGroup(t,.hit) then
                        set cx = GetUnitX(t)
                        set cy = GetUnitY(t)
                        call GroupAddUnit(.hit,t)
                        set d = Knock.create(.source,t,Atan2(cy-y,cx-x),(.speed/TIME)*SPEEDFACTOR,(.decrement/TIME))
                        call GroupAddUnit(d.hit,.target)
                        if .OnChain.exists then
                            call .OnChain.execute()
                        endif
                        set .D[.Count] = d
                        set .Count = .Count + 1                      
                    endif
                call GroupRemoveUnit(ENUM_GROUP,t)
            endloop

This works fine, but when changed to

Collapse JASS:
  if .chain == 1 or .chain == 2 then
            set .data = this
            call GroupClear(ENUM_GROUP)
            call GroupEnumUnitsInRange(ENUM_GROUP,x,y,CHAINRADIUS,ChainFilter)
            loop
                set t = FirstOfGroup(ENUM_GROUP)
                exitwhen t == null
                    if not IsUnitInGroup(t,.hit) then
                        if .OnChainCondition.exists then
                            if .OnChainCondition() then
                                set cx = GetUnitX(t)
                                set cy = GetUnitY(t)
                                call GroupAddUnit(.hit,t)
                                set d = Knock.create(.source,t,Atan2(cy-y,cx-x),(.speed/TIME)*SPEEDFACTOR,(.decrement/TIME))
                                call GroupAddUnit(d.hit,.target)
                                if .OnChain.exists then
                                    call .OnChain.execute()
                                endif
                                set .D[.Count] = d
                                set .Count = .Count + 1       
                                endif
                            endif
                    endif
                    
                call GroupRemoveUnit(ENUM_GROUP,t)
            endloop

Fails big time.

Now how do I make it work with a interface condition?
05-16-2009, 01:10 PM#2
Vexorian
what interface condition?
post the interface?
05-16-2009, 01:14 PM#3
wraithseeker
Collapse JASS:
private interface face
    method OnPeriodic takes nothing returns nothing defaults nothing
    method OnStop takes nothing returns nothing defaults nothing
    method OnStopCondition takes nothing returns boolean defaults false
    method OnChain takes nothing returns nothing defaults nothing
    method OnChainCondition takes nothing returns boolean defaults false
endinterface

OnChainCondition.
05-16-2009, 01:16 PM#4
Vexorian
post the struct that implements the interface as well?
Define "fails big time" ?
05-16-2009, 01:21 PM#5
wraithseeker
Quote:
Originally Posted by Vexorian
post the struct that implements the interface as well?
Define "fails big time" ?

Collapse JASS:
library Knockback initializer Init requires DestructableLib, IsTerrainWalkable, GroupUtils, AutoIndex

globals
    private constant real    TIME         = 0.03                     // The timer interval.
    private constant real    CHAINRADIUS  = 160.00                   // The radius a unit can get chained when near the unit target.
    private constant real    SPEEDFACTOR  = 0.75                     // How much speed will be reduced when a unit chains another unit.
    private constant real    RADIUS       = 128.00                   // The radius to check tree.
    private constant real    HEIGHTLEVEL  = 200.00                   // The default height level that stops chaining or killing trees when in the air.
    private constant string  GROUND       = "MDX\\Dust.mdx"          // The effect for ground.
    private constant string  WATER        = "MDX\\SlideWater.mdx"    // The effect for water.
    private constant string  COLLISION    = "MDX\\DustAndRocks.mdx"  // The effect when at cliff
endglobals

globals
    private constant integer INVULNERABLE   = 'Avul'               
    private constant integer FLYID          = 'Amrf' 
    private rect     TreeRect               = null
    private boolexpr TreeCheck              = null
    private boolexpr ChainFilter            = null
    private boolexpr LineFilter             = null
    private real MapMaxX                    = 0
    private real MapMaxY                    = 0
    private real MapMinX                    = 0
    private real MapMinY                    = 0
endglobals

private interface face
    method OnPeriodic takes nothing returns nothing defaults nothing
    method OnStop takes nothing returns nothing defaults nothing
    method OnStopCondition takes nothing returns boolean defaults false
    method OnChain takes nothing returns nothing defaults nothing
    method OnChainCondition takes nothing returns boolean defaults false
endinterface
    

struct Knock extends face
    private static timer Timer    = CreateTimer()
    private static integer Count  = 0
    private static Knock array D
    private static Knock data
    private static integer array Entries
    private     integer      mode            = 0
    private     group        hit             = null
    private     group        linehit         = null
    private     real         VariableSpeed   = 0
    private     effect      effects          = null
    unit        source          = null
    unit        target          = null
    unit        dashtarget      = null
    integer     Mode            = 0
    real        cos             = 0
    real        sin             = 0 
    real        speed           = 0
    real        decrement       = 0
    real        distance        = 0
    real        Increment       = 0
    real        LineDamage      = 0
    real        z               = 0
    real        ElevationAngle  = 0.
    real        h               = 0.
    real        GRAVITY         = -981.
    real        vf              = 0.
    string      SFX             = ""
    string      attachpoint     = "origin"
    location    TargetPoint     = null
    boolean     trees           = false
    integer     chain           = 0
    boolean     fly             = false
    boolean     ToTarget        = false
    boolean     Move            = false
    
static method KnockbackStop takes unit target returns boolean
    local Knock this
    local integer id = GetUnitId(target)
    local integer i = .Count - 1
    if .Entries[id] != 0 then
        if .Count > 0 then
            set .D[i]= .D[.Count]
        else 
            call PauseTimer(.Timer) 
        endif
        set .Entries[id] = .Entries[id] - 1
        call .destroy()
        return true
    endif
    return false
endmethod

static method IsKnockedBack takes unit target returns boolean
    local Knock this
    local integer id = GetUnitId(target)
    return .Entries[id] != 0
endmethod
   
private static method CheckTrees takes nothing returns boolean
    return IsDestructableTree(GetFilterDestructable())
endmethod

private static method Trees takes nothing returns nothing
    call KillDestructable(GetEnumDestructable())
endmethod

private static method ChainCheck takes nothing returns boolean
    local Knock this = .data
    return .target != GetFilterUnit() and IsUnitEnemy(GetFilterUnit(),GetOwningPlayer(.source)) and IsUnitType(GetFilterUnit(), UNIT_TYPE_GROUND) == true and IsUnitType(GetFilterUnit(), UNIT_TYPE_MECHANICAL) == false and GetWidgetLife(GetFilterUnit()) > 0.405 and GetUnitAbilityLevel(GetFilterUnit(),INVULNERABLE) <= 0
endmethod

private static method LineCheck takes nothing returns boolean
    local Knock this = .data
    return GetWidgetLife(GetFilterUnit()) > 0.405 and IsUnitEnemy(GetFilterUnit(),GetOwningPlayer(.source)) and GetFilterUnit() != .source
endmethod

private method IsPointOutside takes real x, real y returns nothing
    local real tx = GetUnitX(.target) + 50 * .cos
    local real ty = GetUnitY(.target) + 50 * .sin
    if (x > MapMaxX or y > MapMaxY or x < MapMinX or y < MapMinY) or (tx > MapMaxX or ty > MapMaxY or tx < MapMinX or ty < MapMinY) then
        set .cos = -.cos
        set .sin = -.sin
    endif
endmethod
    
private method TerrainCheck takes nothing returns integer
    local real x = GetUnitX(.target)
    local real y = GetUnitY(.target)
    local real height = GetUnitFlyHeight(.target)
    if IsTerrainWalkable(x + 50.00 * .cos,y + 50.00 * .sin) == false then
        return 3
   elseif IsTerrainPathable(x,y,PATHING_TYPE_FLOATABILITY) then
        return 1
    elseif not IsTerrainPathable(x,y,PATHING_TYPE_WALKABILITY) then
        return 2
    endif 
    return 0
endmethod

method operator ElevationA takes nothing returns real
    return .ElevationAngle
endmethod

method operator ElevationA= takes real a returns nothing
    local real speed = .speed/0.03
    set .ElevationAngle = a
    set .z = speed * Sin(.ElevationAngle*bj_DEGTORAD)
endmethod
            
static method create takes unit source, unit target, real angle, real speed, real decrement returns Knock
    local Knock d = Knock.allocate()
    local integer i = GetUnitId(target)
    if target == null or source == null or speed == 0.00 or decrement == 0.00 then
        call BJDebugMsg("|cffffInvalid values for Knockback.!")
        call d.destroy()
    endif
    set d.source        = source
    set d.target        = target
    set d.trees         = false
    set d.fly           = false
    set d.chain         = 0
    set d.ToTarget      = false
    set d.Move          = false
    set d.hit           = NewGroup()
    set d.linehit       = NewGroup()
    set d.speed         = speed * TIME
    set d.decrement     = decrement * TIME
    set d.sin           = Sin(angle)
    set d.cos           = Cos(angle)
    set d.distance      = -1 * speed * speed / (2 * -decrement / TIME)
    set d.LineDamage    = 0
    set d.Mode          = 0
    set d.VariableSpeed = 0
    set d.Increment     = 0
    set d.dashtarget    = null
    set d.TargetPoint   = null
    set d.VariableSpeed = speed
    set d.SFX           = ""
    set d.attachpoint   = "origin"
    set d.mode = d.TerrainCheck()
    set d.GRAVITY = -981.
    set d.z = 0.
    set d.vf = 0.
    set d.h = 0.
    if d.mode == 1 then
        set d.effects = AddSpecialEffectTarget(GROUND,d.target,d.attachpoint)
    elseif d.mode == 2 then
        set d.effects = AddSpecialEffectTarget(WATER,d.target,d.attachpoint)
    elseif d.mode == 3 then
        set d.effects = AddSpecialEffectTarget(COLLISION,d.target,d.attachpoint)
    endif
    set .D[.Count] = d
       if .Count == 0 then
        call TimerStart(.Timer,TIME,true,function Knock.action)
    endif
    set .Count = .Count + 1
    set .Entries[i] = .Entries[i] + 1
    return d
endmethod
    
static method get takes unit u returns integer
    local integer id = GetUnitId(u)
    return .Entries[id]
endmethod

private method onDestroy takes nothing returns nothing
    call DestroyEffect(.effects)
    call ReleaseGroup(.hit)
    call ReleaseGroup(.linehit)
    call SetUnitFlyHeight(.target,GetUnitDefaultFlyHeight(.target),0)
    call SetUnitPathing(.target,true)
endmethod
        
private static method action takes nothing returns nothing
    local Knock d       = 0
    local Knock this    = 0
    local real    x     = 0.
    local real    y     = 0.
    local real    cx    = 0.
    local real    cy    = 0.
    local real    tx    = 0.
    local real    ty    = 0.
    local integer id    = 0
    local integer mode  = 0
    local real height   = 0.00
    local real angle    = 0.00
    local integer i     = 0
    local unit t        = null
    loop
        exitwhen i >= .Count
        set this = .D[i]
        set id = GetUnitId(.target)
        set x = GetUnitX(.target)
        set y = GetUnitY(.target)
        set height = GetUnitFlyHeight(.target)
        set mode = .mode
        set .vf = .z + .GRAVITY * TIME
        set .h = .h + (.vf*.vf-.z*.z) / (2 * .GRAVITY)
        set .z = .vf
        if .OnPeriodic.exists then
            call .OnPeriodic.execute()
        endif
        
        if .ToTarget and .TargetPoint == null then
            set cx = GetUnitX(.dashtarget)
            set cy = GetUnitY(.dashtarget)
            set x = GetUnitX(.target)
            set y = GetUnitY(.target)
            set angle = Atan2(cy-y,cx-x)
            set .sin = Sin(angle)
            set .cos = Cos(angle)
            if SquareRoot((cx - x) * (cx - x) + (cy - y) * (cy - y)) <= 125 then
                if .OnStop.exists then
                    call .OnStop.execute()
                endif
                call .destroy()
                set .Count = .Count - 1
                set .Entries[id] = .Entries[id] - 1
                if .Count > 0 then
                    set .D[i]= .D[.Count]
                set i = i - 1 
            else 
                call PauseTimer(.Timer) 
            endif
        endif
        elseif .OnStopCondition.exists and .TargetPoint == null and not .ToTarget then
            if .OnStopCondition() then
                if .OnStop.exists then
                    call .OnStop.execute()
                endif
                call .destroy()
                set .Count = .Count - 1
                set .Entries[id] = .Entries[id] - 1
                if .Count > 0 then
                    set .D[i]= .D[.Count]
                    set i = i - 1 
                else 
                    call PauseTimer(.Timer) 
                endif
            endif
        elseif .speed <= 0 and .TargetPoint == null and not .ToTarget and not .OnStopCondition.exists then
            if .OnStop.exists then
                call .OnStop.execute()
            endif
            call .destroy()
            set .Count = .Count - 1
            set .Entries[id] = .Entries[id] - 1
            if .Count > 0 then
                set .D[i]= .D[.Count]
                set i = i - 1 
            else 
                call PauseTimer(.Timer) 
            endif
        else
        
        call .IsPointOutside(x,y)
        if height >= HEIGHTLEVEL then
            set .chain = 0
            set .trees = false
        endif
    
        if .Mode == 0 then
            set x = x + .speed * .cos
            set y = y + .speed * .sin
        elseif .Mode == 1 then
            set x = x + .speed * .cos
            set y = y + .speed * .sin
        elseif .Mode == 2 then
            set x = x + .VariableSpeed *.cos
            set y = y + .VariableSpeed *.sin
            set .VariableSpeed = .VariableSpeed + .Increment
        endif
    
        if .Move then
            call SetUnitX(.target,x)
            call SetUnitY(.target,y)
        else
            call SetUnitPosition(.target,x,y)
        endif
     
        if .LineDamage > 0 then
            set .data = this
            call GroupClear(ENUM_GROUP)
            call GroupEnumUnitsInRange(ENUM_GROUP,x,y,100,LineFilter)
            loop
                set t = FirstOfGroup(ENUM_GROUP)
                exitwhen t == null
                if not IsUnitInGroup(t,.linehit) then
                    call UnitDamageTarget(.source,t,.LineDamage,false,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,null)
                    call GroupAddUnit(.linehit,t)
                endif
                call GroupRemoveUnit(ENUM_GROUP,t)
            endloop
        endif
     
        if .trees then
            call SetRect(TreeRect,x-RADIUS,y-RADIUS,x+RADIUS,y+RADIUS)
            call EnumDestructablesInRect(TreeRect,TreeCheck,function Knock.Trees)
        endif
    
        set height = GetUnitFlyHeight(.target)   
        if .fly  then
            call UnitAddAbility(.target,FLYID)
            call UnitRemoveAbility(.target,FLYID)
            call SetUnitPathing(.target,false)
            call SetUnitFlyHeight(.target,.h,0)
        endif

        set height = GetUnitFlyHeight(.target)   

    if .SFX == "" and height >= GetUnitDefaultFlyHeight(.target) and height <= GetUnitDefaultFlyHeight(.target) +1 then
            set .mode = .TerrainCheck()
            if .mode == 1 and (mode == 2 or mode == 3)then
                call DestroyEffect(.effects)
                set .effects = AddSpecialEffectTarget(GROUND,.target,.attachpoint)
            elseif .mode == 2 and (mode == 1 or mode == 3) then
                call DestroyEffect(.effects)
                set .effects = AddSpecialEffectTarget(WATER,.target,.attachpoint)
            elseif .mode == 3 and (mode == 1 or mode == 2) then
                call DestroyEffect(.effects)
                set .effects = AddSpecialEffectTarget(COLLISION,.target,.attachpoint)
            endif
        else
            call DestroyEffect(.effects)
            set .effects = AddSpecialEffectTarget(.SFX,.target,.attachpoint)
        endif

        if .chain == 1 or .chain == 2 then
            set .data = this
            call GroupClear(ENUM_GROUP)
            call GroupEnumUnitsInRange(ENUM_GROUP,x,y,CHAINRADIUS,ChainFilter)
            loop
                set t = FirstOfGroup(ENUM_GROUP)
                exitwhen t == null
                    if not IsUnitInGroup(t,.hit) then
                        if .OnChainCondition.exists then
                            if .OnChainCondition() then
                                set cx = GetUnitX(t)
                                set cy = GetUnitY(t)
                                call GroupAddUnit(.hit,t)
                                set d = Knock.create(.source,t,Atan2(cy-y,cx-x),(.speed/TIME)*SPEEDFACTOR,(.decrement/TIME))
                                call GroupAddUnit(d.hit,.target)
                                if .OnChain.exists then
                                    call .OnChain.execute()
                                endif
                                set .D[.Count] = d
                                set .Count = .Count + 1       
                                endif
                            endif
                    endif
                    
                call GroupRemoveUnit(ENUM_GROUP,t)
            endloop
    endif
    endif
    set .speed = .speed - .decrement

        set i = i + 1
    endloop
endmethod
    
static method onInit takes nothing returns nothing
    set TreeRect    = Rect(0.00,0.00,1.00,1.00)
    set TreeCheck   = Filter(function Knock.CheckTrees)
    set ChainFilter = Filter(function Knock.ChainCheck)
    set LineFilter  = Filter(function Knock.LineCheck)
endmethod
endstruct

private function Init takes nothing returns nothing
    set MapMaxX     = GetRectMaxX(bj_mapInitialPlayableArea)
    set MapMaxY     = GetRectMaxY(bj_mapInitialPlayableArea)
    set MapMinX     = GetRectMinX(bj_mapInitialPlayableArea)
    set MapMinY     = GetRectMinY(bj_mapInitialPlayableArea)     
endfunction

endlibrary

The units don't get chained anymore. (Meaning that when the unit target touches a unit, they don't get knocked back)
05-16-2009, 01:39 PM#6
Vexorian
The way you wrote your struct and interface, the default is not to allow chain by default.

So, to make chain work you'll have to create a struct that extends Knock and got a ChainCondition method that returns true, then use the Knock stuff.

I think you actually want the default to allow Chains, in that case:

Collapse JASS:
private interface face
    method OnPeriodic takes nothing returns nothing defaults nothing
    method OnStop takes nothing returns nothing defaults nothing
    method OnStopCondition takes nothing returns boolean defaults false
    method OnChain takes nothing returns nothing defaults nothing
    method OnChainCondition takes nothing returns boolean defaults true
endinterface

Collapse JASS:
                    if not IsUnitInGroup(t,.hit) then
                        if  not (.OnChainCondition.exists) or .OnChainCondition() then
                                set cx = GetUnitX(t)

05-16-2009, 01:50 PM#7
wraithseeker
+REP, solved.