System Damage Struct

Dirac

22710180
Reaction score
147
JASS:
library Damage /* v2.0.7
 ____            _    _            _____    _____
|  _ \    /\    | \  / |    /\    /  ___\  |  ___|
| | | |  /  \   |  \/  |   /  \   | /  _   |  __|
| |_| | / /\ \  | |\/| |  / /\ \  | |_\ \  | |___
|____/ /_/  \_\ |_|  |_| /_/  \_\ \_____/  |_____|

*/uses/* one of the following
*/  optional AIDS           /* thehelper.net/forums/showthread.php/130752-Advanced-Indexing-Data-Storage
*/  optional UnitIndexer    /* hiveworkshop.com/forums/jass-functions-413/system-unit-indexer-172090/

  and
*/  LinkedListModule        /* thehelper.net/forums/showthread.php/168775-LinkedListModule

Description:
    Damage management, detection and manipulation. Allows full control of damage done
    by units
    
Extensions:
    DamageMod       v1.0.7  - thehelper.net/forums/showthread.php/168198-Damage-Mod
    DamageType      v1.0.1  - thehelper.net/forums/showthread.php/168364-DamageType
    DamageId        v1.0.1  - thehelper.net/forums/showthread.php/168970-DamageId
    Armor           v1.0.0  - thehelper.net/forums/showthread.php/168282-Armor
    RawDamage       v1.0.5  - thehelper.net/forums/showthread.php/168257-RawDamage
    AmplifyDamage   v1.0.4  - thehelper.net/forums/showthread.php/168255-AmplifyDamage
    DampenDamage    v1.0.4  - thehelper.net/forums/showthread.php/168256-DampenDamage
    Shield          v1.0.6  - thehelper.net/forums/showthread.php/168203-Shield
    
Demo map:
    mediafire.com/?o8hxybolawjeun5
    
Special thanks to:
    -Nestharus (Damage library concept)
    -PurgeandFire111 (original idea)
    
Important note:
    If there is another damage system in your map, replace it with this one, otherwise
    it will cause collision issues. This system provides all the useful damage tools
    you'll ever need.

**********************************************************************/
globals
//*********************************************************************
//  For damage event recycling upon deindexing. Resets the main damage
//  event recognition trigger whenever that amount of units are
//  deindexed.
    private constant integer MAX_WASTED_UNITS   =   20
    
//*********************************************************************
//  An ability based off item life bonus that should add a very high 
//  amount of hp to the unit, the higher the better
            constant integer ABILITY_LIFE_BONUS =   'DcLB'
endglobals
/**********************************************************************
*
*   function RegisterGlobalDamage takes code func returns triggercondition
*       -   Runs after damage mods and unit damage events.
*   function UnregisterGlobalDamage takes triggercondition whichCondition returns nothing
*       -   Unregister the function from handling damage
*   function RegisterUnitDamageDealtEvent takes unit whichUnit, code func returns DamageDealtEvent
*   function RegisterUnitDamageTakenEvent takes unit whichUnit, code func returns DamageTakenEvent
*       -   Wrappers for the DamageDealtEvent and DamageTakenEvent register methods
*   function UnregisterUnitDamageDealtEvent takes DamageDealtEvent whichEvent returns nothing
*   function UnregisterUnitDamageTakenEvent takes DamageTakenEvent whichEvent returns nothing
*       -   Wrappers for the DamageDealtEvent and DamageTakenEvent unregister methods
*   function GetUnitDamageReduction takes unit whichUnit, attacktype attackType, damagetype damageType returns real
*       -   Returns the amount of damage the unit takes from a specific type
*       -   of damage. 1.0 means it takes 100% of the damage.
*   function GetUnitArmor takes unit whichUnit returns real
*       -   Returns the unit's armor, losses it's accuracy when dealing with
*       -   negative armor.
*
***********************************************************************
*
*   struct Damage
*
*       -   This struct manages all damage done and taken.
*
*       readonly static real amount
*           -   Total damage dealt.
*       readonly static real dealt
*           -   Actual damage received by the unit:
*           -   Takes into account prevented and added damage.
*       readonly static real recount
*           -   Recount damage done by all units.
*       readonly static unit target
*       readonly static unit source
*           -   Event units.
*       readonly static integer targetId
*       readonly static integer sourceId
*           -   The custom value of those units.
*       readonly integer data
*           -   The damage event attached data.
*       static boolean enabled
*           -   If false the system stops recording damage.
*       static method prevent takes real howMuch returns real
*           -   Prevents damage done, call only inside damage handling method.
*           -   Note: after this call the unit's max health changes.
*       static method add takes real howMuch returns nothing
*           -   Increases damage done, damage dealt this way is pure, call only
*           -   inside damage handling methods.
*
**********************************************************************
*
*   struct DamageDealtEvent and DamageTakenEvent
*
*       -   Both structs have the same API, they record the unit's damage dealt
*       -   or taken.
*
*       integer data
*           -   You're able to attach and retreive data from instances.
*       static method register takes integer unitId, code func returns thistype
*           -   Registers unit's damage through the given code.
*       method unregister takes nothing returns nothing
*           -   Unregisters the given damage event.
*
**********************************************************************
*
*   struct UnitDamage
*
*       -   This struct manages damage done by units, uses unit custom value as
*       -   instances.
*
*       readonly real dealt
*       readonly real taken
*           -   Recount of unit damage, doesn't take into account current damage.
*       boolean enabled
*           -   If false then damage events by this unit wont fire.
*       method reset takes nothing returns nothing
*           -   Clears all the damage done by the given unit.
*
*********************************************************************/

    globals
        private trigger         globalTrig      =CreateTrigger()
        private integer         currentData     =0
        private real    array   unitDamageDealt
        private real    array   unitDamageTaken
    endglobals

