View Single Post
Old 09-13-2009, 08:41 AM   #43
Quillraven
User
 
Join Date: Sep 2007
Posts: 40

Quillraven has little to show at this moment (3)

Send a message via ICQ to Quillraven
Default

just wanted to mention that i got a "bug" with this library when using it with different missile spells with knockback or a moving dummy which casts frostnova on itself.

howevere i could "fix" it with this change:

one more global
Collapse JASS:
private constant real epsilon                                   = 10.0

and the changed function:
Collapse JASS:
function IsTerrainPathingType takes real x, real y, integer terrainPathingType returns boolean
    local boolean b = false
    local real x2 = 0
    local real y2 = 0
    if terrainPathingType == TERRAIN_PATHING_DEEP then
        set b = not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY)
    elseif terrainPathingType == TERRAIN_PATHING_SHALLOW then
        set b = not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY)
    elseif terrainPathingType == TERRAIN_PATHING_LAND then
        set b = IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY)
    elseif terrainPathingType == TERRAIN_PATHING_WALKABLE then
        call SetUnitPosition(Dummy, x, y)
        set x2 = GetUnitX( Dummy )
        set y2 = GetUnitY( Dummy )
        set b = (x-x2)*(x-x2)+(y-y2)*(y-y2) <= epsilon*epsilon and not (not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY))
        call SetUnitX(Dummy, WorldMinX)
        call SetUnitY(Dummy, WorldMinY)
    endif
    return b
endfunction

this worked fine for me now. missiles are still blocked by buildings or sthg else but the "collision bug" or whatevere it was didn't appear anymore.

