HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Is a unit's expiration timer not accurate?

02-09-2007, 08:40 PM#1
CaptainPicard
Hello,

I've got this spell that removes a unit from the map and then (depending on the identity of the original unit) creates a summoned unit. I want the player to know that the summoned unit is temporary, so I add an expiration timer with an amount of time equal to (lifetime of summoned unit) + 0.1 seconds. There is a timer-controlled function that reaches in at (lifetime of summoned unit) and switches them back if the summoned unit is still alive.

However, most of the time (but not all of the time) the summoned unit's expiration timer seems to expire and th uint then registers as "dead" when the timer-activated function goes looking for it.

Is the unit expiration timer not precise?

Thanks,

Capt. Picard
02-10-2007, 03:17 AM#2
WNxCryptic
Code?
02-10-2007, 05:50 AM#3
CaptainPicard
Collapse JASS:
function CreateNagaMyrmidon takes integer UnitID returns boolean
    if ( UnitID < 'h61M' ) then
        if ( UnitID == 'edoc' ) then
            return true
        elseif ( UnitID == 'edcm' ) then
            return true
        elseif ( UnitID == 'h00B' ) then
            return true
        elseif (UnitID == 'n603' ) then
            return true
        endif
    else
        if (UnitID == 'h61M' ) then
            return true
        elseif (UnitID == 'hhes' ) then
            return true
        elseif (UnitID == 'n65R' ) then
            return true
        elseif (UnitID == 'n65S' ) then
            return true
        endif
    endif
    return false
endfunction

function CreateNagaSnapDragon takes integer UnitID returns boolean
    if ( UnitID < 'n00E' ) then
        if ( UnitID == 'earc' ) then
            return true
        elseif ( UnitID == 'edry' ) then
            return true
        elseif ( UnitID == 'h61C' ) then
            return true
        endif
    else
        if ( UnitID == 'n00E' ) then
            return true
        elseif ( UnitID == 'n65F' ) then
            return true
        elseif ( UnitID == 'nhea' ) then
            return true  
        endif
    endif
    return false
endfunction

function CreateNagaReaver takes integer UnitID returns boolean
    if ( UnitID == 'n00C' ) then
        return true
    elseif ( UnitID == 'n65D' ) then
        return true
    elseif ( UnitID == 'n00D' ) then
        return true
    endif
    return false
endfunction

function CreateNagaDragonTurtle takes integer UnitID returns boolean
    if ( UnitID == 'e601' ) then
        return true
    elseif ( UnitID == 'esen' ) then
        return true
    endif
    return false
endfunction

function CreateNagaRoyalGuard takes integer UnitID returns boolean
    if ( UnitID == 'h61B' ) then
        return true
    elseif ( UnitID == 'emtg' ) then
        return true
    elseif ( UnitID == 'h004' ) then
        return true
    endif
    return false
endfunction

function CreateNagaSiren takes integer UnitID returns boolean
    if ( UnitID == 'h005' ) then
        return true
    elseif ( UnitID == 'n602' ) then
        return true
    elseif ( UnitID == 'edot' ) then
        return true
    endif
    return false
endfunction

function SerpentranceSwapBack takes nothing returns nothing

    local real TargetLife
    local real TargetMana
    local real TargetFacing
    local string s
    local unit Serpent
    local unit Target
    local location TargetLoc
    local player TargetPlayer
    local player CasterPlayer

    set s = I2S( H2I( GetExpiredTimer() ) )
    call DestroyTimer( GetExpiredTimer() )
    set Serpent = I2U( GetStoredInteger(udg_AbilityCache, s, "Serpent") )
    
    // Check: are we over deep water?
    set TargetLoc = GetUnitLoc( Serpent )
    if ( IsTerrainPathableBJ(TargetLoc, PATHING_TYPE_WALKABILITY) ) then
        if ( IsTerrainPathableBJ(TargetLoc, PATHING_TYPE_FLOATABILITY) == false ) then
            call KillUnit( Serpent )
        endif
    endif
    call RemoveLocation( TargetLoc )

    // Swap back!
    if ( IsUnitAliveBJ( Serpent ) ) then

        // Information on the serpent
        set TargetLoc = GetUnitLoc( Serpent )
        set TargetFacing = GetUnitFacing( Serpent )
        set TargetLife = GetUnitLifePercent( Serpent )
        if ( GetUnitStateSwap( UNIT_STATE_MAX_MANA, Serpent ) > 0.0 ) then
            set TargetMana = GetUnitManaPercent( Serpent )
        else
            set TargetMana = GetStoredReal(udg_AbilityCache, s, "TargetMana")        
        endif

        // Put the original unit back
        set CasterPlayer = GetOwningPlayer(Serpent)
        if (IsUnitSelected( Serpent, CasterPlayer ) ) then
            call SelectUnitRemoveForPlayer( Serpent, CasterPlayer )
        endif
        call RemoveUnit( Serpent )
        set TargetPlayer = Player(GetStoredInteger(udg_AbilityCache, s, "TargetPlayer"))
        call RestoreUnitLocFacingAngleBJ( "Target", s, udg_AbilityCache, TargetPlayer, TargetLoc, TargetFacing )
        set Target = bj_lastLoadedUnit
        call ScaleMapUnits( Target )
        call SetUnitLifePercentBJ( Target, TargetLife )
        call SetUnitManaPercentBJ( Target, TargetMana )
        call AddSpecialEffectTargetUnitBJ( "origin", Target, "Abilities\\Spells\\Other\\Charm\\CharmTarget.mdl" )
        call DestroyEffectBJ( GetLastCreatedEffectBJ() )
        call RemoveLocation( TargetLoc )
    endif

    // Destroy the game cache data
    call FlushStoredMission(udg_AbilityCache, s)

    // Set non-elemental variables to null
    set Serpent = null
    set Target = null
    set TargetLoc = null
    set TargetPlayer = null
    set CasterPlayer = null    