/*********************************************************************/
    
    //! runtextmacro optional DAMAGE_TYPE_EX1()
    
    //! runtextmacro optional DAMAGE_MOD_EX1()
    
    //! runtextmacro optional DAMAGE_ID_EX1()
    
/*********************************************************************/

    function RegisterGlobalDamage takes code func returns triggercondition
        return TriggerAddCondition(globalTrig,Filter(func))
    endfunction
    
    function UnregisterGlobalDamage takes triggercondition whichCondition returns nothing
        call TriggerRemoveCondition(globalTrig,whichCondition)
    endfunction
    
/*********************************************************************/
    
    struct UnitDamage extends array
        boolean enabled
        
        method operator dealt takes nothing returns real
            return unitDamageDealt[this]
        endmethod
        
        method operator taken takes nothing returns real
            return unitDamageTaken[this]
        endmethod
        
        method reset takes nothing returns nothing
            set unitDamageDealt[this]=0
        endmethod
    endstruct

/*********************************************************************/

    //! runtextmacro DAMAGE_EVENT_REGISTRATION_SETUP("Dealt")
    
    //! runtextmacro DAMAGE_EVENT_REGISTRATION_SETUP("Taken")
    
    //! textmacro DAMAGE_EVENT_REGISTRATION_SETUP takes NAME
        struct Damage$NAME$Event extends array
            implement LinkedList
            
            //*********************************************************************
            //  The instance's corresponding unit id.
            private thistype    root
            
            //*********************************************************************
            //  First instance from the list attached to an unit.
            private thistype    node
            
            //*********************************************************************
            //  The instance's trigger to be evaluated.
            private trigger     trig
            
            //*********************************************************************
            //  If false the event wont be fired.
                    boolean     enabled
            
            //*********************************************************************
            //  Value assigned by the user.
                    integer     data
            
            static method fire takes thistype unitId returns nothing
                local thistype exit = unitId.node
                local thistype this = exit
                
                //*********************************************************************
                //  If node points to nowhere then the list is empty.
                if this==0 then
                    return
                endif
                
                //*********************************************************************
                //  Iterate through the list firing all the triggers.
                loop
                    set currentData=data
                    if enabled then
                        call TriggerEvaluate(trig)
                    endif
                    set this=next
                    exitwhen this==exit
                endloop
            endmethod
            
            static method register takes thistype unitId, code func returns thistype
                local thistype this
                if unitId.node==0 then
                    set this=createNode()
                    set unitId.node=this
                else
                    set this=allocate()
                    call unitId.node.insertNode(this)
                endif
                set root=unitId
                if this.trig==null then
                    set trig=CreateTrigger()
                else
                    call TriggerClearConditions(trig)
                endif
                set enabled=true
                call TriggerAddCondition(trig,Filter(func))
                return this
            endmethod
            
            method unregister takes nothing returns nothing
                call this.removeNode()
                if next==this then
                    set root.node=0
                elseif this==root.node then
                    set root.node=next
                endif
                call this.deallocate()
            endmethod
            
            static method clear takes thistype unitId returns nothing
                call unitId.node.flushNode()
                set unitId.node=0
            endmethod
        endstruct
    //! endtextmacro
    
