System Precise Damage Counter

Furby

Current occupation: News poster
Reaction score
144
auwqh4.png

v1.4

1p787q.png
v1.4 - 5.19.2010
- Fixed an issue when GetMostDamagePlayer function was returning wrong player​

Older update:
v1.3 - 5.15.2010
- Minor edit​

v1.2 - 5.15.2010
- Removed some unnecessary nulling
- Changed name of the library
- Changed names of functions​

v1.1 - 5.15.2010
- Fixed an issue when system was creating unnecessary links, when damaged by same player more times
- Fixed an issue when system was counting more percent when the unit was damaged for more than actual hit points
- Both system structs privatized​

v1.0 - 5.14.2010
- First release​

s30ppt.png
This damage counting will never fail, it won't fail when target is healed nor when target's maximum hp has been changed. It's great for preventing kill stealing in AoS games, but also for many other purposes.

Here's explanation how the system works.

ap89at.jpg

vgnec6.png

2ue1rg0.png
  • Make new trigger.
  • Rename it to Precise Damage Counter or whatever you want.
  • Edit -> Convert to custom text.
  • Replace the whole trigger with the code.

2a6nw1t.png
JASS:
//  |===========================================================================================|
//  |*******************************************************************************************|
//  |*****                             PRECISE DAMAGE COUNTER                              *****|
//  |***                             ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯                              ****|
//  |**                                      by Furby                                        ***|
//  |*****                                    v1.4                                         *****|
//  |*******************************************************************************************|
//  |                                   - Requirements -                                        |
//  |                                        AIDS                                               |
//  |                                       Damage                                              |
//  |*******************************************************************************************|
//  |                                   - Functions -                                           |
/*  |      PDC_GetDamagePercentUnit takes unit whatUnit, player whatPlayer returns real         |*/
//  |       - returns damage done to the unit in percent                                        |
/*         PDC_GetMostDamagePlayer takes unit whatUnit returns player                           |*/
//  |       - returns player who done the most damage to unit                                   |
//  |*******************************************************************************************|
//  |                            more info at thehelper.net                                     |
//  |===========================================================================================|
library PDC requires AIDS, Damage

    // If this function will return true, unit will be counted as valid
    private function ValidUnit takes unit u returns boolean
        return true
    endfunction

    // If this function will return true, damage will be counted as valid
    // uses the usual damage event responses
    private function ValidDamage takes nothing returns boolean
        return true
    endfunction

    // = = = = = = = = = = = = = = = = = = = = = = = = = = = = 
    //  DO NOT TOUCH BELOW UNLESS YOU KNOW WHAT'RE YOU DOING!
    // = = = = = = = = = = = = = = = = = = = = = = = = = = = =

    private struct DamageCount
        real percent
        player  who
        thistype next
        private method onDestroy takes nothing returns nothing
            set percent = 0.0
            set who = null
        endmethod
    endstruct

    private struct VictimUnit extends array
        //! runtextmacro AIDS()
        real done
        DamageCount first
        DamageCount last
        private static method AIDS_filter takes unit u returns boolean
            return ValidUnit(u)
        endmethod   
        
        private method AIDS_onDestroy takes nothing returns nothing
            local DamageCount dc = first
            loop
                call dc.destroy()
                exitwhen(dc.next == dc or dc == 0)
                set dc = dc.next
            endloop
        endmethod
        
        private method AIDS_onCreate takes nothing returns nothing
            set done = 0.0
        endmethod
        
        private static method onDamage takes nothing returns nothing
            local unit u = GetTriggerUnit()
            local thistype this = VictimUnit<u>
            local real dmgPercent = 100.0 * (GetEventDamage() / GetUnitState(u, UNIT_STATE_MAX_LIFE))
            local player p = GetOwningPlayer(GetEventDamageSource())
            local real over = dmgPercent - (100 - done)
            local DamageCount dc = 0
            local DamageCount temp = 0
            if GetEventDamage() &gt; GetWidgetLife(u) then
                set dmgPercent = 100.0 * (GetWidgetLife(u) / GetUnitState(u, UNIT_STATE_MAX_LIFE))
                set over = dmgPercent - (100 - done)
            endif
            if over &gt; 0 then
                set dc = first
                loop
                    exitwhen(over &lt;= 0.0 or dc == 0)
                    if dc.percent - over &gt; 0.0 then
                        set dc.percent = dc.percent - over
                        set over = 0.0
                    else
                        set over = over - dc.percent
                        set temp = dc
                        if dc.next &gt; 0 then
                            set dc = dc.next
                        endif
                        call temp.destroy()
                    endif
                endloop
                if dc &gt; 0 then
                    set first = dc
                endif
                if last.who == p then
                    set dc = last
                else
                    set dc = DamageCount.create()
                    set dc.next = dc
                    set last.next = dc
                    set last = dc
                endif
            else
                if first &gt; 0 then
                    if last.who == p then
                        set dc = last
                    else
                        set dc = DamageCount.create()
                        set last.next = dc
                        set dc.next = dc
                        set last = dc
                    endif
                else
                    set dc = DamageCount.create()
                    set first = dc
                    set dc.next = dc
                    set last = dc
                endif
            endif
            set dc.percent = dc.percent + dmgPercent
            set dc.who = p
            set done = done + dmgPercent
            set u = null
        endmethod
        
        private static method AIDS_onInit takes nothing returns nothing
            local trigger t = CreateTrigger()
            call Damage_RegisterEvent(t)
            call TriggerAddCondition(t, Condition(function ValidDamage))
            call TriggerAddAction(t, function thistype.onDamage)
        endmethod
    endstruct
    
    public function GetDamagePercentUnit takes unit whatUnit, player whatPlayer returns real
        local DamageCount dc = VictimUnit[whatUnit].first
        local real total = 0
        loop
            if dc.who == whatPlayer then
                set total = total + dc.percent
            endif
            exitwhen(dc.next == dc or dc == 0)
            set dc = dc.next
        endloop
        return total
    endfunction
    
    public function GetMostDamagePlayer takes unit whatUnit returns player
        local real temp = 0
        local player result = null
        local integer i = 0
        loop
            exitwhen(i&gt;15)
            if GetDamagePercentUnit(whatUnit, Player(i)) &gt; temp then
                set result = Player(i)
                set temp = GetDamagePercentUnit(whatUnit, Player(i))
            endif
            set i = i + 1
        endloop
        return result
    endfunction
    