endfunction

function SerpentranceCasterStop takes nothing returns nothing

    local string s
    local integer SerpentLevel
    local unit Caster 
    local timer t

    set t = GetExpiredTimer()
    set s = I2S( H2I( t ) )
    set SerpentLevel = GetStoredInteger(udg_AbilityCache, s, "level")
    set Caster = I2U( GetStoredInteger(udg_AbilityCache, s, "Caster") )
    call SetUnitAnimation( Caster, "stand" )
    call TimerStart(t, I2R(5*SerpentLevel+9), false, function SerpentranceSwapBack)

    // Set non-elemental variables to null
    set Caster = null
    set t = null

endfunction

function Trig_Cast_Serpentrance_Conditions takes nothing returns boolean
    if ( GetSpellAbilityId() == 'A669' ) then
        return true
    endif
    return false
endfunction

function Trig_Cast_Serpentrance_Actions takes nothing returns nothing

    local integer TargetID
    local integer NewUnitID
    local integer SerpentLevel
    local real TargetLife
    local real TargetMana
    local real TargetFacing
    local real SerpentScale
    local unit Caster
    local unit Target
    local unit Serpent
    local player CasterPlayer
    local player TargetPlayer
    local group SelectGroup
    local location TargetLoc
    local timer t
    local string s    

    // Get information about the target and caster
    set Caster = GetSpellAbilityUnit()
    set CasterPlayer = GetOwningPlayer( Caster )
    set Target = GetSpellTargetUnit()
    set TargetID = GetUnitTypeId( Target )
    set SerpentLevel = GetUnitAbilityLevelSwapped('A669', Caster )
    
    
    // Decide which unit to make
    set NewUnitID = 0
    set SerpentScale = 0.0
    if ( CreateNagaMyrmidon( TargetID ) ) then
        if ( SerpentLevel == 1 ) then
            set NewUnitID = 'n65W'
        elseif ( SerpentLevel == 2 ) then
            set NewUnitID = 'n65X'
        elseif ( SerpentLevel == 3 ) then
            set NewUnitID = 'n65Y'
        elseif ( SerpentLevel == 4 ) then
            set NewUnitID = 'n65Z'
        endif
        set SerpentScale = 90.0
    elseif ( CreateNagaSnapDragon( TargetID ) ) then
        if ( SerpentLevel == 1 ) then
            set NewUnitID = 'n660'
        elseif ( SerpentLevel == 2 ) then
            set NewUnitID = 'n661'
        elseif ( SerpentLevel == 3 ) then
            set NewUnitID = 'n662'
        elseif ( SerpentLevel == 4 ) then
            set NewUnitID = 'n663'
        endif
        set SerpentScale = 81.0
    elseif ( CreateNagaDragonTurtle( TargetID ) ) then
        if ( SerpentLevel == 1 ) then
            set NewUnitID = 'n664'
        elseif ( SerpentLevel == 2 ) then
            set NewUnitID = 'n665'
        elseif ( SerpentLevel == 3 ) then
            set NewUnitID = 'n666'
        elseif ( SerpentLevel == 4 ) then
            set NewUnitID = 'n667'
        endif
        set SerpentScale = 72.0
    elseif ( CreateNagaReaver( TargetID ) ) then
        if ( SerpentLevel == 1 ) then
            set NewUnitID = 'n669'
        elseif ( SerpentLevel == 2 ) then
            set NewUnitID = 'n66A'
        elseif ( SerpentLevel == 3 ) then
            set NewUnitID = 'n668'
        elseif ( SerpentLevel == 4 ) then
            set NewUnitID = 'n66B'
        endif
        set SerpentScale = 100.0        
    elseif ( CreateNagaRoyalGuard( TargetID ) ) then
        if ( SerpentLevel == 1 ) then
            set NewUnitID = 'n66D'
        elseif ( SerpentLevel == 2 ) then
            set NewUnitID = 'n66E'
        elseif ( SerpentLevel == 3 ) then
            set NewUnitID = 'n66C'
        elseif ( SerpentLevel == 4 ) then
            set NewUnitID = 'n66F'
        endif
        set SerpentScale = 115.0        
    elseif ( CreateNagaSiren( TargetID ) ) then
        if ( SerpentLevel == 1 ) then
            set NewUnitID = 'n66H'
        elseif ( SerpentLevel == 2 ) then
            set NewUnitID = 'n66I'
        elseif ( SerpentLevel == 3 ) then
            set NewUnitID = 'n66G'
        elseif ( SerpentLevel == 4 ) then
            set NewUnitID = 'n66J'
        endif
        set SerpentScale = 90.0
    endif
    set SerpentScale = SerpentScale*(0.4+0.2*I2R(SerpentLevel) )

    // Create the new unit if appropriate
    if ( NewUnitID > 0 ) then

        // More information on the target
        set TargetLoc = GetUnitLoc( Target )
        set TargetFacing = GetUnitFacing( Target )
        set TargetPlayer = GetOwningPlayer( Target )
        set TargetLife = GetUnitLifePercent( Target )
        if ( GetUnitStateSwap( UNIT_STATE_MAX_MANA, Target ) > 0.0 ) then
            set TargetMana = GetUnitManaPercent( Target )
        else
            set TargetMana = 0.0
        endif

        // Drop target unit items
        call UnitRemoveItemFromSlotSwapped( 1, Target )
        call UnitRemoveItemFromSlotSwapped( 2, Target )

        // Swap!
        set t = CreateTimer()
        set s = I2S(H2I(t))
        call StoreUnit(udg_AbilityCache, s, "Target", Target)
        call RemoveUnit( Target )
        call CreateNUnitsAtLoc( 1, NewUnitID, CasterPlayer, TargetLoc, TargetFacing )
        set Serpent = GetLastCreatedUnit()
        call RemoveLocation( TargetLoc )
        call SetUnitLifePercentBJ( Serpent, TargetLife )
        call SetUnitManaPercentBJ( Serpent, TargetMana )
        call UnitApplyTimedLifeBJ( I2R(5*SerpentLevel + 10) + 1.0, 'BFig', Serpent )
        call UnitPauseTimedLifeBJ( false, Serpent )
        call UnitAddTypeBJ( UNIT_TYPE_SUMMONED, Serpent )
        call AddSpecialEffectTargetUnitBJ( "origin", Serpent, "Abilities\\Spells\\Other\\Charm\\CharmTarget.mdl" )
        call DestroyEffectBJ( GetLastCreatedEffectBJ() )

        // Add serpent to caster's selection
        set SelectGroup = GetUnitsSelectedAll(CasterPlayer)
        if ( CountUnitsInGroup(udg_ArcRain_Group) < 12 ) then
            call SelectUnitAddForPlayer( Serpent, CasterPlayer )
        endif
        call DestroyGroup( SelectGroup )

        // Wait
        call StoreInteger(udg_AbilityCache, s, "level", SerpentLevel)
        call StoreInteger(udg_AbilityCache, s, "Serpent", H2I(Serpent))
        call StoreInteger(udg_AbilityCache, s, "Caster", H2I(Caster))
        call StoreInteger(udg_AbilityCache, s, "TargetPlayer", GetConvertedPlayerId(TargetPlayer)-1)
        call StoreReal(udg_AbilityCache, s, "TargetMana", TargetMana)
        call TimerStart(t, 1.0, false, function SerpentranceCasterStop)
    endif
    
    // Set non-elemental variables to null
    set Caster = null
    set Target = null
    set Serpent = null
    set CasterPlayer = null
    set TargetPlayer = null
    set TargetLoc = null
    set t = null
    set SelectGroup = null

endfunction

//===========================================================================
function InitTrig_Cast_Serpentrance takes nothing returns nothing
    set gg_trg_Cast_Serpentrance = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Cast_Serpentrance, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Cast_Serpentrance, Condition( function Trig_Cast_Serpentrance_Conditions ) )
    call TriggerAddAction( gg_trg_Cast_Serpentrance, function Trig_Cast_Serpentrance_Actions )
    call Preload("Abilities\\Spells\\Other\\Charm\\CharmTarget.mdl")
endfunction

There are a number of functions to help me organize the various units that might come of each casting of the spell. The timer is set for 1 second so I can trigger the casting unit to stop it's animation, then the timer is set again for the rest of the time the summoned unit should last, barring its being killed.

I'm stumped unless the expiration timer isn't precise.