Attachment System Challenge - KillCounter

Flare

Stops copies me!
Reaction score
662
You need 0 groups to attach 10 different properties to a unit xD

(Note: I don't know what "group method" is)

edit: A couple people have repped me for my "tag-team ownage" comment...I never knew being a dick could be so rewarding! I'll have to try more often :p

That's if you don't want to recycle no-longer-used arrays i.e. when a unit completely decays, they have no business of having a kill count, since they can't use it in any way

And what's so 'being a dick'-ish about teaming up with Ace to prove a point? That's instant win tbh :D
 

Cohadar

master of fugue
Reaction score
209
I'm imagining it when I get the correct messages then, thanks for clearing it up :thup:

In case you're too sure that you're right to test it, I've provided an image:
http://img108.imageshack.us/my.php?image=killcountersh8.jpg

I don't give a shit for some messages you write on your own.
It does not work in my test map.

TheDamien said:
1 is feasible.
Ok now I need you to prove it, extend your CSData example so it attaches one more property to unit using only one group.

Let it be real property called Bounty that calculates like this:
set Bounty = Bounty + GetRandomReal(7., 10.) * GetUnitLevel(GetTriggerUnit())
 

quraji

zap
Reaction score
144
I don't give a shit for some messages you write on your own.
It does not work in my test map.

"some messages you write on your own"
Are you implying I sent the game messages by myself, and they weren't a result of the kill counter? If so, I take offense.

BTW I found the issue:

JASS:
        loop
            exitwhen i == GetPlayers() //doesn't work with only one player in the game, you have to add more through Player Properties
            //just replace with a number, like 11
        
            call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_DEATH, null)
            set i = i + 1
        
        endloop


Now then, I think you owe me some rep :D
 

Vexorian

Why no custom sig?
Reaction score
187
Custom unit data is the best way to do this. I can't think how using PUI would make this any easier - you still run into the same problems.
TheDamien has a solution with CSData so I won't bother with speed stuff:
Unit groups (just for fun):
JASS:
library whatever initializer init

   globals
       private group array bits
       private constant integer N=10 //err I doubt a unit will ever kill more than 1023 units
   endglobals

   function GetKills takes unit u returns integer
    local integer p=1
    local integer i=0
    local integer r=0
       loop
           exitwhen i==N
           if (IsUnitInGroup(u,bits<i>)) then
               set r=r+p
           endif
           set p=p*2
           set i=i+1
       endloop
    return r
   endfunction

   private function onDeath takes nothing returns nothing
    local unit u=GetKillingUnit()
    local integer i=0
       loop
           exitwhen i==N
           if(IsUnitInGroup(u,bits<i>))  then
               call GroupRemoveUnit(bits<i>,u)
           else
               call GroupAddUnit(bits<i>,u)
               debug call BJDebugMsg(GetUnitName(u)+&quot; has killed &quot;+I2S(GetKills(u) )+&quot; units ! &quot; )
               set u=null
               return
           endif
           set i=i+1
       endloop
       debug call BJDebugMsg(&quot;Darn, I told you, your map is imbalanced and a single unit is able to kill 1024 other units, it is ridiculous, please increase N to 31&quot;)
    set u=null
   endfunction

   private function init takes nothing returns nothing
    local trigger t = CreateTrigger()
    local integer i = 0
    
        loop
            exitwhen i &gt;= 16
            call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_DEATH, null)
            set i=i+1        
        endloop
        set i=N-1
        loop
            exitwhen i&lt;0
            set bits<i>=CreateGroup()
            set i=i-1
        endloop
        call TriggerAddAction(t, function onDeath)
        set t = null
   endfunction


endlibrary


</i></i></i></i></i>



Table: This is my current favorite system and would use it anywhere speed is not a factor, besides its speed deficiency is not really that considerable, I only do a call to this per processor instant so it doesn't matter a lot.
JASS:
library whatever initializer init requires Table

   globals
       private group log
       private Table kills
   endglobals

   private function H2I takes handle h returns integer
       return h
       return 0
   endfunction

   function GetKills takes unit u returns integer
       if(IsUnitInGroup(u,log)) then
           return kills[H2I(u)]
       endif
    return 0
   endfunction

   private function onDeath takes nothing returns nothing
    local unit u=GetKillingUnit()
       if(IsUnitInGroup(u,log)) then
           set kills[H2I(u)]=kills[H2I(u)]+1
       else
           call GroupAddUnit(log,u)
           set kills[H2I(u)]=1
       endif
       debug call BJDebugMsg(GetUnitName(u)+&quot; has killed &quot;+I2S(GetKills(u) )+&quot; units ! &quot; )
    set u=null
   endfunction

   private function init takes nothing returns nothing
    local trigger t = CreateTrigger()
    local integer i = 0
    
        set log=CreateGroup()
        loop
            exitwhen i &gt;= 16
            call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_DEATH, null)
            set i=i+1        
        endloop
        set kills=Table.create()
        call TriggerAddAction(t, function onDeath)
        set t = null
   endfunction