/*********************************************************************/
        
    private module DamageModule
        readonly    static real             recount =0
        readonly    static real             dealt   =0
        readonly    static real             amount  =0
        readonly    static unit             source  =null
        readonly    static unit             target  =null
        readonly    static integer          sourceId=0
        readonly    static integer          targetId=0
        
        //*********************************************************************
        //  Keeps track of the amount of wasted unit indexes.
        private     static integer          count   =0
        
        //*********************************************************************
        //  Keeps track of the additional damage dealt through the Damage.add
        //  method, this damage is applied at the end of the evaluation to
        //  prevent the unit from dying.
        private     static real             toAdd   =0
        
        //*********************************************************************
        //  The main trigger that detects all damage done ingame
        private     static trigger          dmgTrig =CreateTrigger()
        
        //*********************************************************************
        //  Timer used to remove the life bonus ability from units who had
        //  damage prevented to them.
        private     static timer            after   =CreateTimer()
        
        //*********************************************************************
        //  Stack used for simultaneous damage prevention, stores all the units
        //  inside it and then it gets cleared.
        private     static boolean  array   stackIs
        private     static integer  array   stack
        
        //*********************************************************************
        //  Linked list of all units indexed.
        private     static integer  array   next
        private     static integer  array   prev
        
        private static method handleDamage takes nothing returns nothing
            local real hp
            local unit u
            
            //*********************************************************************
            //  Loops through the stack removing the life bonus ability from units,
            //  after that the unit gets removed from the stack.
            loop
                exitwhen stack[0]==0
                static if LIBRARY_UnitIndexer then
                    set u=GetUnitById(stack[0])
                else
                    set u=GetIndexUnit(stack[0])
                endif
                set hp=GetWidgetLife(u)
                call UnitRemoveAbility(u,ABILITY_LIFE_BONUS)
                call SetWidgetLife(u,hp)
                set stackIs[stack[0]]=false
                set stack[0]=stack[stack[0]]
            endloop
        endmethod
    
        static method prevent takes real howMuch returns real
            local real hp=GetWidgetLife(target)
            
            set howMuch=RMinBJ(howMuch,amount)
            
            set dealt=RMaxBJ(dealt-howMuch,0)
            
            if dealt>hp or howMuch==0 then
                return howMuch
            endif
            
            //*********************************************************************
            //  This is where the stack for damage prevention gets created. Only
            //  adds the life bonus ability if needed (remember that the damage
            //  prevention comes before the damage is actually done, so if the unit
            //  has it's max hp then adding life to it would bug.)
            if not(stackIs[targetId]) and (hp+howMuch>=GetUnitState(target,UNIT_STATE_MAX_LIFE)) then
                set stack[targetId]=stack[0]
                set stack[0]=targetId
                set stackIs[targetId]=true
                call UnitAddAbility(target,ABILITY_LIFE_BONUS)
            endif
            
            call SetWidgetLife(target,hp+howMuch)
            
            return howMuch
        endmethod
        
        static method operator enabled= takes boolean state returns nothing
            if state then
                call EnableTrigger(dmgTrig)
            else
                call DisableTrigger(dmgTrig)
            endif
        endmethod
        
        static method operator data takes nothing returns integer
            return currentData
        endmethod
        
        //! runtextmacro optional DAMAGE_ID_EX2()
        
        static method add takes real howMuch returns nothing
            set dealt=dealt+howMuch
            set toAdd=toAdd+howMuch
        endmethod
        
        //*********************************************************************
        //  First damage handler method of the entire system.
        private static method onDamage takes nothing returns boolean
        
            //*********************************************************************
            //  Stores the previous damage instance inside locals, at the end of
            //  the execution the values are reverted.
            local real      prevAmount      =amount
            local real      prevDealt       =dealt
            local real      prevAdd         =toAdd
            local unit      prevSource      =source
            local unit      prevTarget      =target
            local integer   prevSourceId    =sourceId
            local integer   prevTargetId    =targetId
            
            //! runtextmacro optional DAMAGE_ID_EX3()
            
            set amount=GetEventDamage()
            set source=GetEventDamageSource()
            set target=GetTriggerUnit()
            set sourceId=GetUnitUserData(source)
            set targetId=GetUnitUserData(target)
            set toAdd=0
            
            //! runtextmacro optional DAMAGE_ID_EX4()
            
            static if OVERKILL then
                set dealt=amount
            else
                set dealt=RMinBJ(amount,GetWidgetLife(target))
            endif
            
            //! runtextmacro optional DAMAGE_TYPE_EX2()
            
            //! runtextmacro optional DAMAGE_MOD_EX2()
            
            //*********************************************************************
            //  Fires the trigger attached to the unit's custom value, each trigger
            //  with a number of conditions that are added on the Register calls.
            if UnitDamage[sourceId].enabled then
                call DamageDealtEvent.fire(sourceId)
            endif
            if UnitDamage[targetId].enabled then
                call DamageTakenEvent.fire(targetId)
            endif
            
            call TriggerEvaluate(globalTrig)
            
            //*********************************************************************
            //  Keeping track of all damage dealt and taken...
            set unitDamageDealt[sourceId]=unitDamageDealt[sourceId]+dealt
            set unitDamageTaken[targetId]=unitDamageTaken[targetId]+dealt
            set recount=recount+dealt
            
            //*********************************************************************
            //  Applies all missing damage left to be dealt.
            if 0<toAdd then
                set enabled=false
                call UnitDamageTarget(Damage.source,Damage.target,toAdd,true,false,ATTACK_TYPE_CHAOS,DAMAGE_TYPE_UNIVERSAL,null)
                set enabled=true
            endif
            
            //*********************************************************************
            //  Reverts the variables to their previous values
            set amount=prevAmount
            set dealt=prevDealt
            set source=prevSource
            set target=prevTarget
            set sourceId=prevSourceId
            set targetId=prevTargetId
            set toAdd=prevAdd
            
            //! runtextmacro optional DAMAGE_ID_EX5()
            
            //*********************************************************************
            //  When amount equals to 0 as well as any other variable it means that
            //  no more damage is left to be done so it starts the prevention timer
            //  if stack isn't empty
            if not(stack[0]==0) and amount==0 then
                call TimerStart(after,0,false,function thistype.handleDamage)
            endif
            
            set prevSource=null
            set prevTarget=null
            
            return false
        endmethod
        
        private static method onIndex takes nothing returns boolean
            local integer index
            local unit indexUnit
            static if LIBRARY_UnitIndexer then
                set index=GetIndexedUnitId()
                set indexUnit=GetIndexedUnit()
            else
                set index=AIDS_GetIndexOfEnteringUnit()
                set indexUnit=AIDS_GetEnteringIndexUnit()
            endif
            
            //*********************************************************************
            //  Adds the unit to the list.
            set prev[next[0]]=index
            set next[index]=next[0]
            set next[0]=index
            set prev[index]=0
            
            //! runtextmacro optional DAMAGE_ID_EX6()
            
            set UnitDamage[index].enabled=true
            call TriggerRegisterUnitEvent(dmgTrig,indexUnit,EVENT_UNIT_DAMAGED)
            set indexUnit=null
            return false
        endmethod
        
        private static method onDeIndex takes nothing returns boolean
            local integer i = 0
            local integer index
            static if LIBRARY_UnitIndexer then
                set index=GetIndexedUnitId()
            else
                set index=AIDS_GetDecayingIndex()
            endif
            
            //*********************************************************************
            //  Deletes the given unit from the list.
            set next[prev[index]]=next[index]
            set prev[next[index]]=prev[index]
            
            //*********************************************************************
            //  In order to prevent a high amount of unused evets added to the
            //  trigger whenever plenty of units are deindexed it refreshes the
            //  trigger's events using a linked list of indexed units.
            set count=count+1
            if count==MAX_WASTED_UNITS then
                call DestroyTrigger(dmgTrig)
                set dmgTrig=CreateTrigger()
                call TriggerAddCondition(dmgTrig,Filter(function thistype.onDamage))
                loop
                    set i=next<i>
                    exitwhen i==0
                    static if LIBRARY_UnitIndexer then
                        call TriggerRegisterUnitEvent(dmgTrig,GetUnitById(i),EVENT_UNIT_DAMAGED)
                    else
                        call TriggerRegisterUnitEvent(dmgTrig,GetIndexUnit(i),EVENT_UNIT_DAMAGED)
                    endif
                endloop
                set count=0
            endif
            
            //*********************************************************************
            //  Prepares the triggers for the next unit.
            call DamageDealtEvent.clear(index)
            call DamageTakenEvent.clear(index)
            return false
        endmethod
        
        private static method onInit takes nothing returns nothing
        
            debug if GetObjectName(ABILITY_LIFE_BONUS)==&quot;&quot; then
            debug   call BJDebugMsg(&quot;ERROR: Life Bonus Ability doesn&#039;t exist&quot;)
            debug   return
            debug endif
            
            call TriggerAddCondition(dmgTrig,Filter(function thistype.onDamage))
            
            //*********************************************************************
            //  Detection of units that enter the map.
            static if LIBRARY_UnitIndexer then
                call RegisterUnitIndexEvent(Condition(function thistype.onIndex),UnitIndexer.INDEX)
                call RegisterUnitIndexEvent(Condition(function thistype.onDeIndex),UnitIndexer.DEINDEX)
            else
                call AIDS_RegisterOnEnter(Condition(function thistype.onIndex))
                call AIDS_RegisterOnDeallocate(Condition(function thistype.onDeIndex))
            endif
        endmethod
    endmodule
    
    struct Damage extends array
    
        //*********************************************************************
        //  Module initialization calls perform before any other.
        implement DamageModule
    endstruct
    
/*********************************************************************/
    
    function RegisterUnitDamageDealtEvent takes unit whichUnit, code func returns DamageDealtEvent
        return DamageDealtEvent.register(GetUnitUserData(whichUnit),func)
    endfunction
    
    function RegisterUnitDamageTakenEvent takes unit whichUnit, code func returns DamageTakenEvent
        return DamageTakenEvent.register(GetUnitUserData(whichUnit),func)
    endfunction
    
    function UnregisterUnitDamageDealtEvent takes DamageDealtEvent whichEvent returns nothing
        call whichEvent.unregister()
    endfunction
    
    function UnregisterUnitDamageTakenEvent takes DamageTakenEvent whichEvent returns nothing
        call whichEvent.unregister()
    endfunction
    
/*********************************************************************/
endlibrary</i>
 

tooltiperror

Super Moderator
Reaction score
231
Documentation is messy, confusing, and unclear.

Variables should be on the left side of comparisons, and constants on the right, as is the convention in Jass and about every other language.

Static methods use Pascal case.

This seems like a useless system. How is this better than Damage, despite being OOP? Why is OOP an advantage here over the typical procedural approach?
 

Dirac

22710180
Reaction score
147
Direct trigger evaluations
Instead of running 300 checks everytime an unit deals damage, this simplifies things to "this unit's damage purposes". Makes code cleaner and more intuitive.
IMO damage libraries forgot what their primary use was for: providing damage detection for specific units, no one is interested in recording all the damage caused in-game all the time, and if they can pick from the other damage libraries.
Also provides some quite useful variables (such as .dealt different from .amount)
Provides safety methods that separate trigger evaluations from one to another, so you're free to cause damage inside damage handling methods without the possibility of a bug.
It's implementation is also a lot cleaner, recycles triggers and easy to manipulate.
I don't really know how to write a good documentation for codes. I find reading this easier than AIDS, which provides awful information of how it works and it's full API isn't quite mentioned anywhere unless you read the whole thing.
Please give me some good documentation examples to improve this library
 

tooltiperror

Super Moderator
Reaction score
231
AIDS documentation is excellent, and found at the top of the library, I fail to see what it is missing. It is often used as an example of good documentation.

Perhaps you should provide me some demos of this versus the same code in Damage to show me how it is better. As far as efficiency goes, we can discuss that once I see how this improves your code compared to Damage. I feel like Damage/AIDS is just a better workflow.

The interface is really ugly. The "enableDealt" method is something you really want to avoid.
 

Nestharus

o-o
Reaction score
84
AIDS documentation is excellent, and found at the top of the library, I fail to see what it is missing. It is often used as an example of good documentation.

Ahem, I can't even read the AIDS documentation (super messy, can't find anything in it), but I can read this documentation fairly easily. The random //s all over the place is a little screwy (could be cleaner), but yea >.>.
 

