• 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.

I made GetUnitDamage - Is it viable??

Status
Not open for further replies.
Level 5
Joined
Oct 2, 2013
Messages
95
So I made a "system" and was thinking about posting it as a resource, but not sure yet.

It works like this:

U = the "caster", whose dmg is being retrieved
T = the target, whose armor is being tested against u's damage.

When the user wants to detect damage, it call a "startDamage()" function inside a spell struct and creates a dummy unit ( via an system function ) that is a clone of U with all items and max atk speed ( 0.00 cooldown, 0.00 animations ). That dummy is ordered to attack T. When he does, a dmg detection trigger in fire and evaluate if that damage source is part of any of the active spell structs ( active structs are defined using "startDamage" ). If damage source == dummy, then in blocks all damage done by that dummy, kills the dummy and sends the damage var to the spell struct, while calling a specific method named "do_damage". That method will do whatever the spell does with the dmg retrieved and call "stopDamage", meaning the GetDmg process is over.

The thing is am not sure if this is really efficient, maybe its just better to have all units dmg saved in some vars, modifying it every time that unit levels up or gets an item.

Also, the way I looped the GetUnitDamageX static method was taken from T32 ( Jesus4Lyf ), it works for this system but im not sure if its the best option.

So any help with improving the system code and opinions on this are greatly appreciated.

Is this useless garbage? Should I post it as a resource? It there any way to improve the code?

Theres a test map. Normal damage instances will be put out in strings like "Unit X dealt Y damage to unit Z", and theres a spell that, when used, will send a text message with just te value retrieved. Also note that i've put all armor effectiveness vs attack tipes to 100% in gameplay constants.
 

Attachments

  • GetUnitDamage v001.w3x
    50.3 KB · Views: 27
I've seen people try implementing this before, but it is a bit difficult to get right especially since most units have a minimum and maximum damage output.

My general rule of thumb: if you need to get the amount of damage a unit is going to do, use a damage detection system. If you need to get a unit's raw damage, store those values in a hashtable and read it whenever you need it.

It is hard to design that sort of system for general maps, but it is really easy to do if you are tailoring it to your own map.

I wouldn't say your system is useless though. Some people might prefer that method. And if you can do it as best as possible under those constraints, then that is good. :) Although, you should probably post the code so people are more likely to give feedback.
 
Level 5
Joined
Oct 2, 2013
Messages
95
thanks for the replies

well ok then, im going to use unit arrays to store dmg. Just one thing I would like to know tho :

JASS:
// The system module
    module GetUnitDamageX
   
        private thistype next
        private thistype prev
       
        private static method CheckDummy takes nothing returns boolean
            // This method runs every time a damage instance is detected via
            // the Damage system.
            local unit u = GetEventDamageSource()
            local thistype this=thistype(0).next
            loop
                // This block loops through all possible damage instances.
                exitwhen this==0
                if u == this.dmg_get then
                    // If the damage source happens to be a dummy unit
                    // from some spell instance, that means someone is
                    // trying to get a unit's dmg via this system.
                    // This part blocks all the damage done by the dummy,
                    // removes all his items ( so no dropables will appear )
                    // and kills it without showing any effect.
                    // Then, set the struct variable .dmg_val to the
                    // damage value dealt by the dummy, and call the
                    // "do_damage" method, where the user will set up
                    // a spell's effects using the damage value given.
                    call Damage_BlockAll()
                    set i = UnitRemoveItemFromSlot( this.dmg_get, 0 )
                    call RemoveItem(i)
                    set i = UnitRemoveItemFromSlot( this.dmg_get, 1 )
                    call RemoveItem(i)
                    set i = UnitRemoveItemFromSlot( this.dmg_get, 2 )
                    call RemoveItem(i)
                    set i = UnitRemoveItemFromSlot( this.dmg_get, 3 )
                    call RemoveItem(i)
                    set i = UnitRemoveItemFromSlot( this.dmg_get, 4 )
                    call RemoveItem(i)
                    set i = UnitRemoveItemFromSlot( this.dmg_get, 5 )
                    call RemoveItem(i)
                    call ShowUnit( this.dmg_get, false )
                    call KillUnit( this.dmg_get )
                    set this.dmg_get = null 
                    set this.dmg_val = GetEventDamage()
                    call this.do_damage()
                    set this=this.next
                endif
            endloop
            return false
        endmethod
       
        method startDamage takes nothing returns nothing
            // Puts a struct in the active struct list, meaning it's
            // looking for its dummy to show up in the dmg detection.
            // This must be called after the dummy has been created
            // using CreateDamageGetter.
            set thistype(0).next.prev=this
            set this.next=thistype(0).next
            set thistype(0).next=this
            set this.prev=thistype(0)
        endmethod
       
        method stopDamage takes nothing returns nothing
            // Removes a struct from activity. This ?????
            set this.prev.next=this.next
            set this.next.prev=this.prev
            debug set this.prev=0
        endmethod
       
        private static method onInit takes nothing returns nothing
            // Adds the trig condition. This will activate the CheckDummy
            // method every time someone gets hit.
            call TriggerAddCondition(Trig,Condition(function thistype.CheckDummy))
        endmethod
       
    endmodule