endlibrary

Cohadar will complain about how it leaks with I2S, and it will certainly not win the speed contest (since speed is always sooo important) The thing is that gamecache is incredibly reliable, have 9000 units alive, and it will still work. Also, the same "Table" system will allow you to make something else in which you attach to units without conflicts with this Kill counter stuff - this is something that no gamecache alternative has fixed so far, besides of the few ones that are textmacro dependent, but in that case you need to deal with code size increment, grim's data system that uses mega arrays for example will generate huge code per instance and a couple of 50 array names.

Oh and I am of course using the unit group trick in the Table test, It is true that TheDamien was the first one to use it here but I would have used it as well, just because I have recently converted to Groupism, btw the same trick will make HSAS and HAIL work just fine. This demonstrates my prediction that unit groups are the ultimate attachment system, everyone ended up using unit groups to attach booleans to units even though they are saying their solution is CSData or inlined 0x100000, the reality is that they have used unit groups, which allow the same level of safety as user data, but without monopolizing anything.



Ever since that spell pack that made me figure out how good IsUnitInGroup is I have always wanted to use the bit trick to make a system that attaches integers to units, I am glad I finally had the chance to do it.

The real fix to this is to set the value to 0 when you create the unit rather than worry about doing UnitGroup stuff. I also think that the rule in Cohadar's post about not resetting the value after the unit dies is ambiguos , for example with one interpretation not even user data would work there. If the unit has no corpse, the unit will be removed when it dies.
 

Cohadar

master of fugue
Reaction score
209
Now then, I think you owe me some rep :D

Are you referring to the -rep I am going to give you for wasting my time by posting the code that does not compile properly?

Or maybe to the fact that after I fix your stupid error it still does not work.
You can see why you failed here.

Vexorian said:
I also think that the rule in Cohadar's post about not resetting the value after the unit dies is ambiguos
What if unit has reincarnation?
What if someone casts resurrection?

Vexorian said:
for example with one interpretation not even user data would work there. If the unit has no corpse, the unit will be removed when it dies.
Ancient Hydra in Pyramidal Defence has no corpse (because it spawns 3 smaller hydras when it dies) so I guess UnitUserData works in that case :p

// checking the code you posted...

(someone merge my posts please....)
 

quraji

zap
Reaction score
144
Are you referring to the -rep I am going to give you for wasting my time by posting the code that does not compile properly?

Or maybe to the fact that after I fix your stupid error it still does not work.
You can see why you failed here.

I didn't know about your test map rules. Let me quote the rules you posted:

>Make a KillCounter library that will attach a Counter variable to all units on the map and will keep track of how many units some unit killed.

All units on the map...nothing about working with repeated killing and spawning. So, fulfilled.

1. All your code must be in one library. (except the system you are using)

Fulfilled.

2. Monopolizing UnitUserData is not allowed.

Fulfilled.

3. No using of Object editor is allowed, you must use some attaching system to do the job.

Fulfilled.

4. The only event you are allowed to use is EVENT_PLAYER_UNIT_DEATH

Fulfilled.

In the end, you're just sore about the gamecache crashing thread thing, it's okay :thup:


Oh yeah, you're negative rep loses against the positive rep I've gotten from this thread :p
But who else better than you to pop my neg-rep cherry? Hah.

Now let me get out of this thread before this gets really ugly xD
 
Reaction score
333
JASS:
library BountyCounter initializer Init requires CSData
    globals
        private group G = CreateGroup()
    endglobals
    
    private struct UnitProps [24573] // stops working after 24573 or so leaks/handles in use
        integer kills
        real bounty
    endstruct
    
    private function UnitDies takes nothing returns boolean
        local unit u = GetKillingUnit()
        local unit v = GetTriggerUnit()
        local UnitProps d
        
        if (u != null and u != v) then
            set d = GetCSData(u)
            if IsUnitInGroup(u, G) then
                set d.kills = d.kills+1
                set d.bounty = d.bounty+GetRandomReal(7., 10.) * GetUnitLevel(v)
            else
                call GroupAddUnit(G, u)
                if (d == 0) then
                    set d = UnitProps.create()
                    call SetCSData(u, d)
                endif
                set d.kills = 1
                set d.bounty = GetRandomReal(7., 10.) * GetUnitLevel(v)
            endif
            call BJDebugMsg(I2S(CS_H2I(u)-0x100000) + &quot; has killed &quot; + I2S(d.kills) + &quot; units.&quot;)
        endif
        
        set u = null
        set v = null
        return false
    endfunction
    
    private function Init takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH)
        call TriggerAddCondition(t, Condition(function UnitDies))
    endfunction