endlibrary</u>


2hcqpg9.png
  • What does this do?
    - It counts percent of damage done to any unit on the map by all players.
  • Why would I need that?
    - If you use anything related to bounty, this should help you.
  • Why not just count damage done and then calculate percent when unit dies?
    - That would count healed units two times.
  • Hmm.
    - Aha?
  • I will use it for my map.
    - Ok? That's why it's here.
  • Do you want some credits?
    - Sure, why not.
  • I need to edit it to fit my map!
    - Go ahead, I don't care.
  • I don't understand vJass
    - So?
 

Attachments

  • PreciseDamageCounterDEMOMAP.w3x
    63.1 KB · Views: 367

Jesus4Lyf

Good Idea™
Reaction score
397
That is a really cool premise. There is one problem. How do you factor in regen?

In an AoS or something, heroes often get away and heal. The one who deserves the kill is the one who dealt all the damage since they last healed. There are ways to accomplish this - they're not that hard.

When a unit is damaged, store their missing health, after the damage is dealt ([LJASS]GetUnitState(unit,UNIT_STATE_MAX_LIFE)-(GetWidgetLife(unit)-GetEventDamage())[/LJASS]). Then, next time they are damage, check their missing health ([LJASS]GetUnitState(unit,UNIT_STATE_MAX_LIFE)-GetWidgetLife(unit)[/LJASS]). Find [LJASS](nowMissingHealthBeforeActuallyDealingThisDamage/prevMissingHealth)[/LJASS] which is then a value you can multiply every damage count by to reduce it by the percentage regenerated since when it was last damaged. This will factor in every heal and everything. :)

Also, I'm not sure what you're doing in your loops as I haven't read it yet, but I bet I could write this thing without loops... (except for the regen part).
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
-> Privatelize DamageCount and VictimUnit.
-> Just remove the usage of LinkedList, you should use array in this case, since the players number are fixed. It is faster too.
Jasshelper will pop up error if you put arrayed member(s) in array struct, use dynamic array/hashtable to solve it.
JASS:
type DamageCount extends real array [16]
private struct VictimUnit
    DamageCount dc
    
    method AIDS_onCreate takes nothing returns nothing
        set .dc = DamageCount.create()
    endmethod

//.dc[GetPlayerId(GetOwningPlayer(GetEventDamageSource))] += GetEventDamage
 

Furby

Current occupation: News poster
Reaction score
144
That is a really cool premise. There is one problem. How do you factor in regen?