This is how i loop the struct instances - Is this safe/the best way to do it here? ( talking about that whole this.next/this.prev stuff ) I saw this in T32 code and just copied it at my trigger.
I want to unify all damage events on my map ( so i dont need to create a new trigger every time dmg detection is needed for a spell ) so I will do something that will look like this, using a simple trigger to detect dmg and then pass values to struct instances if GetEventDamageSource() matches.
Im assuming it would be more efficient than creating a trigger for every spell that needs it .... is that correct?
 
Level 5
Joined
Oct 2, 2013
Messages
95
This is the function that creates the dummy. Its not a hero.
JASS:
function CreateDamageGetter takes unit whichUnit, unit whichTarget returns unit
        // This creates a dummy viable for damage testing,
        // whichUnit being the damage source, and whichTarget
        // is whos gonna get hit.
        local real x = GetUnitX(whichTarget)
        local real y = GetUnitY(whichTarget)
        local real a
     
        // Store all items possesed by the "caster"
        local integer item1 = GetItemTypeId(UnitItemInSlot(whichUnit, 0))
        local integer item2 = GetItemTypeId(UnitItemInSlot(whichUnit, 1))
        local integer item3 = GetItemTypeId(UnitItemInSlot(whichUnit, 2))
        local integer item4 = GetItemTypeId(UnitItemInSlot(whichUnit, 3))
        local integer item5 = GetItemTypeId(UnitItemInSlot(whichUnit, 4))
        local integer item6 = GetItemTypeId(UnitItemInSlot(whichUnit, 5))
     
        //set a = bj_RADTODEG * Atan2(y - (y+15), x - (x+15)) use this?
     
        // Create the unit
        set u = CreateUnit(GetOwningPlayer(whichUnit), DUMMY_ID, (x+15), (y+15), 0)
     
        // Make dummy phased and move it to the target's location
        call SetUnitPathing( u, false )
        call SetUnitX(u,x)
        call SetUnitY(u,y)
     
        // Give the dummy items
        call UnitAddItemById(u, item1)              
        call UnitAddItemById(u, item2)
        call UnitAddItemById(u, item3)
        call UnitAddItemById(u, item4)
        call UnitAddItemById(u, item5)
        call UnitAddItemById(u, item6)
     
        // Order the unit to attack the target
        call IssueTargetOrder( u, "attack", whichTarget )
     
        // The dummy attack speed base cooldown is 0.00, with animations
        // at 0.00 too. It will attack pretty fast, but theres still a
        // slight delay.
        return u
    endfunction
 
Status
Not open for further replies.
Top