• 🏆 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] Using timer to wait for inrange check for an attack system

Status
Not open for further replies.
Level 19
Joined
Oct 12, 2007
Messages
1,821
Hey there.

I've been progressing a lot on learning vJass and been working hard on my map. However I reached a dead end again because there's one thing I cannot achieve. I was wondering if there's someone here able to help me out a bit.

What I want to achieve is:

- A unit moves to a different unit and 'attacks' it (only 1 hit). Then this unit attacks him back after maybe half a second (only 1 hit).

The thing is that the units this is about are unable to attack so I should use animations and such to 'fake' their attacks.

How do I work on creating something like this?
Basically I have to create a timer (?) that checks if the moving unit is in range of its target already. When he is the timer should trigger a function to make the unit use his fake attack animation and such. Then I should run another timer to 'wait' .5 seconds and let the second unit 'attack' back?

I'm a bit stuck and very unsure what's the right way to approach this.
 
Level 19
Joined
Oct 12, 2007
Messages
1,821
I'm trying to create something like that. I just don't seem to get far.
Could you give me a little push in the right direction?

I'm using TimerUtils, but I don't know how to properly use it actually.
UnitIndexing is something I will need later on.

Like how do I set a repeating 0.0325 loop to the timer and how do I work to make something happen when the unit comes in range?

JASS:
library CombatSystem requires UnitIndexing, TimerUtils

globals
    private timer TIMER = NewTimer()
endglobals


function Combat_MovementTimer takes timer t returns nothing
    
    if IsUnitInRange(u, t, 100.) then
     ///...
    endif


endfunction

private function Combat_MoveUnit takes unit u, unit t returns nothing
    local real x = GetUnitX(t)
    local real y = GetUnitY(t)
    
    call IssueTargetOrder(u, "move", t)
    call Combat_MovemenTimer(TIMER)
    



    set u = null
    set t = null
endfunction

endlibrary
 
Level 19
Joined
Oct 12, 2007
Messages
1,821
I came up with something like this, but it doesn't work.
I figured letting the timer loop constantly is not a good idea so with TimerUtils I would "release" it every time after I'm done.

But yeah. Like I said, I never reach the text message part, and the units don't even move at all. So there must be something wrong.

JASS:
library CombatSystem requires UnitIndexing, TimerUtils

globals
    private timer T
    
    private unit attacker = null
    private unit defender = null
    
    private integer BLOCK = 'A00N'
endglobals


private function Combat_InRange takes nothing returns nothing

    if IsUnitInRange(attacker, defender, 90.) then
        call ReleaseTimer(T)
        
        call DisplayTextToForce( GetPlayersAll(), "check check check" )
        set attacker = null
        set defender = null
    endif
endfunction

function Combat_MoveUnit takes unit u, unit t returns nothing
    
    set T = NewTimer()
    
    if GetUnitAbilityLevel(t, BLOCK) > 0 then
        call SetUnitAnimation(t, "stand defend")
    endif
    
    call IssueTargetOrder(u, "move", t)
    
    set attacker = u
    set defender = t
    call TimerStart(T, 0.05, true, function Combat_InRange)
    



    set u = null
    set t = null
endfunction

endlibrary
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
instead of T you should use local timer, currently you can only call your function once, making it not really MUI, nor MPI.

JASS:
function callback ...
    local timer TimerThatExecutesMe = GetExpiredTimer()
    //work with TimerThatExecutesMe
    ...
endfunction

function executer ...
    local timer t = NewTimer()
    ...
    call TimerStart(t, 0.05, true, function callback)
    set t = null
endfunction

This way you can have as many running instances as you want(theoretically)
 
Level 19
Joined
Oct 12, 2007
Messages
1,821
I see.
Well it doesn't have to be able to run simultaniously since it's for a turn based game.
But I'll try the local timer thing!
 
Level 19
Joined
Oct 12, 2007
Messages
1,821
This is what I got so far.
With the text messages I found out until where it seems to work.
Unfortunatelly not till the end.

I see:
"Unit is Moving"
"Unit is in range now"
"Combat_Attacking is running"
"Order has been made, attacker goes first" (which is weird, because when I tested it the defender should've gone first actually.. but that's a less important problem for later)

But after this I don't see any messages anymore.
I should be seeing:
"Attacker hits for X damage"