endlibrary


A struct solves the multiple unit property problem. Once again, not thoroughly tested (but did pass the UA test).
 

Vexorian

Why no custom sig?
Reaction score
187
What if unit has reincarnation?
The unit will not really die until it dies without reincarnation. I never said it is a bad rule, I said it is ambiguous, units get removed after their decay time, in some units which don't leave corpses this time is quite small. After that the unit doesn't exist so keeping its kill counts is non-sense.
 

Cohadar

master of fugue
Reaction score
209
I didn't know about your test map rules.
Ye there is a simple unwritten rule that the code must work what it was supposed to. (just dl the map with your code)

@grim001
Just saw your post, ok standard group solution, thank you for your time.

@Vexorian
The unit will not really die until it dies without reincarnation?
It does not trigger the death event?

The real fix to this is to set the value to 0 when you create the unit.
This turns out to be the best solution so far :D
 

quraji

zap
Reaction score
144
Ye there is a simple unwritten rule that the code must work what it was supposed to. (just dl the map with your code)

I meant how it had to pass your test in your map, you should include that.
And if you "just dl" the map I attached it would work, but I understand that it should work in all maps, which is why I pointed out the problem. (It was one line that was returning a bad value when the map only has 1 player - which really wouldn't happen outside using Test Map - so please don't act like I crashed your game with some horrible code)

Sigh, I can't help myself from posting :p
 

Vexorian

Why no custom sig?
Reaction score
187
@Vexorian
The unit will not really die until it dies without reincarnation?
It does not trigger the death event?
Nope, that's the reason it is so darn hard to detect it. (Not really, it is extremely easy, specially if you use a unit group, as a matter of fact, lack of death event is what makes it very easy to detect it, reminds me I should release BurningNightmare officially)
 

Cohadar

master of fugue
Reaction score
209
I wonder why that group trick works at all...

Guess it is time to end all this:
JASS:
library KillCounter initializer Init uses PUI

globals
    // You can use same Pivot array for all unit properties that need to be reset together.
    // This usually means all properties declared inside one library or scope.
    // Same shit as using group trick with standard attaching
    private unit array Pivot 
    
    // kill counter property
    private integer array Counter
endglobals

//===========================================================================
public function Add takes unit whichUnit, integer count returns integer
    local integer pui = GetUnitIndex(whichUnit)
    if Pivot[pui] != whichUnit then
        set Pivot[pui] = whichUnit
        set Counter[pui] = count
    else
        set Counter[pui] = Counter[pui] + count
    endif
    return Counter[pui]
endfunction

//===========================================================================
//  I need this only for debug message
//===========================================================================
private function H2I takes handle h returns integer
    return h
    return 0
endfunction

//===========================================================================
private function Conditions takes nothing returns boolean
    local unit killer = GetKillingUnit()

    if killer == null then
        return false
    endif
    
    if IsUnitAlly(killer, GetOwningPlayer(GetDyingUnit())) then
        set killer = null
        return false
    endif

    call Add(killer, 1) // this calls GetUnitIndex()
    
    // We can use GetUnitUserData directly if there are no waits after call to GetUnitIndex
    debug call BJDebugMsg(I2S(H2I(killer)-0x100000) + &quot; has killed &quot; + I2S(Counter[GetUnitUserData(killer)]) + &quot; units.&quot;)
    
    set killer = null
    return false
endfunction

//===========================================================================
public function Init takes nothing returns nothing
    local trigger trig = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_DEATH)
    call TriggerAddCondition(trig, Condition(function Conditions))
endfunction

endlibrary


Most important demo maps are attached to the first post.
Thank you all who participated in this thread.
 

Cohadar

master of fugue
Reaction score
209
Are you going to argue about the definition of monopolizing?
I mean really.

There is a difference between using a resource and preventing others from using it.
 

Vexorian

Why no custom sig?
Reaction score
187
PUI is monopolizing userdata, now every other system will have to use it instead of being able to use UserData directly.

Anyway, I am glad, my solutions and Damien's are the only ones which could work with more than 8191 units. Great?.
 

Cohadar

master of fugue
Reaction score
209
Vexorian said:
PUI is monopolizing userdata, now every other system will have to use it instead of being able to use UserData directly.
How about: ALL other systems that needed UserData can now work together.
I mean really are you going to tell me that is bad compared to only one specific system using it and screwing all others?
(once again, monopolizing == not sharing a resource)

Vexorian said:
Anyway, I am glad, my solutions and Damien's are the only ones which could work with more than 8191 units. Great?.

Something tells me that IsUnitInGroup and AddunitToGroup will not be so nice when unit count gets over 1000 (compared to constant array lookup PUI has)
 

chobibo

Level 1 Crypt Lord
Reaction score
48
Who won? Aside from cohadar, did anyone use any unit custom value system?
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top