• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[Snippet] DamageSource

Level 31
Joined
Jul 10, 2007
Messages
6,306
JASS:
library DamageSource /* v1.0.0.0
*************************************************************************************
*
*   All damage creators require a damage source that represents the source of the damage
*
************************************************************************************
*
*   struct DamageSourceType extends array
*
*       static method create takes DamageSourceType parentType returns thistype
*
************************************************************************************
*
*   struct DamageSource extends array
*
*       readonly DamageSourceType type
*
*       static method create takes DamageSourceType damageSourceType returns thistype
*       method destroy takes nothing returns nothing
*
*************************************************************************************/
    struct DamageSourceType extends array
        private static integer instanceCount = 0
        private thistype parentType
        
        method operator == takes thistype damageSourceType returns boolean
            if (integer(this) != integer(damageSourceType) and (0 == integer(this) or 0 == integer(damageSourceType))) then
                return false
            endif
            loop
                exitwhen integer(damageSourceType) == integer(this) or 0 == integer(this)
                set this = parentType
            endloop
            return integer(this) == integer(damageSourceType)
        endmethod
        
        static method create takes DamageSourceType parentType returns thistype
            local thistype this = instanceCount + 1
            set instanceCount = this
            
            set this.parentType = parentType
            
            return this
        endmethod
    endstruct

    struct DamageSource extends array
        private static integer instanceCount = 0
        private static integer array recycler
        
        readonly DamageSourceType type
        
        static method create takes DamageSourceType damageSourceType returns thistype
            local thistype this = recycler[0]
            if (0 == this) then
                set this = instanceCount + 1
                set instanceCount = this
            else
                set recycler[0] = recycler[this]
            endif
            set this.type = damageSourceType
            
            return this
        endmethod
        method destroy takes nothing returns nothing
            set recycler[this] = recycler[0]
            set recycler[0] = this
        endmethod
    endstruct
endlibrary

Demonstration
JASS:
library DamageSourceTypes uses DamageSource
    private module DamageSourceTypes_mod
        readonly static DamageSourceType NULL = 0
        readonly static DamageSourceType HANDS
        readonly static DamageSourceType WEAPON
        
        private static method onInit takes nothing returns nothing
            set WEAPON = DamageSourceType.create(NULL)
            set HANDS = DamageSourceType.create(WEAPON)
        endmethod
    endmodule
    
    struct DamageSourceTypes extends array
        implement DamageSourceTypes_mod
    endstruct
endlibrary
 
Last edited:
I just think you are replacing something very simple with something over the top complicated.

Reasonable people usually use damage detection systems only to block all damage entirely and trigger every damage on their own. And if you do so, a map-specificly tailored damage struct containing all required information is the way to go. No need for public modules, if you ask me.

Don't get me wrong; your coding simply looks awesome in almost everything you submit, but you tend to complicate the simple stuff. No average vJasser will use those systems, as they simply can't get what they do (heck ... I have been coding for YEARS now and even I don't get the purpose of all this stuff you have there).
I do like the struct syntax and all, but I simply don't feel like everything in WC3 requires a wrapper, struct syntax and complete rescripting.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Then your code becomes extremely messy and what not ;\. Map is harder to manage and adding new things to it is more difficult.

These were made to make doing the hard complicated things easier, and they accomplish that task.

edit
oh yes, try doing evasion with the simplified stuff.. you won't get the correct behavior ; P.

Imagine a unit dual wielding two weapons. Modifiers should modify both weapons and evasion should have a chance to evade each attack. Two weapons = two different damage sources.

Using my stuff, accomplishing that high quality combat is possible with ease ; ). w/o my stuff, it is extremely hard ;o.

multiple damage sources
you need to have like a list of damage sources on each unit
and then each source has more sources underneath
and then each source might run multiple times
and then evasion works against only certain sources
evasion can only run once for a given source during some conditions
and more than once in other conditions
 
Then your code becomes extremely messy and what not ;\. Map is harder to manage and adding new things to it is more difficult.

These were made to make doing the hard complicated things easier, and they accomplish that task.
Why would you ever have to add something like damagetypes later on? When you create a map, you know exactly what kind of damage you need, as you should have a general idea about your map right from start. You know there is fire, water, etc.
I simply won't know why you would add something like that?
Also, every damage detection system can retrieve data like attack type and damage type, as they are part of WC3 coding anyway.

edit
oh yes, try doing evasion with the simplified stuff.. you won't get the correct behavior ; P.
Block all damage, roll the dice, it it hits, deal the damage and play the hit sound. I don't see any trouble here.

Imagine a unit dual wielding two weapons. Modifiers should modify both weapons and evasion should have a chance to evade each attack. Two weapons = two different damage sources.
I don't see a problem here either. For dual wield, you need to control the units attack animations anyway, as you don't want them to happen randomly.
And if you control your attack animations, you will always know which weapon did the strike. No need for a system here either.

Using my stuff, accomplishing that high quality combat is possible with ease ; ). w/o my stuff, it is extremely hard ;o.
Mhh ... don't get me wrong: I think you stuff is awesome and all, but really: Do you really expect any serious mapper out there to totally understand what it does and how to do something very simple with it?

You got an awesome product, but your advertising is just horrible. It looks like you only code for yourself and those 0.1% of people on hive that are studied programmers. Hobby programmers or those 99.9% of map makers won't even understand what you did here.