Dirac

22710180
Reaction score
147
This is how common Damage libraries work
JASS:
library Examples
    
    globals
        unit optionA
        unit optionB
        unit optionC
    endglobals
    
    function A takes nothing returns boolean
        if GetEventDamageSource()==optionA then
            //do actions
        endif
        return false
    endfunction
    
    function B takes nothing returns boolean
        if GetTriggerUnit()==optionB then
            //do actions
        endif
        return false
    endfunction
    
    function C takes nothing returns boolean
        if GetEventDamageSource()==optionC then
            //do actions
        endif
        return false
    endfunction
    
    function onInit takes nothing returns nothing
        local trigger trig=CreateTrigger()
        call Damage_RegisterEvent(trig)
        call TriggerAddCondition(trig,Condition(function A)) //multiple conditions are added to the same trigger, all of them executed
        call TriggerAddCondition(trig,Condition(function B)) //every time an unit deals damage. Each condition performs a check or declares
        call TriggerAddCondition(trig,Condition(function C)) //a local that&#039;s irrelevant to alien functions. Also there&#039;s no way to separate
    endfunction                                              //damage done from damage taken events.

endlibrary
This is how a proper damage library works
JASS:
library Examples
    
    globals
        unit optionA
        unit optionB
        unit optionC
    endglobals
    
    function A takes nothing returns boolean
            //do actions
        return false
    endfunction
    
    function B takes nothing returns boolean
            //do actions
        return false
    endfunction
    
    function C takes nothing returns boolean
            //do actions
        return false
    endfunction
    
    function onInit takes nothing returns nothing
        call enableDealt(optionA,function A)
        call enableTaken(optionB,function B)
        call enableDealt(optionC,function C)
    endfunction