i think (or i'm really sure:D) that it is my "bad triggered" spells, so i share them here as well for debugging.

description:
when i use freezing shards and cast the fireball at the same targetpoint, the fireball missile sometimes detonated near the freezing shards when using the original library. imo this shouldn't happen because there is no knockback, only a dummy without locust and the IsUnitTargetable function returns false, when a unit has the 'win&' ability (like the footman dummy of the library). so the librar'y dummy isn't picked either.
when using my changes the spells work fine.



Collapse JASS:
scope FreezingShard

globals
    private trigger trig = null
    private constant integer SpellID = 'A00C'
    private constant integer DummySpellID = 'A01D'
    private constant integer MissileID = 'h000'
    private constant real Basedam = 20
    private constant real Bonusdam = 5
    private constant real IntBonusdam = 0.60
    
    private constant real missilespeed = 350
    private constant real AoE = 225
    
    private player TempPlayer = null
    private unit TempCaster = null
    private unit TempDummy = null
    private real TempDamage = 0.00
    private boolexpr beFilter = null
endglobals

private function group_filter takes nothing returns boolean
    return IsUnitTargetable( GetFilterUnit() ) and IsUnitEnemy( GetFilterUnit(), TempPlayer )
endfunction

private function group_callback takes nothing returns nothing
    local unit u = GetEnumUnit()
    local real x = 0.00
    local real y = 0.00
    
    set x = GetUnitX( u )
    set y = GetUnitY( u )
    call DealDamage( TempCaster, u, TempDamage )
    call SetUnitX( TempDummy, x )
    call SetUnitY( TempDummy, y )
    call IssueTargetOrder( TempDummy, "frostnova", TempDummy )
    call DestroyEffect( AddSpecialEffect( GetAbilityEffectById( SpellID, EFFECT_TYPE_AREA_EFFECT, 1 ), x, y ) )
endfunction

private struct Spell
    unit caster
    unit dummy
    unit array missiles[12]
    
    player owner
    
    group targets
    
    real targetX
    real targetY
    
    real damage
    
    private method onTimedLoop takes nothing returns boolean
        local integer i = 0
        local real x = 0.00
        local real y = 0.00
        local real angle = 0.00
        
        if( this.missiles[0] == null or not IsUnitInRangeXY( this.missiles[0], this.targetX, this.targetY, AoE ) ) then
            return false
        endif
        
        set TempPlayer = this.owner
        set TempDamage = this.damage
        set TempCaster = this.caster
        set TempDummy = this.dummy
        loop
            exitwhen i > 11
            call GroupClear( TEMPGROUP )
            call GroupEnumUnitsInRange( TEMPGROUP, GetUnitX( this.missiles[i] ), GetUnitY( this.missiles[i] ), 80, beFilter )
            call GroupRemoveUnit( TEMPGROUP, this.dummy )
            call GroupRemoveGroup( this.targets, TEMPGROUP )
            call ForGroup( TEMPGROUP, function group_callback )
            call GroupAddGroup( TEMPGROUP, this.targets )
        
            set x = GetUnitX( this.missiles[i] )
            set y = GetUnitY( this.missiles[i] )
            set angle = Atan2( y - this.targetY, x - this.targetX )
            call SetUnitX( this.missiles[i], x + missilespeed * TimedLoop_PERIOD * Cos( angle ) )
            call SetUnitY( this.missiles[i], y + missilespeed * TimedLoop_PERIOD * Sin( angle ) )
            set i = i + 1
        endloop

        return true
    endmethod

    implement TimedLoop
    
    static method create takes unit c, real x, real y returns Spell
        local Spell data = Spell.allocate()
        local integer i = 0
        local integer spelllevel = GetUnitAbilityLevel( c, SpellID )
        local real x2 = 0.00
        local real y2 = 0.00
        local real angle = 0.00
        
        set data.caster = c
        set data.owner = GetOwningPlayer( c )
        set data.targetX = x
        set data.targetY = y
        set data.targets = NewGroup()
        set data.damage = Basedam + ( Bonusdam * spelllevel ) + ( IntBonusdam * GetHeroInt( c, true ) )
        set data.dummy = CreateUnit( data.owner, DUMMY_ID, x, y, 0 )
        call UnitRemoveAbility( data.dummy, 'Aloc' )
        call UnitAddAbility( data.dummy, DummySpellID )
        call SetUnitAbilityLevel( data.dummy, DummySpellID, spelllevel )

        loop
            exitwhen i > 11
            set angle = 2*bj_PI/12 * i
            set x2 = x + 50 * Cos( angle )
            set y2 = y + 50 * Sin( angle )
            set data.missiles[i] = CreateUnit( data.owner, MissileID, x2, y2, bj_RADTODEG * Atan2( y2 - y, x2 - x ) )
            set i = i + 1
        endloop
        
        call data.startTimedLoop()
        
        return data
    endmethod
    
    method onDestroy takes nothing returns nothing
        local integer i = 0

        call ReleaseGroup( this.targets )
        loop
            exitwhen i > 11
            if( this.missiles[i] != null ) then
                call KillUnit( this.missiles[i] )
            endif
            set i = i + 1
        endloop
        if( this.dummy != null ) then
            call UnitApplyTimedLife( this.dummy, 'BTLF', 2.00 )
            call ShowUnit( this.dummy, false )
        endif
    endmethod
endstruct

private function Conditions takes nothing returns boolean
    local Spell spell = 0
    
    if( GetSpellAbilityId() == SpellID ) then
        set spell = Spell.create( GetTriggerUnit(), GetSpellTargetX(), GetSpellTargetY() )
    endif
    
    return false
endfunction

public function init takes unit RegisterUnit returns nothing
    if( trig == null ) then
        set trig = CreateTrigger()
        set beFilter = Condition( function group_filter )
        call TriggerAddCondition( trig, Condition( function Conditions ) )
    endif
    call TriggerRegisterUnitEvent( trig, RegisterUnit, EVENT_UNIT_SPELL_EFFECT )
endfunction

endscope

Collapse JASS:
scope Fireball

globals
    private trigger trig = null
    private constant integer SpellID = 'A01P'
    private constant integer MissileID = 'h003'
    private constant real Basedam = 40
    private constant real Bonusdam = 15
    private constant real IntBonusdam = 0.45
    private constant real AoE = 350
    private constant real missilespeed = 750
    
    private boolexpr beFilter = null
    private boolexpr beFilter2 = null
    private player TempPlayer = null
    private unit TempUnit = null
    private real TempDam = 0
endglobals

private function group_filter_callback takes nothing returns boolean
    return IsUnitTargetable( GetFilterUnit() ) and IsUnitEnemy( GetFilterUnit(), TempPlayer )
endfunction

private function group_filter_callback2 takes nothing returns boolean
    local unit u = GetFilterUnit()
    
    if( IsUnitTargetable( u ) and IsUnitEnemy( u, TempPlayer ) ) then
        call DealDamage( TempUnit, u, TempDam )
    endif
    
    set u = null
    return false
endfunction

private struct Spell
    unit caster
    unit missile
    
    player owner
    
    real damage
    real targetX
    real targetY
    real dist
    
    private method onTimedLoop takes nothing returns boolean      
        local real x = GetUnitX( this.missile )
        local real y = GetUnitY( this.missile )
        
        if( this.caster == null or IsUnitType( this.missile, UNIT_TYPE_DEAD ) or this.dist >= 1500 ) then
            return false
        endif
            
        set TempPlayer = this.owner
        call GroupClear( TEMPGROUP )
        call GroupEnumUnitsInRange( TEMPGROUP, x, y, 80, beFilter )

        if( FirstOfGroup( TEMPGROUP ) != null ) then
            return false
        else
            set this.dist = this.dist + missilespeed * TimedLoop_PERIOD
            set x = x + missilespeed * TimedLoop_PERIOD * CosBJ( GetUnitFacing( this.missile ) )
            set y = y + missilespeed * TimedLoop_PERIOD * SinBJ( GetUnitFacing( this.missile ) )
            if( not IsTerrainPathingType( x, y, TERRAIN_PATHING_WALKABLE ) ) then
                return false
            endif
            call SetUnitX( this.missile, x )
            call SetUnitY( this.missile, y )
        endif
        return true
    endmethod

    implement TimedLoop
    
    static method create takes unit c, real x, real y returns Spell
        local Spell data = Spell.allocate()
        local real cx = GetUnitX( c )
        local real cy = GetUnitY( c )
        local real angle = Atan2( y - cy, x - cx )
        
        set data.caster = c
        set data.owner = GetOwningPlayer( c )
        set data.targetX = x
        set data.targetY = y
        set data.damage = Basedam + ( Bonusdam * GetUnitAbilityLevel( c, SpellID ) ) + ( IntBonusdam * GetHeroInt( c, true ) )
        set data.missile = CreateUnit( GetOwningPlayer( c ), MissileID, cx + 120.00 * Cos( angle ), cy + 120.00 * Sin( angle ), bj_RADTODEG * angle )
        set data.dist = 0
        
        call data.startTimedLoop()
        
        return data
    endmethod
    
    method onDestroy takes nothing returns nothing
        local real x = 0
        local real y = 0
    
        if( not IsUnitType( this.missile, UNIT_TYPE_DEAD ) ) then
            set x = GetUnitX( this.missile )
            set y = GetUnitY( this.missile )
            if( this.caster != null ) then
                set TempPlayer = this.owner
                set TempUnit = this.caster
                set TempDam = this.damage
                call GroupClear( TEMPGROUP )
                call GroupEnumUnitsInRange( TEMPGROUP, x, y, AoE, beFilter2 )
            endif
            call DestroyEffect( AddSpecialEffect( GetAbilityEffectById( SpellID, EFFECT_TYPE_AREA_EFFECT, 0 ), x, y ) )
            call KillUnit( this.missile )
        endif
    endmethod
endstruct

private function Conditions takes nothing returns boolean
    local Spell spell = 0
    
    if( GetSpellAbilityId() == SpellID ) then
        set spell = Spell.create( GetTriggerUnit(), GetSpellTargetX(), GetSpellTargetY() )
    endif
    return false
endfunction

public function init takes unit RegisterUnit returns nothing
    if( trig == null ) then
        set trig = CreateTrigger()
        set beFilter = Condition( function group_filter_callback )
        set beFilter2 = Condition( function group_filter_callback2 )
        call TriggerAddCondition( trig, Condition( function Conditions ) )
    endif
    call TriggerRegisterUnitEvent( trig, RegisterUnit, EVENT_UNIT_SPELL_EFFECT )
endfunction

endscope
Quillraven is offline   Reply With Quote