Efficiency and flexibility at all cost is just weird. Do you know why apple products are so damn popular? because they are as simple as taking a dump.
What I'm saying is: Improve your documentation, give descriptive examples, show why this stuff is actually better than using a much more simple all-in-one damage detection system, which has almost all of the features without being unneccesary complicated.


Using simple logic in your damage conditions and actions allow you to have very efficient and flexible damage events.
You got the event, you got the damage. You block it. And then you apply your logic and modifiers in one hardcoded condition.
You might argue that hardcoding is a bad practice, but we are talking about a custom map here. Stuff like this is highly map specific. The mappers know what they need and what not. Hardcoding is exactly what you need here. It's faster and everything you don't need is left out.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Uh... my stuff is simple to use... I made it highly modular so you could use DamageEvent, AdvDamageEvent, or w/e you want ; |.

If you use all of the scripts, then you can create a highly advanced combat system.

Block all damage, roll the dice, it it hits, deal the damage and play the hit sound. I don't see any trouble here.

Incorrect... damage sources may fire multiple times due to multiple damage types. You should only be evading a given source once. From here, damage sources may fire again later for things like riposte, which you should then evade.

Damage sources require instancing (a unique id) that tells things like evasion whether they should evade or not.

Now, right now I am working on stuff to showcase all of this. If you notice, I've been releasing stuff like UnitRangeTree. This will lead to UnitAcquireTarget stuff, which will lead to attacking stuff, which will lead to the damage event stuff ; ).

Let's look at a very simple modifier that modifies physical damage from weapons
JASS:
library PhysicalDamageModifier uses DamageQueue, DamageSource
    private struct PhysicalDamageModifier_p extends array
        real change
        
        private static method PRIORITY takes nothing returns integer
            return DAMAGE_PRIORITY_MODIFIER
        endmethod

        private method onDamageOutgoing takes nothing returns nothing
            if (damageType == DamageTypes.PHYSICAL and DamageSource(damageId).type == DamageSourceTypes.WEAPON) then
                set modifiedAmount = modifiedAmount + change
            endif
        endmethod
        
        private method onDamageIncoming takes nothing returns nothing
            if (damageType == DamageTypes.PHYSICAL and DamageSource(damageId).type == DamageSourceTypes.WEAPON) then
                set modifiedAmount = modifiedAmount + change
            endif
        endmethod
        
        implement DamageModificationEffect
    endstruct
    
    struct PhysicalDamageModifier extends array
        method operator change takes nothing returns real
            return PhysicalDamageModifier_p(this).change
        endmethod
        method operator change= takes real value returns nothing
            set PhysicalDamageModifier_p(this).change = value
        endmethod
        
        implement UnitIndexStructMethods
        
        method apply takes real change, boolean incoming returns thistype
            set this = PhysicalDamageModifier_p(this).apply(incoming)
            
            set this.change = change
            
            return this
        endmethod
        method destroy takes nothing returns nothing
            call PhysicalDamageModifier_p(this).destroy()
        endmethod
    endstruct
endlibrary

This can be applied to units and is a stackable effect. If you were to equip a special amulet that increased damage, then you could create this damage modifier on equip. If you drop the amulet, destroy the damage modifier. It's pretty simple ; ).


The outgoing refers to damage that is being produced on the attacker. The incoming refers to damage that is being applied to the target. First outgoing runs (builds all damage), then incoming runs (defends against damage).

I should probably write a tutorial because there really is a lot of stuff ;o.

edit
everything you don't need is left out.

The stuff I wrote is highly modular ;\. You can pick and choose what you want. If you want the simplified stuff, use AdvDamageEvent for just modifying damage the normal way. The point of this was making highly complex map specific combat systems easier to create and easier to manage. If you want a hardcoded jumble of spaghetti code, go for it ; ).
 
Hardcoding doesn't mean spaghetti programming and you know that.
And things like proc effects with deal multiple damage events in one blow were never a problem with ordinary damage detection if you did it right, as all damage events will fire one after one and you can ALWAYS retrieve the source of the damage for every single event.

It's possible to have a nice and well-done damage condition even by hardcoding all the stuff you need.
If you feel the need of adding a tutorial and linking dozens of different modules just for one purpose, it proves that your system is way to hard to understand for the average-joe.
 
You don't get my point here. Of course all your stuff is highly logical and extremely flexible. However, you miss one thing here:

Most people on Hive are not able to deal with it. They need plug and play. They need something they can look at and get a grip on how it's done and how it works.
You script for advanced jassers. Period.
To me this is fine, but to be honest: everyone with limited jass knowledge who just learned to use it and needs a damage detection system will look into it, will see the cryptic coding and the insane modularity and will just mumble "what the hell is going on?" and stick with one of the simple systems and hardcode all other stuff.
Modularity is awesome. I gotta agree. But not at all costs.
People don't like to import a dozen of libraries just for one purpose. They want all-in-one functionality. Simple interfaces and most of the stuff automated if possible.

I'm not really criticizing this particular system. It's just this one unlucky script that got my attention. I criticize the extreme coding elitism that developed here during the last years which completely destroyed the whole purpose of script submitting: saving time for lazy people or making it easier for people with limited knowledge of coding.
 
I like using Nes' stuff and sometimes, I get carried away and write similar things for my map :p

The uses of a lot of his resources may be limited, but they make things easier to look at and manage at the end of the day :D

I know it's going to be hard to make a fully functioning Combat system because of the large amount of required scripts, but that doesn't matter, it's more important to write maintainable and easily changeable scripts :D
 
Top