• 🏆 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!

Damage Engine v0.A.2

This bundle is marked as useful / simple. Simplicity is bliss, low effort and/or may contain minor bugs.

Damage Engine


By: aznricepuff


Version: 0.A.2

Damage Engine is a damage detection and manipulation system. It also provides functionality for dealing triggered damage and using custom damage types.

As of v0.A.0 it also includes Heal Engine: an optional module for dealing with triggered
healing events.

Open the Demo Map in WE to view the system code and documentation.

Requires
  • jasshelper 0.9.Z.0+
  • Object Merger (by grimoire)
  • Table (by Vexorian)
  • TimerUtils (by Vexorian)
  • TreeMap

Changelog
For the full changelog refer to the demo map.

Keywords:
damage detection, damage manipulation, triggered damage, healing manipulation, triggered healing
Contents

Damage Engine v0.A.2 (Map)

Reviews
18 October 2011 Bribe - This is deprecated. The code is superfluous compared to what it could be. GUI Damage Engine does this better, and vJass users can take advantage of our superior vJass damage modifying systems.

Moderator

M

Moderator

18 October 2011
Bribe - This is deprecated. The code is superfluous compared to what it could be. GUI Damage Engine does this better, and vJass users can take advantage of our superior vJass damage modifying systems.
 
Level 17
Joined
Mar 17, 2009
Messages
1,349
Ok I'm not gonna read the whole thing, but some BJ's to be fixed:
JASS:
call TriggerRegisterEnterRectSimple(enterTrigger, bj_mapInitialPlayableArea)
This one leaks a region.

JASS:
call TriggerRegisterAnyUnitEventBJ(upgradeTrigger, EVENT_PLAYER_UNIT_UPGRADE_FINISH)
This here leaks 16 times, I'll advice you to avoid this BJ and use a filter to avoid leaks...

All other BJ's don't leak so they're no big deal...

As for the system itself... the idea is amazing, but I can't run the map with my Warcraft for some reason... the map doesn't open :s (I've got Warcraft v1.21)

All in all, good job!
 
Level 17
Joined
Mar 17, 2009
Messages
1,349
Kingz said:
Predefined regions like playable map area shouldn't leak :p
Oh I never knew that xD does that means that whether you use the region or not it is created at map intialization?
But it still has to be removed, and why? well, it uses locals, so it'll be filling in locals which aren't nulled... you get what I'm saying here eh?

And yes I know that leaks only 16 times in the whole game, but I mean, with a system that seems so well done, it would be a nice treat removing them :p
 
Level 23
Joined
Nov 29, 2006
Messages
2,482
In order to use it you will have to get the latest 'test' patch 1.23b which can be found at the westfall server. He is using hashtables and such, that's why.

I had some remarks on some other places in the code, but I dont have the time right now. A review will come soon, hopefully.
 
Level 11
Joined
Feb 22, 2006
Messages
752
To those who are having trouble using this I apologize. I use the 1.23b beta patch for testing purposes (since blizz is going to make the change eventually...I need to know my stuff will work with it). If you're still on 1.23a, just swap out the Table and TimerUtils libraries in the Demo map for the pre-1.23b versions on wc3.net.

As for those trigger init leaks...yes I know they leak...but 17 null boolexpr leaks didn't seem like it was a big deal. (and the thing with the un-nulled local in TriggerRegisterUnitEnterRectSimple isn't a leak cuz that region never gets destroyed).

EDIT: I'm working on a major update to this, which will break backwards compatibility (for the ONE version released so far :p). So if any moderators see this you should hold off on reviewing until the update comes out.
 
Last edited:
Level 23
Joined
Nov 29, 2006
Messages
2,482
Ah, here was those small things I saw.

JASS:
    private static method calculateDamage takes EventDamage eventDamage returns nothing
        if (eventDamage.damage > 0 and .isEnabled()) then
            call eventDamage.attacker.onDamage(eventDamage)
            if (eventDamage.damage > 0) then
                call eventDamage.target.onDamaged(eventDamage)
            endif
            if (eventDamage.damage > 0) then
                call .onUnitDamaged(eventDamage)
            endif
        endif
    endmethod