In an AoS or something, heroes often get away and heal. The one who deserves the kill is the one who dealt all the damage since they last healed. There are ways to accomplish this - they're not that hard.

When a unit is damaged, store their missing health, after the damage is dealt ([LJASS]GetUnitState(unit,UNIT_STATE_MAX_LIFE)-(GetWidgetLife(unit)-GetEventDamage())[/LJASS]). Then, next time they are damage, check their missing health ([LJASS]GetUnitState(unit,UNIT_STATE_MAX_LIFE)-GetWidgetLife(unit)[/LJASS]). Find [LJASS](nowMissingHealthBeforeActuallyDealingThisDamage/prevMissingHealth)[/LJASS] which is then a value you can multiply every damage count by to reduce it by the percentage regenerated since when it was last damaged. This will factor in every heal and everything. :)
I think this system takes care of it. :thup:
Also, I'm not sure what you're doing in your loops as I haven't read it yet, but I bet I could write this thing without loops... (except for the regen part).
Do tell. :)
-> Privatelize DamageCount and VictimUnit.
Oh, thanks. Done.
-> Just remove the usage of LinkedList, you should use array in this case, since the players number are fixed. It is faster too.
Jasshelper will pop up error if you put arrayed member(s) in array struct, use dynamic array/hashtable to solve it.
JASS:
type DamageCount extends real array [16]
private struct VictimUnit
    DamageCount dc
    
    method AIDS_onCreate takes nothing returns nothing
        set .dc = DamageCount.create()
    endmethod

//.dc[GetPlayerId(GetOwningPlayer(GetEventDamageSource))] += GetEventDamage
Eww.. you misunderstood my system, if it was working as you said, it would not be precise. :)

Ok, I think none of you understood my system correctly, here's how it works:

ap89at.jpg

___________________

Released version 1.1. Check the change log.
 

Chaos_Knight

New Member
Reaction score
39
Furby, maybe shorter functions, like PreciseDamageCounter_GetUnitPlayerDamage
DamageCounter_Damage
Or PDC_GUPD
 
Reaction score
91
Just the normal function names would do good... Otherwise, just make your library an abbreviation (PDC) and leave the functions public. This way is more user friendly. :thup:
 

Romek

Super Moderator
Reaction score
963
> Or PDC_GUPD
Christ, no.

From a brief look, method [ljass]validDamage[/ljass] could be removed, and you could just [ljass]ValidDamage[/ljass] directly. You could also state somewhere that it uses the usual damage event responses. :p
 

Furby

Current occupation: News poster
Reaction score
144
> Or PDC_GUPD
Christ, no.
I don't even like current one with "PDC". xD It looks ugly, but otherwise it would be just too long.
From a brief look, method [ljass]validDamage[/ljass] could be removed, and you could just [ljass]ValidDamage[/ljass] directly. You could also state somewhere that it uses the usual damage event responses. :p
Oh, yeah. Thanks. Fixed. :)
 

Komaqtion

You can change this now in User CP.
Reaction score
469
Also, struct members doesn't need to be nulled either, right ? :S
(Or am I crazy to believe I've heard this ? XD)

And also, put [ljass]GetEventDamageSource()[/ljass] into a unit variable (Which also needs to be nulled later) and you should also null that player variable ;)
 

Romek

Super Moderator
Reaction score
963
> Also, struct members doesn't need to be nulled either, right ? :S
Right (they're likely to be overwritten). Though it doesn't hurt to, I'd imagine.

> null that player variable
Players don't need to be nulled.
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
....., linked list is really not needed, as I mentioned it before.
2d array/hashtable is enough for it.
Linked list is slower when the node is deep inside the list.
GetDamagePercent unit will faster if you remove linked list because O(n) search in linked list is not really fast.
 

Furby

Current occupation: News poster
Reaction score
144
....., linked list is really not needed, as I mentioned it before.
2d array/hashtable is enough for it.
Linked list is slower when the node is deep inside the list.
GetDamagePercent unit will faster if you remove linked list because O(n) search in linked list is not really fast.

You don't get it, do you? :rolleyes:

Have you seen picture with explanation? ;)

Show me how you gonna do it with arrays.. :thup:
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
set i = i + 1 o_O
If you want to add some temporary data, just use the other slots to do so.
 

Furby

Current occupation: News poster
Reaction score
144
I would have to move all indexes of array after each damage overwrite.
 

Furby

Current occupation: News poster
Reaction score
144
Released version 1.4!

Fixed one pretty major bug and reworked demo map! :thup:
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top