• 💀 Happy Halloween! 💀 It's time to vote for the best terrain! Check out the entries to Hive's HD Terrain Contest #2 - Vampire Folklore.❗️Poll closes on November 14, 2023. 🔗Click here to cast your vote!
  • 🏆 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!
  • 🏆 HD Level Design Contest #1 is OPEN! Contestants must create a maze with at least one entry point, and at least one exit point. The map should be made in HD mode, and should not be openable in SD. Only custom models from Hive's HD model and texture sections are allowed. The only exceptions are DNC models and omnilights. This is mainly a visual and design oriented contest, not technical. The UI and video walkthrough rules are there to give everyone an equal shot at victory by standardizing how viewers see the terrain. 🔗Click here to enter!

[vJASS] Using timer to wait for inrange check for an attack system

Status
Not open for further replies.
Level 18
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 18
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 18
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 18
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 18
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