I assume, you could just place those last calls under the same if, right?

call TimerStart(t, 0.00, false, function DamageEntity.modifyDamageCallback)

Is that necessary? As far as I saw you only use that callback by one function. Why not merging it?

JASS:
    static method create takes nothing returns Damager
        local Damager this = Damager.allocate()
        return this
    endmethod

This function can be inlined if it's merged to
return Damager.allocate()


Oh and one more question (since I haven't read the whole Jasshelper manual yet, blargh)
You tend to have some stub methods which contains nothing. What are those for?
 
Level 11
Joined
Feb 22, 2006
Messages
752
I assume, you could just place those last calls under the same if, right?

No, since the value could possibly be changed in onDamaged().

Is that necessary? As far as I saw you only use that callback by one function. Why not merging it?

Not sure what you mean. I need that timer cuz triggers registered to EVENT_UNIT_DAMAGE fire BEFORE the unit is actually damaged (which is a good thing) and using that 0 second timer essentially "waits" until the unit IS damaged so I can do my damage modification/on final damage stuff.

This function can be inlined if it's merged to
return Damager.allocate()

Actually I don't even need that explicit constructor anymore. I'll get rid of it.

You tend to have some stub methods which contains nothing. What are those for?

Stub methods are meant to be overridden by child structs. That's how people customize the event responses. They extend DamageEntity and Damager with their own structs and override those stub methods to provide their own functionality (like in the examples in the demo map).
 
Level 8
Joined
Aug 2, 2008
Messages
193
Hi,

i like this System and would like to use is in a map.
But could you pls chance or add examples, so we can use the code like a custom-stat system.
I mean:
You can set the custom values (like DamageType, Crit-Chance, Evade etc) for each unit and the System checks by the stored datas in the unit-struct, if the unit has a critical-strike and so on. Important is, that these values can be changed each time.
At the moment the System is very hard for me (wanna use it for a RPG...^^)
 
Level 11
Joined
Feb 22, 2006
Messages
752
Hard-coding that stuff into the system is a bad idea and would make it lose a lot of generality/customizability (is that a word?...).

The demo code already has examples of how to do evasion/crit strike (look in the Blademaster trigger). And every DamageEntity example implements a way of giving a unit custom damage properties/types.

What I'll probably do is update the demo code with some kind of critical strike/evasion/block/w.e example mini-system that abstracts away most of the code dealing with such things. At the very least this would give people an idea of how to implement similar things.

EDIT: Update. I decided against adding the example minisystem for now just cuz it would actually be quite a bit of coding and I wanted to get this update out quickly since it's just a few quick fixes.

@ kricz: if you still can't figure out how to do crit and evasion and stuff after looking at the examples in Blademaster, PM me and I can help you.
 
Last edited:

LeP

LeP

Level 13
Joined
Feb 13, 2008
Messages
537
Hard-coding that stuff into the system is a bad idea and would make it lose a lot of generality/customizability (is that a word?...).
JASS:
    private static method onUnitEntersMap takes unit u returns DamageEntity
        //**** Begin example code...
        local integer id = GetUnitTypeId(u)
        if (id == 'Hpal') then
            return Paladin.create(u)
        elseif (id == 'Obla') then
            return Blademaster.create(u)
        elseif (id == 'hfoo') then
            return Footman.create(u)
        elseif (id == 'hmpr') then
            return Priest.create(u)
        elseif (id == 'ogru') then
            return Grunt.create(u)
        elseif (id == 'nbld') then
            return BanditLord.create(u)
        elseif (id == 'nrog') then
            return Rogue.create(u)
        elseif (id == 'nass') then
            return Assassin.create(u)
        endif
        //**** End example code...
        return DamageEntity.create(u)
    endmethod
....

You can avoid this using a hashtable or something.
just make a static method addUnitType or whatever which takes the unit-id and the struct-id.

DamageEntity.addUnitType('Hpal', Paladin.typeid)

Oh, you should fix the syntax-error in debug mode.
 
Level 11
Joined
Feb 22, 2006
Messages
752
You can avoid this using a hashtable or something.

Yea, I could, but what if I wanted to create different struct types based on something other than unit type ids? If the user wants to create a hashtable himself then that's fine. The point is to let the user decide.

Syntax error in debug mode...ugh. Must be from when I refactored. I'll look into it.
 

LeP

LeP

Level 13
Joined
Feb 13, 2008
Messages
537
Yea, I could, but what if I wanted to create different struct types based on something other than unit type ids? If the user wants to create a hashtable himself then that's fine. The point is to let the user decide.

If thats true, they can change the code, but, for the unit-types, which is the most used situation imo, this is better,
JASS:
    private static method onUnitEntersMap takes unit u returns DamageEntity
        if the.users.condition.with(u) then
            return whatever
        endif
        return DamageEntity.createFromUnit(u)
    endmethod

or, maybe better:
use function interfaces for the condition and the action,
 
Level 11
Joined
Feb 22, 2006
Messages
752
Never used IDDS and never even bothered to look at the code until now (same for the other two scripts). But from my 5 seconds of glancing at the code for IDDS (i.e. scrolling down while reading random lines), it doesn't seem very similar to my system. It's not very object oriented, and that's the main point of Damage Engine.
 
Level 19
Joined
Aug 2, 2008
Messages
442
I noticed that when you enable the damage display; the unit who deals damage has the number float over its head. Is there a way I can change it to show over the head of the damaged unit? This code is too complex for me to edit :p

Also, I know this system is awesome but what can I remove so that I just have the damage numbers appear when a unit is attacked?
 
Last edited:
Level 11
Joined
Feb 22, 2006
Messages
752
You just need the triggers in the folder titled 'System'. Anything that's in between a comment that says "Example code" and another one that says "End example code" you can remove.

For the damage display thing, there's a line of code inside the static method DamageEntity.onUnitFinalDamaged that calls the function CreateTT(). One of the parameters passed is eventDamage.attacker.u. Just change that argument to eventDamage.target.u. For this to work you'll also need to keep the function declaration of CreateTT(), which is in the trigger named "Stuff". You can also create your own text tags instead of using CreateTT() if you want.
 
Level 19
Joined
Aug 2, 2008
Messages
442
Cool thanks. I got the numbers to swap but how do I make it so that the system only generates damage text numbers? Now when I kill units its not getting registered(creeps dont give bounty, hero doesnt get experience). I am asking this because my previous damage text system used Vexorians CSCache and now that it will no longer work I need a new up to date system. Hope you understand

edit: it appears that bounty/exp doesnt work for the test map either. is this intended?
 
Last edited:
Level 2
Joined
Jun 25, 2009
Messages
15
I am also getting a syntax error.

line 7725: Identifier redeclared: "Damager"
JASS:
function Damager_SetLifeSpan takes unit Damager, real lifespan returns nothing

line 8296: ----(previously declared here)
JASS:
struct Damager

Edit, nevermind this error is actually coming from the Caster System... I don't get it. It was working fine before...
There seems to be some syntax confusion concerning the term "Damager" between the two systems. It's beyond me, /shrug.
 
Last edited:
Level 11
Joined
Feb 22, 2006
Messages
752
Ok, I'm basically ready to push this into v1.0.0. After this point, I would really like not to make any more functionality changes (I will definitely not make any changes that either significantly change the API or break backwards compatibility). Everything after v1.0.0 would be bug fixes, maybe some minor add-ons. So if anybody has any suggestions on features they would like to see added or features they think should be changed, speak up now please.

Oh and as always bug reports are welcome.
 
Level 11
Joined
Feb 22, 2006
Messages
752
The demo map now uses TreeSet v0.6.0, which doesn't epic fail when you try to load more than about 5-10 listeners into it. So if you were getting TreeSet from the demo map and wondering why DamageListeners weren't working if you had a lot (and by a lot I mean more than about 5) of them, it's now fixed (I hope).

O, and a quick bug fix to the heal engine module.
 
Level 9
Joined
Oct 17, 2007
Messages
547
Is it possible to make it so that GUI users can make use of this system as well? Basiclaly a configuration option in GUI to adjust the damage detection to work when using GUI custom spells.

I think Advance JASSers such as yourself can prob create a system like this customize to his or her map but people who only use GUI or very little JASS can't even make use of this system fully so it makes sense to make it customizable by GUI right?
 
Level 11
Joined
Feb 22, 2006
Messages
752
Is it possible to make it so that GUI users can make use of this system as well? Basiclaly a configuration option in GUI to adjust the damage detection to work when using GUI custom spells.

That's pretty much impossible unless I inject something into WE that provides GUI support for just this system, which isn't going to happen.

We have like 15 of this thing man, it may be jass, but still not innovative

I think every dds is in JASS (pretty sure it's not possible in GUI...at least not in any useful way). And the point of this is object-oriented event handling, which I haven't seen in any dds I've used before.
 
Level 9
Joined
Oct 17, 2007
Messages
547
I've been looking for a system that just displays the damage amount with text over the damaged unit. It's pretty hard to find one I can work with after the 1.24 patch. I just need to be able to configure it in GUI. I can sorta read JASS, but not to the level that this system is written in. Can you make a simpler version with just the text display and custom spell damage?
 
Level 11
Joined
Feb 22, 2006
Messages
752
If you want damage display with my system, copy the following library into your map (along with Damage Engine):


JASS:
library DamageDisplay requires DamageEngine

globals
    constant integer DAMAGE_TEXT_RED = 0xff
    constant integer DAMAGE_TEXT_GREEN = 0xcc
    constant integer DAMAGE_TEXT_BLUE = 0x00
    constant integer DAMAGE_TEXT_SIZE = 10
    constant integer DAMAGE_TEXT_Z_OFFSET = 100.0
    constant integer DAMAGE_TEXT_FADE = 1.00
    constant integer DAMAGE_TEXT_LIFE = 2.00
endglobals

function CreateTT takes string text, integer r, integer g, integer b, real size, unit u, real z, real fade, real life returns nothing
    local texttag tt = CreateTextTagUnitBJ(text, u, z, size, r * 100 / 255.0, g * 100 / 255.0, b * 100 / 255.0, 0)
    
    call SetTextTagPos(tt, GetUnitX(u) - StringLength(text) * 5, GetUnitY(u), z)
    call SetTextTagVisibility(tt, true)
    call SetTextTagFadepoint(tt, fade)
    call SetTextTagLifespan(tt, life)
    call SetTextTagVelocity(tt, 0.0, 0.05)
    call SetTextTagPermanent(tt, false)
    
    set tt = null
endfunction

struct DisplayListener extends DamageListener
    static constant integer PRIORITY = 10
    
    static method create takes nothing returns DisplayListener
        return DisplayListener.allocate(.PRIORITY)
    endmethod
    
    method onFinalDamage takes EventDamage eventDamage returns nothing
        call CreateTT(I2S(R2I(eventDamage.damage)), DAMAGE_TEXT_RED, DAMAGE_TEXT_GREEN, DAMAGE_TEXT_BLUE, DAMAGE_TEXT_SIZE, eventDamage.target.u, DAMAGE_TEXT_Z_OFFSET, DAMAGE_TEXT_FADE, DAMAGE_TEXT_LIFE)
    endmethod
    
    private static method onInit takes nothing returns nothing
        call DamageEngine.registerDamageListener(DisplayListener.create())
    endmethod
endstruct

endlibrary
 
Level 9
Joined
Oct 17, 2007
Messages
547
Will it detect blizzard standard spells? if I make a custom GUI spell will the damage show when i trigger the damage or do I have to make it show manually using GUI?
 
Top