endlibrary
Ignores every non related action to the event, plus it separates when the unit deals damage from when it takes.
So that makes this system extremely efficient: only pointing out what's important and what's not.
Expect a demo map with some spells coming soon.
 

tooltiperror

Super Moderator
Reaction score
231
I don't want to register damage for every single unit that enters my map. Sure this is better in some situations, but it does it in an ugly way. Don't make this as an alternative to Damage, make it a replacement. Use OOP where you should, and functions where functions are better. And why is this called "Damage Struct" if the library is Damage?
 

Laiev

Hey Listen!!
Reaction score
188
>>This should replace damage libraries.

So, wheres the functions to deals damage and get damage type?

JASS:
Damage_Spell
Damage_Physical
Damage_Pure
Damage_IsSpell
Damage_IsPhysical
Damage_IsPure
 

tooltiperror

Super Moderator
Reaction score
231
> So, wheres the functions to deals damage and get damage type?
I didn't say it does, I said it should.
 

Dirac

22710180
Reaction score
147
Remember that Damage is only able to detect damage type if you specify it through triggers, damage done through object editor abilities can't be predicted, so these functions are plainly useless since any jasser can use a global or attach data to the damage using the DamageData module to find a way through this. I'll have to take a closer look to nestharus's adv_damage library to truly detect damage types, or at least some of them.
And i have to agree with nestharus, AIDS is horribly documented, it's almost impossible to look for anything in there, i had to read the code entirely just to discover there were internal public functions such as RegisterOnEnter, as there are many others. If TH standards are as messy as AIDS is, i can't do anything for you guys.
Also i have to disagree when you say it's useful for only some situations, i can't think of any damage trigger that involves all damage done inside W3 maps without keening on which unit is the one causing the damage or taking it.
The documentation looks cleaner inside the editor because the [ljass]/*[/ljass] comments aren't green as [ljass]//[/ljass] is.
I think the textmacro part is a bit confusing and might require some explanation, it's somehow hard to explain why is it needed, but i'll try.
 

Nestharus

o-o
Reaction score
84
Dirac, you are talking about taking damage under certain conditions (like a certain unit or set of units). It'd be like having a struct run under certain conditions for unit indexing (like specific unit types).

The reason that it is done the way it is is because users are expected to use some sort of filter function. It is way cleaner that way. Sure it is slower, but it is infinitesimally easier to manage.

Now, I can see a damage sort of struct (using DamageEvent or Damage) with some sort of filter in it (easy to use, etc), but anything else is a pain. If you want damage specific events, don't use a damage detection lib, just use the standard natives as those'll do it for specific units.

The damage libs are like EVENT_ANY_UNIT_TAKES_DAMAGE or w/e. It's easier to catch them all and then apply your filter.


Now, if your proposal goes through, then unit indexing would have to be changed around as well. Right now, unit indexers in structs catch all unit indexing but use a filter to filter out the results.


Anyways, just think about that.
 

Sgqvur

FullOfUltimateTruthsAndEt ernalPrinciples, i.e shi
Reaction score
62
tooltiperror:
1. Documentation is messy, confusing, and unclear.
2. AIDS documentation is excellent, and found at the top of the library,

Dirac:

1. I don't really know how to write a good documentation for codes.
2. The documentation looks cleaner inside the editor because the /* comments aren't green as // is.


I have a question:
Why do script resources (Jass2, vJass, Zinc) almost always provide documentation inside the script's text itself?

It's pretty ridiculous. Every "sane" language provide documentation in a more user friendly way, not in comments... green or not.
Embedding types, function names, etc. inside the code is one thing, but another tool is almost always used to generate the documentation for viewing, you don't
stare at comments. So why didn't/haven't jassers adapt a third party tool (javadoc, pod2html or something) that generates web documents or whatever. Even if users don't want to use such a tool to generate the documentation, at least they could separate the documentation and the script in different files/texts and write the documentation in whatever format they like/chose.

PS: here's a fun list
 

Dirac

22710180
Reaction score
147
@Sgqvur
Lets keep this thread related.

@Nestharus
Slower? hm we'll have to see about that, i think it's speed grows in comparison to the amout of times the damage struct is used. I could base this off any other damage system library to get a hold of the damage detection techniques they provide, but now i would be using 1 trigger firing and 2 trigger evaluations in order to get to my unit's damage action list. Ex:

Unit deals damage -> Fires event
Inside the event -> evaluates all conditions added to the damage's event (should only be 1, this system)
Fire the unit's trigger to execute the action list.

How it currently looks like right now:

Unit deals damage -> Fires event
Fire the unit's trigger to execute the action list.

No need for third party members. Regarding what you said about using natives to detect specific unit damage events, think about this: There's actually no way to fire an event when X unit deals damage, only when it takes, so in order to detect when it actually deals damage, you have to detect all damage taken by all units and filter it to only get the X unit's damage, which is exactly what this system does.
 

PurgeandFire

zxcvmkgdfg
Reaction score
511
No demo map? :( It doesn't have to be flashy, just enough to test the system, because some of us are lazy lol.
 

Dirac

22710180
Reaction score
147
Update:
-Added Damage.enabled boolean variable
-Added UnitDamage.enabled boolean variable
-Changed the method used to retrieve damage data to a more intuitive one
-Fixed a bug regarding taken damage not firing events

Added demo map
 

NoobImbaPro

You can change this now in User CP.
Reaction score
60
Dude the comments have to be on the code, not in documentation....Make some better work
 

Nestharus

o-o
Reaction score
84
It should run off of the catch all though >.>


I'm saying that it'd be better to write a system like this to work off of a standard damage detection system. Also, your shield stuff should be a whole separate library. You are coupling resources together : |.


Now, I am also saying that j4l's damage event thing is bad too because it couples features together as well... the core should be plain old damage detection (nothing else). Above that core you can code whatever you want easily, like purge's damage mod stuff or your direct trigger eval stuff.


When you start mashing resources together, you get messy resources... modularity is more important than speed.


Now, you can do extensions to get rid of that speed hit (like I do sometimes), but that really does output some really messy code, lol (it's a serious pain to keep updated).

edit
What TH needs is a damage detection library that only does damage detection (no modifying damage or anything else). From that, damage mod libs and other things can be made >.>. As TH currently doesn't have that and as nobody will probably ever approve that, TH is completely stuck with j4l's damage lib and the exact features on it ;p.
 

Dirac

22710180
Reaction score
147
Couldn't agree more Nes, however this i can easily add plain simple damage detection to this library. Something like RegisterOnDamageEvent(boolexpr callback)->triggercondition is very easily added, wouldn't cause speed cost.
If needed i can submit a version to the hive that uses your damage detection system, but it shouldn't be the case because this system pretends you to only have 1 function that registers ALL of the damage done, which is the one this system provides.
Perfect world? A list of textmacros for your damage system. (like advDamage)

EDIT:
@tooltiperror
Pascal Case? i've never ever seen that on static methods
JASS:
static method create takes nothing returns thistype
JASS:
static method onInit takes nothing returns nothing

Always camelCase
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top