• 🏆 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!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[vJASS] How to Detect if Unit is stuck while being "Pushed/Knockbacked"

Status
Not open for further replies.
Level 13
Joined
Jul 26, 2008
Messages
1,009
Alright I have a skill called Rush. Basically the caster "Rushes" towards a point and upon hitting an enemy he stops and deals AoE damage.

Problem is if he gets caught on something he just sort of sits there til the timer runs out.

What I want is a way to detect if he's stuck on an object and force him to stop and finish the spell. I had it where it checked if he was still in range of his last coordinates but that just caused issues.

Here it is. It uses Knockback, XEDamage and GroupUtils:

JASS:
scope Rush initializer InitTrig_Rush

globals
    private constant integer SPELLID        = 'Rush'
    private constant real tick              = 0.034
    private unit TEMP
endglobals

private struct Data extends xedamage

    unit c
    unit t
    real x
    real y
    real dur

    static method GroupDamage takes nothing returns boolean
     local xedamage d= xedamage.create()
     local real a = bj_RADTODEG*Atan2( GetUnitY(GetFilterUnit()) - GetUnitY(TEMP), GetUnitX(GetFilterUnit()) - GetUnitX(TEMP) )
     local integer lvl = GetUnitAbilityLevel(TEMP, SPELLID)
        set d.dtype = DAMAGE_TYPE_NORMAL
        set d.atype = ATTACK_TYPE_MELEE
        call d.damageTarget(TEMP,GetFilterUnit(), SpellStat(TEMP,true)*(0.5+0.2*lvl) + 25+25*lvl)
        if IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(TEMP)) and not(IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE)) and not( IsUnitType(GetFilterUnit(), UNIT_TYPE_DEAD ))then
            call KnockbackTarget(TEMP, GetFilterUnit(), a, 250., 700., false, true, false, GetAbilityEffectById(SPELLID, EFFECT_TYPE_MISSILE, 0))
        endif
        call d.destroy()
        return false
    endmethod

    static method GroupEm takes nothing returns boolean
     local xedamage d= xedamage.create()
     local real a = bj_RADTODEG*Atan2( GetUnitY(GetFilterUnit()) - GetUnitY(TEMP), GetUnitX(GetFilterUnit()) - GetUnitX(TEMP) )
     local integer lvl = GetUnitAbilityLevel(TEMP, SPELLID)
        if IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(TEMP)) and not(IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE)) and not( IsUnitType(GetFilterUnit(), UNIT_TYPE_DEAD ))then
            set d.dtype = DAMAGE_TYPE_NORMAL
            set d.atype = ATTACK_TYPE_MELEE
            call d.damageTarget(TEMP,GetFilterUnit(), SpellStat(TEMP,true)*(0.5+0.2*lvl) + 25+25*lvl)
            call KnockbackTarget(TEMP, GetFilterUnit(), a, 250., 700., false, true, false, GetAbilityEffectById(SPELLID, EFFECT_TYPE_MISSILE, 0))
        endif
        call d.destroy()
     return false
    endmethod
    
    static method Timer takes nothing returns nothing
     local timer tim = GetExpiredTimer()
     local Data D = Data(GetTimerData(tim))
     local integer lvl = GetUnitAbilityLevel(D.c, SPELLID)
     local real angle = Atan2(D.y - GetUnitY(D.c), D.x - GetUnitX(D.c))
     local real x = GetUnitX(D.c) + 20 * Cos(angle)
     local real y = GetUnitY(D.c) + 20 * Sin(angle)
     local real dist = SquareRoot((GetUnitX(D.c)-D.x) * (GetUnitX(D.c)-D.x) + (GetUnitY(D.c)-D.y) * (GetUnitY(D.c)-D.y))
     local group g = NewGroup()

        if IsTerrainWalkable(x,y) and not(IsUnitType(D.c, UNIT_TYPE_DEAD)) then
            call SetUnitPosition(D.c, x, y)
            call SetUnitFacing(D.c, angle * bj_RADTODEG)

            set TEMP = D.c

            if dist < 19 or D.dur > 3 then
                call GroupEnumUnitsInArea(g, x, y, 160, Filter(function Data.GroupDamage))
                call DestroyEffect(AddSpecialEffectTarget(GetAbilityEffectById(SPELLID, EFFECT_TYPE_MISSILE, 1), D.c, "origin"))

                call D.destroy()
                call ReleaseTimer(tim)
            else
                call GroupEnumUnitsInArea(g, x, y, 60, Filter(function Data.GroupEm))
            endif

        else
            call GroupEnumUnitsInArea(g, x, y, 160, Filter(function Data.GroupDamage))
            call DestroyEffect(AddSpecialEffectTarget(GetAbilityEffectById(SPELLID, EFFECT_TYPE_MISSILE, 1), D.c, "origin"))
            call D.destroy()
            call ReleaseTimer(tim)
        endif

         call ReleaseGroup(g)
         set D.dur = D.dur + tick
    endmethod

    static method create takes unit c, real x, real y returns Data
     local timer tim = NewTimer()
     local Data D = Data.allocate()
     local integer lvl = GetUnitAbilityLevel(c, SPELLID)
        set D.c = c
        set D.x = x
        set D.y = y
        set D.dur = 0

        call SetTimerData(tim,D)
        call TimerStart(tim, tick, true, function Data.Timer)
     return D
    endmethod

    static method Conditions takes nothing returns boolean
        if GetSpellAbilityId() == SPELLID then
            call Data.create(GetTriggerUnit(), GetSpellTargetX(), GetSpellTargetY())
        endif
     return true
    endmethod

endstruct

//===========================================================================
public function InitTrig_Rush takes nothing returns nothing
 local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( t, function Data.Conditions )
    call XE_PreloadAbility(SPELLID)
endfunction

endscope
 
Level 12
Joined
Oct 16, 2010
Messages
680
1. well you can turn off units pathing or
2. add your spell a destructible hitting effect
so then you can even destroy trees and other blocking objects or do with them whatever you want (disabling a units pathing will also let it pass over cliffs)
 
Level 37
Joined
Mar 6, 2006
Messages
9,240
One method is to use one item and a rect. Move the rect where the unit should be moved. Hide all items in that rect. Move the item to the center of the rect. Check the distance between the item's position and the center of the rect. if it is not zero, the point is blocked. Show items in the region and hide the item you use for the system.

Items have collision size of 16.
 
Level 13
Joined
Jul 26, 2008
Messages
1,009
That's already in both my map and the code I showed. Either I've done it wrong or it doesn't work. :\

I had the idea of just incrementing a variable from 0 to the range I'm trying to reach and if I get too far from that mark I don't reach it, but that'd take some pondering to understand the mechanics of it.

EDIT
Alright I played around with the mechanics of it and found that by SettingUnitX and SettingUnitY I didn't have this problem (And a few other problems were resolved too) so that works :)
 
Last edited:
Status
Not open for further replies.
Top