• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[vJASS] CombatState

Status
Not open for further replies.
Level 4
Joined
May 23, 2010
Messages
83
Hello,

I've just posted a threat about my loops. But another thing is being a pain to code: my CombatState system.

First of, the code:
JASS:
library CombatState requires TextTag, ABC, PUI

    globals
        private constant real COMBAT_PERIOD = 7.
    endglobals
    
    private struct CombatData
        
        //! runtextmacro PUI()
        
        timer Clock = CreateTimer()
        
        unit Unit
        player Owner
        integer Index
        
        static method Create takes unit whichUnit returns CombatData
            local CombatData d = CombatData.allocate()
            
            set d.Unit = whichUnit
            set d.Owner = GetOwningPlayer(whichUnit)
            set d.Index = GetPlayerId(d.Owner)
            
            call SetTimerStructA(d.Clock, d)
            
            if GetLocalPlayer() == GetOwningPlayer(d.Unit) then
                call TextTag_Create(PlayerColor[d.Index], "<Entering combat>", d.Unit, 10, 90, 86, d.Owner, true) 
            endif
            
            return d
        endmethod
        
        method onDestroy takes nothing returns nothing
            if GetLocalPlayer() == GetOwningPlayer(.Unit) and not IsUnitType(.Unit, UNIT_TYPE_DEAD) then
                call TextTag_Create(PlayerColor[.Index], "<Leaving combat>", .Unit, 10, 90, 86, .Owner, true) 
            endif
            call ClearTimerStructA(.Clock)
            call PauseTimer(.Clock)
            call DestroyTimer(.Clock)
        endmethod
        
    endstruct
    
    private function CombatExpired takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local CombatData d = GetTimerStructA(t)
        debug call BJDebugMsg("CombatData destroyed by CombatExpired() function")
        call d.destroy()
    endfunction
    
    function GetUnitCombatState takes unit whichUnit returns boolean
        return CombatData[whichUnit] != 0
    endfunction
    
    function SetUnitInCombat takes unit whichUnit returns nothing
        local CombatData d = CombatData[whichUnit]
        if d == 0 then
            set d = CombatData.Create(whichUnit)
            set CombatData[whichUnit] = d
            debug call BJDebugMsg("CombatData() created.")
        endif
        call TimerStart(d.Clock, COMBAT_PERIOD, false, function CombatExpired)
    endfunction
    
    function SetUnitOutOfCombat takes unit whichUnit returns nothing
        local CombatData d = CombatData[whichUnit]
        if d != 0 then
            call d.destroy()
            debug call BJDebugMsg("SetUnitOutOfCombat() function destroyed current CombatData struct.")
        else
            debug call BJDebugMsg("|cffff0000 SetUnitOutOfCombat() function failed to destroy struct.")
        endif
    endfunction
    
endlibrary

This should work like this:

-You set the unit in/out of combat.
-If the unit is already in combat, the combat timer is refreshed.
-You can GetUnitCombatState(whichUnit) which will return true if the unit is in combat.

Problems:

-When my hero dies 'in combat' the struct is not destroyed (it says so in the BJDebugMsg but it doesn't seems to work.

I made a simple trigger just to show my hero combat state when I type '-reset', and it shows I'm in combat, even after the unit is dead and/or revived.

I used this trigger to set units out of combat when dead:
JASS:
scope test initializer onInit
    private function OnDeath takes nothing returns nothing
        local unit whichUnit = GetDyingUnit()
        call SetUnitOutOfCombat(whichUnit)
    endfunction

    private function onInit takes nothing returns nothing
        local trigger death = CreateTrigger() 
        
        call TriggerRegisterAnyUnitEventBJ(death, EVENT_PLAYER_UNIT_DEATH)
        call TriggerAddAction(death, function OnDeath)
    endfunction
endscope

I've searched for some other systems that do the same. But I want a simple system that should work in my map, with my customizations. Any suggestions are welcome :)
 
Level 4
Joined
May 23, 2010
Messages
83
The problem with this one if that it uses GetUnitUserData() which is used on PUI library (which is used on my other systems). I don't know if it may cause conflicts with other systems and the one by PurgeandFire111's.
 
Level 4
Joined
May 23, 2010
Messages
83
Yea, I got 2 other libs using PUI, but I took a look at the systems and coments. I'll try to apply UnitIndexer into my map.

By the way, no clues on the bug with the stuff I posted? Could it possibly be that the unit's death would remove the data from PUI?
 
Well I don't know why you are running the PUI textmacro, while not using any of the utility it offers, I can't find any glaring problem with your script other than this has been written already.

Unit death does not remove the data from PUI, unless there is a bug of some kind with PUI. I do not recommend using PUI as it is not an approved resource on HiveWorkshop.com, TheHelper.net or wc3c.net.
 
Level 4
Joined
May 23, 2010
Messages
83
Well I don't know why you are running the PUI textmacro, while not using any of the utility it offers, I can't find any glaring problem with your script other than this has been written already.

Sure I use it on other libs and scopes (CombatData[whichUnit])... But I'm changing that, I'm adapting my code to use UnitIndexer and I'm also looking forward that Combat State system you linked.

Unit death does not remove the data from PUI, unless there is a bug of some kind with PUI. I do not recommend using PUI as it is not an approved resource on HiveWorkshop.com, TheHelper.net or wc3c.net.

That was what I thought.

And I'm limited on my code since my hashtable functions don't show up 'colored' or in the function list either. I've searched to find out the problem but it doesn't seem to work... And read a code without the proper colorization and stuff is a pain in the *ss, and that's why I'm looking for other systems lately.

Thank you, and this thread can be closed, as I'm changing almost everything..
 
I still answer the question because that's a thing it's good to know.

JASS:
    function SetUnitOutOfCombat takes unit whichUnit returns nothing
        local CombatData d = CombatData[whichUnit]
        if d != 0 then
            call d.destroy()
            // You have to add this line :
            set CombatData[whichUnit]=0
Because when you destroy an object, it doesn't null it. For instance, removing a unit doesn't null the unit variable.
It works pretty the same with structures even if they are actually integers. Destroying structures only makes their "index" available for re-use later : the datas inside the structures are not destroyed (unless you specify it in the "onDestroy" method), you are just not supposed to use them anymore until it gets affected again.

So if you want to use !=0 or !=null to check if a struct or an handle exists and is valid, you have to always null them (the global variables that point on them, at least) after their destruction.
 
Status
Not open for further replies.
Top