But for some reason it doesn't go that far.
I'm getting pretty mad but can't seem to find the issue here. :(



JASS:
library CombatSystem requires UnitIndexing, TimerUtils, CombatSnippets

globals
    private unit attacker = null
    private unit defender = null
    
    private integer FIRST_STRIKE = 'A00A'
    private integer LAST_STRIKE = 'A00D'
    private integer CHARGE = 'A00G'
    private integer BLOCK = 'A00N'
    private integer PARRY = 'A00M'
    private integer HOLD_YOUR_GROUND = 'A01E'
    private integer TRAMPLE = 'A00H'
endglobals

function Combat_Attacking takes unit u, unit t returns nothing
    local integer i = 1 /// positive = attacker goes first. negative = defender first///
    local integer uid = GetUnitId(u)
    local integer tid = GetUnitId(t)
    local boolean openingstrike
    local integer d
    local boolean charge
    local boolean trample
    local boolean block
    local boolean parry
    local boolean hold
    
    call IssueImmediateOrder(u, "stop")
    call DisplayTextToForce(GetPlayersAll(), "Combat_Attacking is running")
    ///test
        set Unit_Attacks[uid] = GetHeroStr(u, true)
        set Unit_Attacks[tid] = GetHeroStr(t, true)
    ///
    
    ///Setting who attacks first: ///
    if GetUnitAbilityLevel(t, HOLD_YOUR_GROUND) > 0 then
        if IsUnitClassified(u, "mounted") and ( GetUnitAbilityLevel(u, TRAMPLE) == 0 or Unit_Charging[uid] == false) then ///If unit didnt move, he has no trample
            set i = i - 2
            set hold = true
        elseif GetUnitAbilityLevel(u, TRAMPLE) > 0 then
            set trample = true
        endif
    endif
    if GetUnitAbilityLevel(t, FIRST_STRIKE) > 0 then
        if GetUnitAbilityLevel(u, FIRST_STRIKE) == 0 then
            set i = i - 2
        endif
    endif
    if GetUnitAbilityLevel(u, LAST_STRIKE) > 0 and Unit_Charging[uid] == false then ///checking if the unit has moved. If he did, Last Strike has no effect
        if GetUnitAbilityLevel(t, LAST_STRIKE) == 0 then
            set i = i - 2
        endif
    endif
    if GetUnitAbilityLevel(u, CHARGE) > 0 and Unit_Charging[uid] then
        set charge = true
    endif
    if GetUnitAbilityLevel(t, BLOCK) > 0 then
        set block = true
    endif
    if GetUnitAbilityLevel(u, PARRY) > 0 then
        set parry = true
    endif
    ///Order has been made///
    if i> 0 then
        call DisplayTextToForce(GetPlayersAll(), "Order has been made, attacker goes first")
    else
        call DisplayTextToForce(GetPlayersAll(), "Order has been made, defender goes first")
    endif
    if i > 0 then ///attacker first, defender second
        ///The attacker:
        if Unit_Attacks[uid] > 0 then //And is unit alive??? (for later)
            if Unit_Attacks[uid] == GetHeroStr(u, true) then
                set openingstrike = true
            endif
            
            call SetUnitAnimation(u, "attack")
            set d = GetRandomInt(Unit_DamageMin[uid], Unit_DamageMax[uid]) - Unit_Armor[tid]
            if openingstrike and charge then
                set d = d + 1
            endif
            if openingstrike and block then
                set d = d - 1
                ///SPECIAL EFFECT - BLOCK
            endif
            if hold then
                set d = d - 1
            endif
            call UnitDamageTarget(u, t, I2R(d), true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS) 
            set Unit_Attacks[uid] = Unit_Attacks[uid] - 1
            
            set openingstrike = false
            call DisplayTextToForce(GetPlayersAll(), "Attacker hit for: "+I2S(d)+" damage!")
        endif
        ///The defender:
        if Unit_Attacks[tid] > 0 then ///(and is unit alive?) for later           
            call SetUnitAnimation(t, "attack")
            set d = GetRandomInt(Unit_DamageMin[tid], Unit_DamageMax[tid]) - Unit_Armor[uid]
            if parry then
                set d = d - 1
                ///SPECIAL EFFECT - PARRY
            endif
            if hold then
                set d = d + 1
            endif
            call UnitDamageTarget(t, u, I2R(d), true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS) 
            set Unit_Attacks[tid] = Unit_Attacks[tid] - 1
            
            call DisplayTextToForce(GetPlayersAll(), "Defender hit for: "+I2S(d)+" damage!")
        endif
    
    else
        ///The defender:
        if Unit_Attacks[tid] > 0 then // is unit alive?       
            call SetUnitAnimation(t, "attack")
            set d = GetRandomInt(Unit_DamageMin[tid], Unit_DamageMax[tid]) - Unit_Armor[uid]
            if hold then
                set d = d + 1
            endif
            call UnitDamageTarget(t, u, I2R(d), true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS) 
            set Unit_Attacks[tid] = Unit_Attacks[tid] - 1
            
            call DisplayTextToForce(GetPlayersAll(), "Defender hit for: "+I2S(d)+" damage!")
        endif
        ///The Attacker:
        if Unit_Attacks[uid] > 0 then //is unit alive?
            call SetUnitAnimation(u, "attack")
            set d = GetRandomInt(Unit_DamageMin[uid], Unit_DamageMax[uid]) - Unit_Armor[tid]
            if hold then
                set d = d - 1
            endif
            call UnitDamageTarget(u, t, I2R(d), true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS) 
            set Unit_Attacks[uid] = Unit_Attacks[uid] - 1
            
            call DisplayTextToForce(GetPlayersAll(), "Attacker hit for: "+I2S(d)+" damage!")
        endif
    
    endif
    

endfunction

private function callback takes nothing returns nothing
    local timer T = GetExpiredTimer()

    if IsUnitInRange(attacker, defender, 70.) then
        call ReleaseTimer(T)

        call DisplayTextToForce( GetPlayersAll(), "Unit is in range now" )
        
        call Combat_Attacking(attacker, defender)
        set attacker = null
        set defender = null
    endif
endfunction

function Combat_MoveUnit takes unit u, unit t returns nothing
    local timer T = NewTimer()
    
    if GetUnitAbilityLevel(t, BLOCK) > 0 then
        call SetUnitAnimation(t, "stand defend")
    endif
    
    call DisplayTextToForce( GetPlayersAll(), "Unit is moving" )
    
    call IssuePointOrder(u, "move", GetUnitX(t), GetUnitY(t))
    
    set attacker = u
    set defender = t
    call TimerStart(T, 0.05, true, function callback)

    set u = null
    set t = null
endfunction

endlibrary
 
Status
Not open for further replies.
Top