• 🏆 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 5.A.0.0

This bundle is marked as director's cut. It exceeds all expectations and excels in every regard.
Damage Engine

Three GUI Damage systems for the community of The Hive,
Seven vJass Damage systems for the JASS-heads on their pedestals high,
Nine competing Damage systems, doomed to die,
One for Bribe on his dark throne
In the Land of the Hive where the Workshop lies.
One Damage Engine to rule them all, One Damage Engine to find them,
One Damage Engine to bring them all and in cross-compatibility unite them.


Whether you're looking for a simple DDS (Damage Detection System), need to modify damage or even if you want a complex network of damage pre-and post-processing, this resource is for you. Damage Engine is the most adapted DDS in existence to take full advantage of the new damage detection natives, and is constantly evaluated and scrutinized by both the community and myself for performance improvements, bug fixes and new features alike.

What started with humble beginnings to bring a Unit Indexer-based version of DDS to GUI users to improve on the previous standard (at the time it was Weep's GDDS) would eventually evolve to incorporate other aspects of damage systems out there. @looking_for_help had identified an extremely useful technique with negative spell resistance being used to detect spell damage, and for a time his Physical Damage Detection system became the new standard. It wouldn't be until much later when Damage Engine would resurface and use the same technique in order to be more useful for the community.

Fast forward to 2020, and you'll find not only that cross-compatibility with Weep's and LFH's systems are incorporated, but the most popular DDS systems in existence - even vJass ones - are fully supported via stripped-down API wrappers. All of the functionality of prior DDS systems has been infused into Damage Engine 5.7, and as such the transition to a "one size fits all" DDS is complete. I hope you find this to be useful, and I also hope that it will help you in developing your map to be more dynamic what than you had previously thought possible.

Features

Legacy Code & Requirements

How it works

How to install/upgrade

Video Guides

FAQs

Thanks


  • Damage Type, Attack Type, Weapon Type, Armor Type and Defense Type detection and modification to alter/understand the fundamentals of WarCraft 3's damage processing;
  • Access to the view and change the damage amount before and/or after reduction by armor, armor type and shields.
  • Fully cross-compatible with every major DDS - vJass and GUI alike.
  • Correctly distribute/negate Spirit Link damage.
  • Differentiate between Ranged, Melee, Spell or other types of attack.
  • Does not require any Object Editor data nor Unit Indexer.
  • As of 5.4, it is now completely recursion-proof.
  • Other features:
    • Damage Blocking, reducing, amplifying and/or conversion to healing
    • Does not require you to know nor use Jass NewGen Pack nor any custom script
    • Custom DamageType association available to be set before and/or during damage event
    • Detect when multiple targets were hit simultaneously via DamageEventAOE > 1.
    • Detect when the same unit was hit simultaneously by the same source via DamageEventLevel > 1.
  • Detect damage: use the event "OnDamageEventEqual to <any value>". You have access to the following variables for reference:
    • DamageEventSource - the unit dealing the damage
    • DamageEventTarget - the unit receiving the damage
    • DamageEventAmount - the amount of damage the unit will receive
    • DamageEventPrevAmt - the amount of damage prior to being modified by the game engine.
    • DamageEventAttackT - the attack type (Chaos, Spells, Pierce, etc.)
    • DamageEventDamageT - the damage type - for comprehensive info, click here.
    • DamageEventWeaponT - the weapon type determines if an attack plays some kind of sound on attack (ie. Metal Heavy Bash). It is always NONE for spells and almost always NONE for ranged attacks.
    • DamageEventArmorT - the armor type (Flesh, Stone, Ethereal, etc.)
    • DamageEventDefenseT - the defense type (Hero, Fortified, Unarmored, etc.)
    • DamageEventArmorPierced - if DAMAGE_TYPE_NORMAL, how much armor was set to be ignored by the user.
    • IsDamageSpell, IsDamageRanged, IsDamageMelee - determine the source category of damage dealt.
    • IsDamageCode - Determine if the damage was dealt natively or by the user. This can give incorrect readings if the user has not identified to Damage Engine that it is code damage. Therefore I recommend setting NextDamageType prior to dealing damage.
    • DamageEventType - An integer identifier that can be referenced by you for whatever extra differentiation you need. You can also create your own special damage types and add them to the definitions in the Damage Event Config trigger. If you the unit should explode on death by that damage, use a damage type integer less than 0. If you want the damage to ignore all modifications, use DamageTypePure.
  • To change damage before it's processed by the WarCraft 3 engine: use the event "PreDamageEvent Becomes Equal to <any value>". Whether you just want to use one monolithic trigger for all damage modification like I do in the demo map, or use the different modifier events here, is up to you.
  • To interact with damage after it's been factored for armor and resistances, use "ArmorDamageEvent Becomes Equal to <any value>". This is typically useful for custom shields. If you fully block or absorb DamageEventAmount (setting it to 0 or less), this event doesn't run.
  • To set the DamageEventType before dealing triggered Damage, use:
    - Set NextDamageType = DamageTypeWhatever
    - Unit - Cause...
  • You can modify the following variables from a "PreDamageEvent" trigger:
    • DamageEventAmount
    • DamageEventAttackT/DamageT/WeaponT/ArmorT/DefenseT
    • DamageEventArmorPierced
    • DamageEventType
    • DamageEventOverride - You can set this if you want to remind yourself not to modify the damage further. If you use the UNKOWN damage type from a Unit - Damage Target native or set "NextDamageType = DamageTypePure" before that function, damage modification is skipped.
  • To catch a unit the moment before it would die from damage, use LethalDamageEvent Becomes Equal to 1.00. Instead of modifying the DamageEventAmount here, modify LethalDamageHP to let the system know how much life to keep the unit alive with. Or you can just reference that LethalDamageHP value in order to know how much "overkill" damage was dealt.
  • To catch a unit as soon as the damage is applied against its Hit Points, use AfterDamageEvent Equal to 1.00.
  • Usage of the "<Event> becomes EQUAL to <value>" can be extrapolated as per the below:
    • EQUAL works as it always has - will run for any damage.
    • NOT EQUAL only runs for code damage.
    • LESS THAN only runs for damage from attacks but not coded attacks.
    • LESS THAN OR EQUAL only runs for melee attacks but not coded attacks.
    • GREATER THAN OR EQUAL only runs for ranged attacks but not coded attacks.
    • GREATER THAN only runs for Spell damage but not coded spell damage.

  • Damage Engine 5 and higher requires the latest Warcraft 3 patch (currently 1.32).
  • For people who did not update their game to Reforged / have not updated to Reforged yet. Alternatively, adding the below JASS script to the top of the DamageEngine library SHOULD enable it to work too:

    JASS:
    function BlzGetEventIsAttack takes nothing returns boolean
         return BlzGetEventDamageType() == DAMAGE_TYPE_NORMAL
    endfunction
  • I have created a Pastebin for all information pertaining to Damage Engine 3.8, including the link to download it, via: Damage Engine 3.8.0.0 | HIVE.
  • As of 20 June 2020, JNGP users who are still on WarCraft 3 1.26 can benefit from Damage Engine 3A, which integrates many of the design choices added in various stages of Damage Engine 5. This is a special update which only requires the JASS script be replaced (no new GUI variables added). Can be found here: Damage Engine 3A.0.0.0 and 3.8.0.0 | HIVE

1
Unit attacks or casts a spell. The pure damage is assessed at this point - damage dice, evasion, critical strike. There is currently no event to affect or modify these at source.
→ →
2
The projectile or weapon hits the target unit
→ →
3
EVENT_UNIT_DAMAGING is fired before any modifications to the damage are made.
→ ↓
↓ ←
6
User changes to DamageEventAmount and/or to DamageEventDamageT/AttackT/WeaponT are saved into the WC3 engine.
← ←
5
If any recursive damage is detected from any of those events, it is postponed and the current damage will continue first.
← ←
4
Damage Engine deploys the PreDamageEvent
7
WarCraft 3 processes the user damage.
→ →
8
WarCraft 3 then distributes the user damage into Spirit Link (before armor)
→ →
9
WarCraft 3 runs any interrupting events, such as spirit link or defensive damage like Thorns Aura
→ ↓
↓ ←
12
The EVENT_UNIT_DAMAGED event runs. This is the original event we have always had access to. Damage Engine will either keep using the original variables from the DAMAGING event, or if there was Spirit Link/defensive damage it will freshly retrieve the event values from WC3 and only retain DamageEventPrevAmt.
← ←
11
Once any potential recursive WarCraft 3 damage is processed, the armor/mana shield modifications to the damage are performed.
← ←
10
If such events such as Spirit Link were detected, they fire their own EVENT_UNIT_DAMAGING & EVENT_UNIT_DAMAGED, and DamageEngine processes it along the way for the user.
13
If the damage is above zero, ArmorDamageEvent will run. If any recursive damage is detected, it is postponed.
→ →
14
The user can make modification to the damage here with the after-damage amount.
→ →
15
The user can access DamageEventPrevAmount if they want to know the damage amount before user changes/WarCraft 3 changes.
→ ↓
↓ ←
18
The user can specify whether or not to change LethalDamageHP in order to stop the unit from dying.
← ←
17
If the damage is still above zero, check if the damage is lethal. If so, run LethalDamageEvent 1.00. If any recursive damage is detected, it is postponed.
← ←
16
If the user wants the value that DamageEngine used to have with DamageEventPrevAmt (after WarCraft 3 processing but before user changes) they multiply DamageEventPrevAmt x DamageScalingWC3.
19
Once all modification is done, run OnDamageEvent. If any recursive damage is detected, it is postponed.
→ →
20
After a new damage instance is detected, or the 0.00 timer expires, run AfterDamageEvent. If any recursive damage is detected, it is postponed.
→ →
21
Run all potential recursive Unit - Damage Target function calls in chronological order (first in, first out).

How to install Damage Engine:
  1. Use WarCraft 3 Version 1.32
  2. If you're upgrading from 3.8 or prior, please delete the entire "Damage Engine" category from your map.
  3. Copy & Paste the Damage Engine category from the attached map to your own map.
How do I upgrade to the latest Damage Engine?
- Depending on the complexity, you'll either need to re-copy the Damage Engine category or just the Damage Engine script. Generally, you can use this as a guide:

  • Damage Engine _._._.x - only requires copying of the JASS script
  • Damage Engine _._.x._ - generally only needs copying of the JASS script, but read the patch notes in case there are changes you may want to make to your own code in order to utilize the changes.
  • Damage Engine _.x._._ - delete your current Damage Engine category or manually add the missing variables to your Variable Editor, and update your JASS script.
  • Damage Engine x._._._ - this occurs very infrequently. Typically requires changes to the way Damage Engine needs to be installed and used.

Notes about upgrading from Damage Engine 4.0 or prior:
  • Revert any custom Object Editor changes made (such as Life Drain reversal, Spell Damage Reduction inversion, etc).
  • You can safely delete the custom spells "Spell Damage Detection" and "Cheat Death Ability"
  • You can delete the Unit Indexer trigger if you do not use it or would prefer to use a different indexer.
  • You should delete any "Mana Shield fix" or "Finger of Death fix" you may have imported, as well as revert any Object Editor data that was required to make it work, as these are no longer needed.
  • !!!DEPRECATED FEATURE!!! As of 5.4, do not bother to take any recursive damage mitigation - Damage Engine will now handle all of that for you!
  • !!!DEPRECATED FEATURE!!! Do not use "ClearDamageEvent" - it does nothing. Just delete it.
  • !!!DEPRECATED FEATURE!!! Do not use "NextDamageOverride" - set NextDamageType = DamageTypePure instead.
  • !!!CHANGED FEATURE!!! If the system detects code damage and the user did not specify it as any particular DamageEvenType, the system will assign it DamageTypeCode automatically.
  • !!!CHANGED FEATURE!!! DamageModifierEvent 1.00-3.00 now run prior to armor reduction. This enables the user to modify the damage before armor and resistance changes are applied - also before Mana Shield and Anti-Magic shell kick in, so no more need for special triggers.


  • Q: Why am I getting a bunch of 'trigger was disabled' errors when I save my map?
  • A: This issue is not unique to Damage Engine, but to all vJass resources. Blizzard has taken the very confusing decision to make JassHelper 'disabled' by default, meaning that every new map that uses a vJass resource has to manually enable JassHelper. Please see this thread if you want to know where to find the Enable JassHelper option.
    .
  • Q: How can I detect when a unit gets damaged?
  • A: Create a trigger with the event: "Game - Value of Real Variable <DamageEvent> becomes Equal to 1.00".
    • Use the following custom variables to reference the event responses:
      • DamageEventSource - the unit dealing the damage
      • DamageEventTarget - the unit getting damaged
      • DamageEventAmount - how much damage is being dealt
      • DamageEventAttackT - which attack type was used by DamageEventSource to damage DamageEventTarget
      • DamageEventDamageT - which damage type was used to damage the target (ie. UNIVERSAL for ultimate damage, or NORMAL for damage that gets reduced by armor).
      • DamageEventDefenseT - which defense type does the target unit have (ie. Hero, Fortified, Unarmored).
      • DamageEventArmorT - which armor type does the target unit have (ie. Flesh, Ethereal, Stone).
      • DamageEventPrevAmt - what the value of the damage was before being modified by armor, ethereal/item bonuses or user changes.
        .
  • Q: How do I modify the damage that is dealt to a unit?
  • A: Create a trigger with the event: "Game - Value of Real Variable <PreDamageEvent> becomes Equal to <any value>".
    • You can change the following variables to affect the damage that will be dealt:
      • DamageEventAmount - how much damage will be dealt (before armor reductions)
      • DamageEventAttackT - which attack type will be used by DamageEventSource to damage DamageEventTarget
      • DamageEventDamageT - which damage type will be used to damage the target.
      • DamageEventDefenseT - which defense type should the target unit have during this attack.
      • DamageEventArmorT - which armor type should the target unit have during this attack.
      • DamageEventArmorPierced - how much armor value to ignore when dealing this damage (applies to DAMAGE_TYPE_NORMAL only, otherwise all armor is ignored).
        .

  • Q: How do I deal Pure damage to a unit (bypassing armor/skipping user modification)?
  • A: Use the following actions:
    • Set NextDamageType = DamageTypePure
    • Unit - Cause Source to damage Target for Amount using attack type Spells and damage type Universal
      .

  • Q: How do I protect against recursive damage?
  • A: Damage Engine 5.4 and above is completely recursion-proof, using vJass hooks to detect registered Damage Event triggers.
    .

  • Q: I've been using <insert Damage system here>. Can I use those with Damage Engine?
  • A: Better - Damage Engine has integrated cross-compatibility with all other approved Damage systems and even the major ones from outside of Hiveworkhop.
    .

  • Q: Can I cause an attack to 'Miss' its target?
  • A: Kind of. Ranged attacks will still explode on the target, and on-hit effects will still apply, but you can do the following:
    • Use the event "PreDamageEvent becomes Equal to 1.00"
    • Use the following actions:
      • Set DamageEventAmount = 0.00
      • Set DamageEventArmorT = ARMOR_TYPE_NONE
      • Set DamageEventWeaponT = WEAPON_TYPE_NONE
    • Setting the weapon type and armor type to none like the above will stop any on-hit sounds from playing. When the Peasant attacks in the demo map, this is the trick I'm using. Instead of saying "MISSED!" I have the Floating Text saying "FAIL!" because - again - it's not exactly a "miss".

Thank you to Blizzard for continuing to work on this amazing game to give us awesome new natives that have the best possible control over incoming damage. Damage Engine brings that power to GUI. Also, a very special thank you to @KILLCIDE for getting me motivated to start up the 5.0 project in the first place.

Thank you to the users of this system who have helped me mold this project into the stable, powerful form it is in today!

For versions 3.8 and prior:

Thank you @looking_for_help for finding the spell damage detection method used in Damage Engine 3 - it was the greatest find since the undefend bug.

Thanks to Jesus4Lyf and @Nestharus for building the inspiration that originally led me to create DamageEngine.

Thank you Wietlol and looking_for_help for challenging me on this project to integrate solutions to problems I had not been made aware of, such as the importance of an After-Damage Event.

Thanks to @Spellbound for several crucial bug reports.


Damage Engine Config

Damage Engine vJass

Damage Engine Lua

Changelog


  • Damage Engine Config
    • Events
      • Map initialization
      • Game - DamageModifierEvent becomes Greater than 0.00
      • Game - LethalDamageEvent becomes Less than or equal to 0.00
      • Game - DamageEvent becomes Not equal to 0.00
      • Game - AfterDamageEvent becomes Less than 0.00
      • Game - AOEDamageEvent becomes Greater than or equal to 0.00
      • Game - SourceDamageEvent becomes Equal to 0.00
      • Game - PreDamageEvent becomes Equal to 0.00
      • Game - ArmorDamageEvent becomes Equal to 0.00
      • Game - ZeroDamageEvent becomes Equal to 0.00
    • Conditions
    • Actions
      • -------- You can add extra classifications here if you want to differentiate between your triggered damage --------
      • -------- Use DamageTypeExplosive (or any negative value damage type) if you want a unit killed by that damage to explode --------
      • -------- - --------
      • -------- The pre-defined type Code might be set by Damage Engine if Unit - Damage Target is detected and the user didn't define a type of their own. --------
      • -------- "Pure" is especially important because it overrides both the Damage Engine as well as WarCraft 3 damage modification. --------
      • -------- I therefore gave the user "Explosive Pure" in case one wants to combine the functionality of the two. --------
      • -------- - --------
      • Set VariableSet DamageTypePureExplosive = -2
      • Set VariableSet DamageTypeExplosive = -1
      • Set VariableSet DamageTypeCode = 1
      • Set VariableSet DamageTypePure = 2
      • -------- - --------
      • Set VariableSet DamageTypeHeal = 3
      • Set VariableSet DamageTypeBlocked = 4
      • Set VariableSet DamageTypeReduced = 5
      • -------- - --------
      • Set VariableSet DamageTypeCriticalStrike = 6
      • -------- - --------
      • Custom script: call DamageEngine_DebugStr()

BribeFromTheHive/DamageEngine

Lua 1.0.2.3 - Fixed to match adjustment made in vJass version 5.4.2.3.
Lua 1.0.2.2 - Fixed to match adjustment made in vJass version 5.4.2.2.
Lua 1.0.2.1 - Fixed to match adjustment made in vJass version 5.4.2.1.
Lua 1.0.2.0 - Added support for Lua Fast Triggers ([Lua] Ridiculously Fast Triggers). Fixed an issue where the AfterDamageEvent wasn't always timed the correct way like it was in the JASS verion.
Lua 1.0.1.0 - Fixed encapsulation issue and recursion issue with DamageEngine_inception. Now hooks UnitDamageTarget.
Lua 1.0.0.0 - Release based on Damage Engine 5.4.2.0

5.9.0.0 - Added the following clearer event names to make things less confusing for new users:
  • PreDamageEvent - can be used in place of DamageModifierEvent pre-armor modification
  • ArmorDamageEvent - can be used in place of DamageModifierEvent post-armor modification
  • OnDamageEvent - can be used instead of a non-zero DamageEvent
  • ZeroDamageEvent - can be used instead of a zero damage DamageEvent
  • SourceDamageEvent - runs at the same time as AOEDamageEvent, but doesn't need to hit multiple units.
Added "DamageFilterRunChance" - odds for the trigger to BE run (works inversely to DamageFilterFailChance).
Shortened the Configuration trigger so that it focuses primarily on what the user can modify.
Organized all variables into categories to help users better understand what does what.
Installation or updating from a previous version will require re-copying the entire Damage Engine folder.
Updated the demo map's text tag production to include a new custom update for ArcingTextTag, thanks to @Ugabunda and @Kusanagi Kuro.
Side note - the Demo Map's triggers have been heavily cleaned up and will now no longer cause crashes when being imported into a new map.
5.8.0.0 -
  • Added a new functionality to the AOEDamageEvent, which allows it to fire even when only one unit is hit, if the AOEDamageEvent is registered as "Not Equal" instead of "Equal to". This is useful in a very specific scenario where an AfterDamageEvent may not be able to be relied upon to properly deallocate data from a running instance that needs to be able to function when multiple units are hit, but also needs to not fail when only one unit is hit.
  • Added additional filters for GUI users to avoid using trigger conditions in even more scenarios:
    • DamageFilterSource/TargetI (has item)
    • DamageFilterSource/TargetA (has ability)
    • DamageFilterSource/TargetC (has a certain classification, like hero or Tauren)
    • DamageFilterFailChance - odds for the trigger to not be run (ideal for critical strike or evasion)
  • Provided a way for GUI to un-register a Damage Event by setting "RemoveDamageEvent" to true from within their trigger's actions.
  • Moved the CreateTimer/CreateTrigger/CreateGroup calls that had been included in the globals block down to the onInit block as per request of @Ricola3D
  • Minor performance improvements thanks to @BLOKKADE
5.7.1.2 - Fixed an issue with armor penetration sometimes bugging out.
5.7.1.1 - Fixed an issue with the eventFilter not retaining its value during an AOE event. Fixed an issue with eventFilter when USE_MELEE_RANGE was set to false. Both issues reported by @lolreported
5.7.1.0 -
I have fixed several potential points of failure reported by multiple users that stopped Damage Engine from working for the rest of the game. In any case there should no longer be ANY SITUATION where Damage Engine just "stops working", even in ways I can't predict. The most likely issue was with DamageScalingWC3/User having possible 0-division errors.​
Fixed the "configured" issue reported by @lolreported where manual configuration didn't work unless the damage and attack type checks were initialized tto -1.​
In addition to these fixed bugs, I have added several more static ifs so that advanced users have more control over getting rid of features they might not care about.​

5.7.0.3 - Fixed the issue reported by @KitsuneTailsPrower wherein the DamageInterface extension wasn't working. This needed to be fixed both in the Damage Engine source as well as the DamageInterface plugin itself.
5.7.0.2 - Fixed the issue reported by @Wazzz where the armor reduction wasn't taken into consideration. Actually there was a much bigger flaw that I had overlooked that was prompting this.
5.7.0.1 - Improved the logic of the 0 damage event.
5.7.0.0:

  • Usage of the "DamageEvent becomes EQUAL to 1.00" now can be extrapolated further than ever before:
    • EQUAL works as it always has.
    • NOT EQUAL only runs for code damage.
    • LESS THAN only runs for damage from attacks.
    • LESS THAN OR EQUAL only runs for melee attacks.
    • GREATER THAN OR EQUAL only runs for ranged attacks.
    • GREATER THAN only runs for Spell damage.
  • Fully adapted Damage Engine to work with every other major DDS
  • Rewrote the internal script to use vJass structs: Damage and DamageTrigger.
  • Changed some of the vJass API. You can find the API listed in the Damage Engine trigger. Notably:
    • I removed UnitDamageTargetEx. You can replace this with Damage.apply.
      • The reason for this change is because of cross-compatibility. Rising Dusk's IDDS uses a different set of parameters for this function, so I removed it from my library to allow this to work seamlessly.
    • TriggerRegisterDamageEvent -> TriggerRegisterDamageEngine
    • RegisterDamageEvent -> RegisterDamageEngine
      • The reason for the above two changes is, like for UnitDamageTargetEx, because Rising Dusk's IDDS uses them. I don't want to make the same mistake I did with Table's API and preferred to walk back my API choices before things got out of hand again.
  • Various performance tweaks, bug fixes and re-commenting of variables.
  • Recursive damage is now processed more intelligently and possibly be more performance-friendly.
  • Adapted the cross-compatibility libraries for Weep and LFH's systems to use textmacros to insert themselves into Damage Engine (this might have been in the 5.6 update, but these two updates were both tailored to achieve similar goals).
5.6.2.0 - Fixed a bug with Damage modification and laid groundwork for a bunch of optional vJass compatibility addons.
5.6.1.0 - Patchwork on Melee/Ranged detection, recursion tracking. Also added the ability to modify damage from a DamageEvent to make it easier on beginners.
5.6.0.1 - Fixed an issue where the DamageEventType for recursive damage that used NextDamageType would always default to DamageTypeCode.
5.6.0.0
Rewrote a significant amount of the internal code so that struct and GUI syntax both work - and are synchronized with each other. vJass-exclusive users can disable the GUI synchronization if they don't use any GUI damage events in their maps.​
Four new variables must be added to your variable editor:​
  • boolean NextDamageIsAttack
  • boolean NextDamageIsMelee
  • boolean NextDamageIsRanged
  • integer NextDamageWeaponT
Struct syntax should not need too much introduction - Damage.index is the triggering event ID, and the syntax is Damage.index.amount/source/target/etc. To initialize a JASS damage event, use:​
JASS:
function RegisterDamageEvent takes code c, string eventName, real value returns nothing
The string is simplified: "Modifier", "" (for simple DamageEvent), "After", "Lethal", "AOE"​
Finally, a neat QOL improvement is that I have assigned weight to each of the events. When registering an event, you can include numbers different than 1, 2, 3 or 4 (for modification) or just the plain "1" for the others. Now you can set your own sequencing and use 1.5, 3.14 or even -1 to give an even more extreme priority to something. Lower numbers run first, higher ones last.​
5.5.0.0 - Added support for the new native BlzGetEventIsAttack via "IsDamageAttack". Also updated the Config trigger to make importing a bit easier
5.4.2.3 - Fixed a mis-flag of the IsDamageSpell value when not being actual spell damage.
5.4.2.2 - Actually fixed the Cold Arrows issue (division by 0.00001 or something ...somehow... either way, it is fixed).
5.4.2.1 - A fix which should hopefully quell the recent reports of damage events failing in complex situations involving Cold Arrows.
5.4.2.0 - A ton of fixes to repair the issues plaguing Sunken City and anyone else who might be pushing this engine well beyond what I imagined it would be used for. Also added a couple of variables intended to be used to ricochet damage: CONVERTED_ATTACK_TYPE and CONVERTED_DAMAGE_TYPE. Check the demo map for how they can be used in a Unit - Damage Target action.
5.4.1.0 - The "Inception" update. Advanced users can interact with Damage Engine via custom script to set DamageEvent_inception = true to allow their damage to potentially go recursive (to a fixed extent).
5.4.0.1 - Hotfixed that modifiers 2 and 3 weren't running.
5.4.0.0 - By using an innovative approach of hooking TriggerRegisterVariableEvent, I've permanently eliminated all risks of recursion in the engine.
5.3.0.1 - Fixed unexpected behavior with DamageTypePure when it is affected by Anti-Magic Shell or Mana Shield. DamageTypePure now no longer ignores DamageScalingWC3.
5.3.0.0 - Fixed an issue with AfterDamageEvent sometimes being delayed. Added DamageScalingUser to track the ratio of user modified damage, as well as DamageEventArmorPierced which allows the user to define how much armor to ignore when working with DAMAGE_TYPE_NORMAL.
5.2.0.1 - Fixed an issue where with the final unit in a Spirit Link chain or the retaliating damage of Thorns/Carapace would not deploy an AfterDamageEvent. Also fixed an issue where AfterDamageEvent would still fire from DAMAGE_TYPE_UNKNOWN if it was greater than 0. Simply copy over the JASS from this post in order to update your own implementation.
5.2.0.0

  • Now features DamageEventArmorT and DamageEventDefenseT, which pull from the target unit's Object Editor data in order to allow you more complete access to detect and even MODIFY those defenses. Changes must be made in a DamageModifierEvent, and they are reverted as soon as armor is calculated.
  • Re-introduced AfterDamageEvent, which is the moment after the unit's life is changed, but before any recursive damage has run.

5.1.3.1 - Bug fixes and performance improvements. No, really. Fixed an issue with the DAMAGED event running even though it was turned off (who would've guessed that?)
5.1.3.0 - Engine re-tooling to improve accuracy and get Spirit Link/Defensive damage out of hardcoded mode - it will now work even in circumstances I haven't tested for (in case those weren't the only issues). Also fixed the Is Unit Moving resource.
5.1.2.1 - Fixed an issue with Spiked Carapace and Thorns Aura where the melee attacker would not get recorded correctly. This required the same fix as I needed to apply for the initial target in a spirit link chain.
5.1.2.0 - Tweaked recursion and fixed a few bugs. Re-introduced the zero damage event now that patch 1.31.1 brought it back.
5.1.1.1 - Minor tweak to Spirit Link in rare situation.
5.1.1.0 - Fixed issues related to Spirit Link. Now works intuitively as expected.
5.1.0.0 - Crazy improvements - check out the details in "How to upgrade from Damage Engine 4.0 or earlier" and "How to use Damage Engine 5.1"
5.0.0.0 - Oh man. Where do I even start?
  • You can now set/compare DamageEventDamageT, DamageEventAttackT or DamageEventWeaponT
  • No longer needs Unit Indexer nor any custom Object Editor data nor modifications.
  • Requires WarCraft 3 1.31 or higher.
  • Changed vanilla JASS code to vJass to clean up a lot of things such as making certain variables private.
  • Look for more details in "How to upgrade from Damage Engine 4.0 or earlier"

4.0.0.0 - Never officially released, but was the first iteration which used SetEventDamage.
For 3.8.0.0 and prior, see: Damage Engine 3.8.0.0 | HIVE


Cross-Compatibility:

BribeFromTheHive/DamageEngine

Keywords:unit indexer, damage detection, damage event, weep, nestharus, looking_for_help, EVENT_PLAYER_UNIT_DAMAGED, damage engine, spell, physical, EVENT_PLAYER_UNIT_DAMAGED, attacktype, damagetype, weapontype, armortype, defensetype, BlzSetEventDamage
Previews
Contents

Damage Engine Demo Map (Map)

Lua Damage Engine 2.0.0.0 (Map)

Reviews
23:20, 11th Jan 2015, BPower Criticism: On the one hand Damage Engine offers extremely high utility to every spell, system and map maker independent of the coding style ( GUI, JASS, vJass, .... ) on the other hand it's very easy to import and...

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Do I install this system together with Unit Indexer or not because I already have your GUI Unit Events and in the installation of the GUI Unit Events, you told me to delete unit indexer from the map
This system doesn't use any "custom value of unit" fields so you can safely use this with any indexing system. Unit Event would be the recommended choice.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Not sure if it's intentional, but the very first damage event will always have udg_DamageEventAOE equals to 1, because that variable is initialized to 1 at the beginning of the game. After the first damage event, it resets to 0 and works normally from then on.
Thanks for the catch. The way I would want it to work is to always be 1 for the first unit hit, so it looks like I need to fix that in the code.
 
Level 3
Joined
Aug 29, 2007
Messages
28
Thanks for the catch. The way I would want it to work is to always be 1 for the first unit hit, so it looks like I need to fix that in the code.

no problem.

By the way i was trying to figure out if we can get the initial target of an attack, when the attack is an AOE one, i wasn't able to, I resorted to using the event "unit is attacked" and i would store the "attacked unit" & "attacking unit" in a hashtable, and use that with the damage engine event to figure out if udg_DamageEventTarget is actually the target of the AOE attack or not.

Not sure if the damage engine already has that information or not, from what i can tell, the order in which the damage engine events take place for AOE damage is random, like we can't rely on the ordering (or value) of udg_DamageEventAOE or udg_DamageAOEGroup.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
no problem.

By the way i was trying to figure out if we can get the initial target of an attack, when the attack is an AOE one, i wasn't able to, I resorted to using the event "unit is attacked" and i would store the "attacked unit" & "attacking unit" in a hashtable, and use that with the damage engine event to figure out if udg_DamageEventTarget is actually the target of the AOE attack or not.

Not sure if the damage engine already has that information or not, from what i can tell, the order in which the damage engine events take place for AOE damage is random, like we can't rely on the ordering (or value) of udg_DamageEventAOE or udg_DamageAOEGroup.

It is certainly random, sure, but it makes me wonder if an Orb being added to the siege unit will mark every unit hit by it, or if it only marks the targeted unit. I'll run some tests later today.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Any LUA updates? That's the version in my map :(
I was scrolling through the changelog and most of the stuff I've done since the last Lua update was just trying to make vJass and GUI be less shitty. In Lua you have access to Lua Fast Triggers where your conditions are called via function call rather than trigger evaluation.

Nevertheless, there are a handful of useful changes I could implement that would allow event priorities such as what I added in 5.6, and then some of the additional GUI variables might want to get some love too.

Maybe I should also allow both Lua and GUI syntax to coexist without requiring Lua people to use the udg_ variable syntax.
 
Level 6
Joined
Jul 12, 2017
Messages
139
I don't know why but my map is very laggy when unit with bonus armor get hit by several enemies. Is there any way to fix this? I think there's more problem too cuz my map gets very laggy once something get hit from time to time. I don't think I mess up with my trigger tho, maybe I need to do something with damage detection trigger itself?
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
I don't know why but my map is very laggy when unit with bonus armor get hit by several enemies. Is there any way to fix this? I think there's more problem too cuz my map gets very laggy once something get hit from time to time. I don't think I mess up with my trigger tho, maybe I need to do something with damage detection trigger itself?
General rule of thumb is to update your damage engine to the latest version.

If there is still lag it is probably caused by an outdated version of IsUnitMoving or some other DDS resource in your map.
 
Level 6
Joined
Jul 12, 2017
Messages
139
General rule of thumb is to update your damage engine to the latest version.

If there is still lag it is probably caused by an outdated version of IsUnitMoving or some other DDS resource in your map.

I already updated it the latest ver and it still lagging. Here's the example of my triggers in this map

  • Great Blizzard Antonidas
    • Events
      • Game - DamageModifierEvent becomes Equal to 1.00
    • Conditions
      • (DamageEventTarget belongs to an enemy of (Owner of DamageEventSource).) Equal to True
      • IsDamageSpell Equal to True
      • (Level of Great Blizzard (Antonidas) for DamageEventSource) Greater than or equal to 1
      • (Current order of DamageEventSource) Equal to (Order(blizzard))
    • Actions
      • Set VariableSet NextDamageType = DamageTypePure
      • Set VariableSet Real1 = (Real((Intelligence of DamageEventSource (Include bonuses))))
      • Unit - Cause DamageEventSource to damage DamageEventTarget, dealing (Real1 x (0.00 + (0.20 x (Real((Level of Great Blizzard (Antonidas) for DamageEventSource)))))) damage of attack type Spells and damage type Normal
  • Sword Swing
    • Events
      • Game - DamageModifierEvent becomes Equal to 1.00
    • Conditions
      • IsDamageSpell Equal to False
      • (DamageEventSource has buff Sword Swing (Sargeras) ) Equal to True
    • Actions
      • Set VariableSet NextDamageType = DamageTypePure
      • Animation - Play DamageEventSource's attack slam 2 animation
      • Set VariableSet Point1 = (Position of DamageEventTarget)
      • Set VariableSet Real1 = (Real((Strength of DamageEventSource (Include bonuses))))
      • Set VariableSet Real2 = (Real((Intelligence of DamageEventSource (Include bonuses))))
      • Custom script: set bj_wantDestroyGroup = true
      • Unit Group - Pick every unit in (Units within 300.00 of Point1.) and do (Actions)
        • Loop - Actions
          • Set VariableSet TempUnit = (Picked unit)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (TempUnit belongs to an enemy of (Owner of DamageEventSource).) Equal to True
              • (TempUnit is alive) Equal to True
            • Then - Actions
              • Unit - Cause DamageEventSource to damage TempUnit, dealing ((125.00 x (Real((Level of Sword Swing (Sargeras) for DamageEventSource)))) + (Real1 x (3.00 + (0.50 x (Real((Level of Sword Swing (Sargeras) for DamageEventSource))))))) damage of attack type Spells and damage type Normal
            • Else - Actions
      • Unit - Set life of DamageEventSource to ((Life of DamageEventSource) + ((150.00 x (Real((Level of Doom Blade (Kazzak) for DamageEventSource)))) + (Real1 x (2.50 + (0.50 x (Real((Level of Sword Swing (Sargeras) for DamageEventSource))))))))
      • Unit - Set mana of DamageEventSource to ((Mana of DamageEventSource) + ((75.00 x (Real((Level of Sword Swing (Sargeras) for DamageEventSource)))) + (Real2 x (1.25 + (0.25 x (Real((Level of Sword Swing (Sargeras) for DamageEventSource))))))))
      • Custom script: call RemoveLocation(udg_Point1)
      • Unit - Remove Sword Swing (Sargeras) buff from DamageEventSource
  • Circle of Fire 1
    • Events
      • Game - DamageModifierEvent becomes Equal to 1.00
    • Conditions
      • (Unit-type of DamageEventSource) Equal to Circle of Fire (Varimathras) Level 1 (large)
      • IsDamageSpell Equal to True
    • Actions
      • Set VariableSet NextDamageType = DamageTypePure
      • Set VariableSet Real1 = (Real((Strength of PlayerHero[(Player number of (Owner of DamageEventSource))] (Include bonuses))))
      • Unit - Cause DamageEventSource to damage DamageEventTarget, dealing (Real1 x (2.50 + (2.50 x (Real((Level of Circle of Fire (Varimathras) for PlayerHero[(Player number of (Owner of DamageEventSource))])))))) damage of attack type Spells and damage type Normal
      • Unit - Set mana of DamageEventTarget to ((Percentage mana of DamageEventTarget) - (1.00 + (Real((Level of Circle of Fire (Varimathras) for PlayerHero[(Player number of (Owner of DamageEventSource))])))))%
Maybe because I used nextdamagetype = damagetypepure a lot?
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Try this:

In your first trigger change the event comparison to Less Than (so it only runs on attack).

In the second trigger use Greater Than so it only runs for spells.

You can then drop the IsDamageSpell boolean from both trigger conditions.

Not sure what kind of a performance delta this would have for you so let me know how it goes.
 
Level 6
Joined
Jul 12, 2017
Messages
139
Like this

  • Great Blizzard Antonidas
    • Events
      • Game - DamageModifierEvent becomes Less than 1.00
    • Conditions
      • (DamageEventTarget belongs to an enemy of (Owner of DamageEventSource).) Equal to True
      • IsDamageSpell Equal to True
      • (Level of Great Blizzard (Antonidas) for DamageEventSource) Greater than or equal to 1
      • (Current order of DamageEventSource) Equal to (Order(blizzard))
    • Actions
      • Set VariableSet NextDamageType = DamageTypePure
      • Set VariableSet Real1 = (Real((Intelligence of DamageEventSource (Include bonuses))))
      • Unit - Cause DamageEventSource to damage DamageEventTarget, dealing (Real1 x (0.00 + (0.20 x (Real((Level of Great Blizzard (Antonidas) for DamageEventSource)))))) damage of attack type Spells and damage type Normal
  • Sword Swing
    • Events
      • Game - DamageModifierEvent becomes Greater than 1.00
    • Conditions
      • IsDamageSpell Equal to False
      • (DamageEventSource has buff Sword Swing (Sargeras) ) Equal to True
    • Actions
      • Set VariableSet NextDamageType = DamageTypePure
      • Animation - Play DamageEventSource's attack slam 2 animation
      • Set VariableSet Point1 = (Position of DamageEventTarget)
      • Set VariableSet Real1 = (Real((Strength of DamageEventSource (Include bonuses))))
      • Set VariableSet Real2 = (Real((Intelligence of DamageEventSource (Include bonuses))))
      • Custom script: set bj_wantDestroyGroup = true
      • Unit Group - Pick every unit in (Units within 300.00 of Point1.) and do (Actions)
        • Loop - Actions
          • Set VariableSet TempUnit = (Picked unit)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (TempUnit belongs to an enemy of (Owner of DamageEventSource).) Equal to True
              • (TempUnit is alive) Equal to True
            • Then - Actions
              • Unit - Cause DamageEventSource to damage TempUnit, dealing ((125.00 x (Real((Level of Sword Swing (Sargeras) for DamageEventSource)))) + (Real1 x (3.00 + (0.50 x (Real((Level of Sword Swing (Sargeras) for DamageEventSource))))))) damage of attack type Spells and damage type Normal
            • Else - Actions
      • Unit - Set life of DamageEventSource to ((Life of DamageEventSource) + ((150.00 x (Real((Level of Doom Blade (Kazzak) for DamageEventSource)))) + (Real1 x (2.50 + (0.50 x (Real((Level of Sword Swing (Sargeras) for DamageEventSource))))))))
      • Unit - Set mana of DamageEventSource to ((Mana of DamageEventSource) + ((75.00 x (Real((Level of Sword Swing (Sargeras) for DamageEventSource)))) + (Real2 x (1.25 + (0.25 x (Real((Level of Sword Swing (Sargeras) for DamageEventSource))))))))
      • Custom script: call RemoveLocation(udg_Point1)
      • Unit - Remove Sword Swing (Sargeras) buff from DamageEventSource
  • Btw, my first trigger is spell (blizzard) and my second trigger is basic attack do AOE so it supposed to be vice versa right?
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
So here's the thing:

When you use the Greater Than/less than, you don't need to additionally check for IsDamageSpell being true or false (because the conditions won't even be evaluated if spell damage is detected and you're using a Less Than event, or for physical damage when you use a Greater Than event).

I proposed you use the event method in order to try to save you a tiny bit of performance.
 
Level 3
Joined
Sep 9, 2009
Messages
658
I have a spell where a bunch of dummy units do an attack ground. The dummy units do spell type damage so I made a trigger where if the unit type of udg_DamageEventSource is the unit type of the dummy, then I set the damage type to explosive but that method doesn't seem to work. The enemies always stay at 1 hp.
Is there any other way to fix this?

Edit: Oh, sorry. I just realized the expiration timer for the dummy was too short.
 
Can someone check my math? I have a trigger with the following action:
set udg_DamageEventAmount=( udg_DamageEventAmount * ( 0.80 - ( 0.10 * I2R(GetUnitAbilityLevelSwapped('A011', udg_DamageEventTarget)) ) ) )

With the 'A011' ability not yet learned the damage should be reduced by 20% right? Somehow it seems like a lot more reduction then a 20% reduction in game

and with A011 at level 3 it should be 50% right?

edit: I think the issue was elsewhere but a math check never hurts
 
Last edited:
Level 12
Joined
May 16, 2020
Messages
660
I have troubles with the compatibility patch for Damage Interface. This is what I did:
  1. Create custom text trigger and copy the code from BribeFromTheHive/DamageEngine into it
  2. Delete the original entry from DamageInterface
This gives me the error "Undeclared variable evade" - what am I doing wrong..?

EDIT:
I took the Damage Interface from New Bonus v2.0. But it seems like there are differences between the Damage Interface from New Bonus 2.0 and the standalone version. Table for example is not included in the New Bonus 2.0 version. Maybe relevant for you @chopinski

EDIT2:
Same error though with the standalone version.
 
Last edited:

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
I have troubles with the compatibility patch for Damage Interface. This is what I did:
  1. Create custom text trigger and copy the code from BribeFromTheHive/DamageEngine into it
  2. Delete the original entry from DamageInterface
This gives me the error "Undeclared variable evade" - what am I doing wrong..?

EDIT:
I took the Damage Interface from New Bonus v2.0. But it seems like there are differences between the Damage Interface from New Bonus 2.0 and the standalone version. Table for example is not included in the New Bonus 2.0 version. Maybe relevant for you @chopinski

EDIT2:
Same error though with the standalone version.

I am not sure if @chopinski has updated that library yet, but you can use the legacy version of that script which I have here if not:

Create chopinkski's Damage Interface.j · BribeFromTheHive/DamageEngine@1f72c37
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Unfortunately I think that's the same code I used already - gives me the same error ("Undeclared variable evade").

You need to update the following scripts to use the ones that chopinski wrote for Damage Interface 1.7:

Evasion
CriticalStrike
SpellPower
LifeSteal
SpellVamp

Simply updating the Damage Interface alone won't do it since he's changed the API several times probably causing the error you get.

If that doesn't fix it then you will need to ask chopinski to update the Bonus system to use his new API and do any debugging.


No I see what it is, there is an integrated global variable called "evade" included in both the older and the newer versions of damage interface. Not sure how I missed this.

Gimme a moment and I will produce an update.

Update:

The method in Evasion which is called onDamage needs to be changed to:

JASS:
            static method OnDamage takes nothing returns nothing
                local unit     src    = Damage.index.source
                local unit     tgt    = Damage.index.target
                //----------------------------------------------
                local real     damage = Damage.index.damage
                //----------------------------------------------
                local integer  sIdx   = GetUnitUserData(src)
                local integer  tIdx   = GetUnitUserData(tgt)
                //----------------------------------------------

                if damage > 0 and not (NeverMiss[sIdx] > 0) then
                    if GetRandomReal(0, 100) <= EvasionChance[tIdx] or GetRandomReal(0, 100) <= MissChance[sIdx] then
                        set udg_DamageEventOverride = true
                        set EvasionSource = src
                        set EvasionTarget = tgt
                        set EvadedDamage  = damage
   
                        call TriggerEvaluate(Evasion)
                        set Damage.index.weaponType = WEAPON_TYPE_WHOKNOWS
                        set Damage.index.damage = 0.00
                        call EvasionText(src, "miss", 1.5, 255, 0, 0, 255)
   
                        set EvasionSource = null
                        set EvasionTarget = null
                        set EvadedDamage  = 0.0
                    endif
                endif
            endmethod

Or copy from here: BribeFromTheHive/DamageEngine
 
Last edited:
Level 20
Joined
May 16, 2012
Messages
635
Oh I see what's happening. That variable was introduced in version 1.5(?) so that when an attack is evaded the system will not process functions registered for attack damage events, simulating an evasion event a little better and saving up process time even more. Since I made the Evasion struct public in the last patch i can get rid of it and implement it in a way so that if you have the Evasion system it will try to do what I described and wouldn't conflict with Bribe's plugin like that. When i have a little more free time i will update the system. Regarding the version used by New Bonus, it's outdated, but even so, the 1.7 updated do not requeires any change in it, even for the expanded version, so it should not be a problem. I will update both just to be safe tho.

Edit: That adjustment from Bribe might still be necessary, have to check. @Bribe you might want to take a look into the Critical Strike system as well and see if it also requires some internal change. If you can wait a little before releasing another plugin that might save you some work, i promise it wont take long.
 
Last edited:

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Oh I see what's happening. That variable was introduced in version 1.5(?) so that when an attack is evaded the system will not process functions registered for attack damage events, simulating an evasion event a little better and saving up process time even more. Since I made the Evasion struct public in the last patch i can get rid of it and implement it in a way so that if you have the Evasion system it will try to do what I described and wouldn't conflict with Bribe's plugin like that. When i have a little more free time i will update the system. Regarding the version used by New Bonus, it's outdated, but even so, the 1.7 updated do not requeires any change in it, even for the expanded version, so it should not be a problem. I will update both just to be safe tho.

Edit: That adjustment from Bribe might still be necessary, have to check. @Bribe you might want to take a look into the Critical Strike system as well and see if it also requires some internal change. If you can wait a little before releasing another plugin that might save you some work, i promise it wont take long.

The way I see it you should only focus on what's best for your script and leave the compatibility things to me. It's my responsibility to manage plugins for Damage Engine.

I would, however, recommend you standardize setting and getting damage rather than strictly relying on the Blizzard natives. But I'm suggesting it mainly based on the fact that it would make it easier for me to develop plugins for your sub-resources. You do have a lot of variable caching variables (see below) that you use and it would make sense for the user to interact with them by means of getting/setting those variables rather than calling to the Blizzard natives each time.

JASS:
        readonly static damagetype damagetype
        readonly static attacktype attacktype
        readonly static unit      source
        readonly static unit      target
        readonly static player    sourcePlayer
        readonly static player    targetPlayer
        readonly static boolean   isEnemy
        readonly static boolean   isAlly
        readonly static boolean   isMelee
        readonly static boolean   isRanged
        readonly static boolean   isAttack
        readonly static boolean   isSpell
        readonly static boolean   isPure
        readonly static boolean   isEnhanced
        readonly static boolean   sourceIsHero
        readonly static boolean   targetIsHero
        readonly static boolean   structure
        readonly static boolean   magicImmune
        readonly static real      sourceX
        readonly static real      sourceY
        readonly static real      targetX
        readonly static real      targetY
        readonly static integer   sIdx
        readonly static integer   tIdx
        readonly static integer   sId
        readonly static integer   tId
 
Level 20
Joined
May 16, 2012
Messages
635
So @Bribe I've updated Damage Interface again, have found a bug due to a problem regarding spell damage, and i just wanted to share a few things i discovered recently, since we both like to play around with these events.

First is regarding the attack type ATTACK_TYPE_NORMAL or as we know it Spell damage type. It turns out that null and ATTACK_TYPE_NORMAL are the same thing, you can check if the attack type of a damage event is equal to null or to the constant type defined and both will produce the same result, which for my system it was unfortunate due to the way damage registration is done there, so i had to work around it.

Another thing that i found out, and that is pretty concerning for both of our systems, is that the native way of detecting damage have a degradable performance over time. I did a stress test in both your system and in mine to make sure i wasn't doing anything stupid and it turns out that the triggers being evaluated produced a worse performance the more events have happened throughout the game. I tried re-constructing the triggers, re-registering their conditions and so far nothing seemed to work. I'm pretty sure for 99% of all maps that use a damage system it will not be a problem, since in my stress tests i was pushing 100000 damage events in under 5 minutes, but for maps that rely heavily on high attack speed units or just a massive number of them interacting constantly, like in tower defenses and such it might get noticeable towards the late stages of a game. Also, it's not a constant drop in performance, just happens when a damage event is being evaluated after that large amounts of events happened.

Regarding this:
I would, however, recommend you standardize setting and getting damage rather than strictly relying on the Blizzard natives.

When i was updating my system i did standardized setting and getting damage, but then the Spell damage bug presented itself and it turn out that in order to keep setting and getting that way i would have to evaluate 2 more triggers per damage event, which is pricey, so i decided to let the user keep using the natives to manipulate the damage amounts.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
So @Bribe I've updated Damage Interface again, have found a bug due to a problem regarding spell damage, and i just wanted to share a few things i discovered recently, since we both like to play around with these events.

First is regarding the attack type ATTACK_TYPE_NORMAL or as we know it Spell damage type. It turns out that null and ATTACK_TYPE_NORMAL are the same thing, you can check if the attack type of a damage event is equal to null or to the constant type defined and both will produce the same result, which for my system it was unfortunate due to the way damage registration is done there, so i had to work around it.

Another thing that i found out, and that is pretty concerning for both of our systems, is that the native way of detecting damage have a degradable performance over time. I did a stress test in both your system and in mine to make sure i wasn't doing anything stupid and it turns out that the triggers being evaluated produced a worse performance the more events have happened throughout the game. I tried re-constructing the triggers, re-registering their conditions and so far nothing seemed to work. I'm pretty sure for 99% of all maps that use a damage system it will not be a problem, since in my stress tests i was pushing 100000 damage events in under 5 minutes, but for maps that rely heavily on high attack speed units or just a massive number of them interacting constantly, like in tower defenses and such it might get noticeable towards the late stages of a game. Also, it's not a constant drop in performance, just happens when a damage event is being evaluated after that large amounts of events happened.

Regarding this:


When i was updating my system i did standardized setting and getting damage, but then the Spell damage bug presented itself and it turn out that in order to keep setting and getting that way i would have to evaluate 2 more triggers per damage event, which is pricey, so i decided to let the user keep using the natives to manipulate the damage amounts.

Hi Chopinski, thanks for your input!

Yes the reason why the "null" method works is because the ConvertAttackType native is passed 0 when assigning the constant value of ATTACK_TYPE_NORMAL. The same is true for DAMAGE_TYPE_UNKNOWN and WEAPON_TYPE_WHOKNOWS. That is also why you only need to pass to UnitDamageTarget the final values of "null,null,null" in order to deal universal damage to it.

Regarding the stress test, I have given it some thought and the likely scenario is that you are allocating too much space on the array storage, hence degrading performance due to memory allocation. When you set a variable in a JASS array which is quite high up, you leave a permanent memory footprint as the dynamic allocation cannot be deallocated.

A better stress test might be just to run 10-100 instances per second and leave it running for a while and see where it gets you.

Regarding the performance impact of running two events, yes I can see why your resource would not (and should not) do that. Having just the events run that are needed by the user is potentially beneficial in a benchmark setting. That's one of the reasons I like for there to be competing systems, which gives users choice. I take it upon myself to make sure that Damage Engine - while not being the fastest system in a vacuum - remains the most feature-packed and cross-compatible system.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Hmm... Okay, I'll try my best to figure it out then.

I would suggest the following process to debug your map:

1) Disable all of your "DamageEvent/DamageModifier/etc" triggers.
2) Test if the issue still exists
3) If it does, let me know as it could potentially be engine-related with a new environment I haven't encountered. Please send me your map in that case.
4) If the issue does not occur, then enable half of your disabled triggers.
5) Test if the issue still exists
6) If yes, then the issue is with one of your recently-enabled triggers. Disable half of them, and then repeat from step 5 until you have narrowed it down to the problematic trigger.
7) If no, repeat from step 4.
 
Level 6
Joined
Jul 12, 2017
Messages
139
I would suggest the following process to debug your map:

1) Disable all of your "DamageEvent/DamageModifier/etc" triggers.
2) Test if the issue still exists
3) If it does, let me know as it could potentially be engine-related with a new environment I haven't encountered. Please send me your map in that case.
4) If the issue does not occur, then enable half of your disabled triggers.
5) Test if the issue still exists
6) If yes, then the issue is with one of your recently-enabled triggers. Disable half of them, and then repeat from step 5 until you have narrowed it down to the problematic trigger.
7) If no, repeat from step 4.

I know that's the way to do it but with my 1000+ triggers and 500+ damage detection trigger, that's gotta take some time.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
I know that's the way to do it but with my 1000+ triggers and 500+ damage detection trigger, that's gotta take some time.
That's massive! I imagine that there being 500+ damage detection triggers alone will cause some latency in the long term (e.g. people with lower-spec-ed machines might already get a little lag on normal hits or completely shut down in a major fight).

It is highly advisable to use as many of the performance-saving shortcuts as possible in order to cut down on more triggers running than are absolutely necessary. Disabling and enabling triggers dynamically as needed might also save you some FPS.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
I think I already gave my map to you one time, but you didn't say anything much, only mentioning 1000+ triggers on my map and that's it.
That sounds like me XD

I don't have time like I used to unfortunately. And since Reforged the performance has been so bad that I had to "retire" my laptop from duty. I might install an older version of WC3 on it if I can find out how.
 
Level 6
Joined
Jul 12, 2017
Messages
139
That sounds like me XD

I don't have time like I used to unfortunately. And since Reforged the performance has been so bad that I had to "retire" my laptop from duty. I might install an older version of WC3 on it if I can find out how.

Ah, that would explain something. Before reforged, my map doesn't lag this badly and I don't think I leak anything. My laptop may be 5 years old but it can run a game like gta 5 just fine but not this game lol. I even lag on map like legion td and farmer vs hunter too. Some people who play my map does have some spike but they can play just fine unlike my laptop so I kinda wonder what should I improve on.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Ah, that would explain something. Before reforged, my map doesn't lag this badly and I don't think I leak anything. My laptop may be 5 years old but it can run a game like gta 5 just fine but not this game lol. I even lag on map like legion td and farmer vs hunter too. Some people who play my map does have some spike but they can play just fine unlike my laptop so I kinda wonder what should I improve on.
I have a 2012 MacBook Pro which I use exclusively at home, and I might be able to find some time to go over your map in a couple of weeks at the soonest. Hopefully that machine should have the CPU power to get me through that long list of triggers. If not, then I won't be able to be of much help.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Wait, you mention something about Upgrading to Reforged. What exactly is the problem or differences? Between 1.31 and 1.32?

I don't have any comment on how this runs on Reforged as I refunded my pre-order when shit hit the fan last year. I am just using a legal copy of WarCraft 3 that is up to date. That is the recommended version.

If my memory serves, there was one new native added at some point which I implemented which requires patch 1.32.x. You don't need it, per se, and in an earlier post I have mentioned a workaround.
 
Level 5
Joined
Dec 25, 2014
Messages
111
If my memory serves, there was one new native added at some point which I implemented which requires patch 1.32.x. You don't need it, per se, and in an earlier post I have mentioned a workaround.
This is what confuses me, because i've seen the reforged patch details and i don't find any additional native added.
Might be a hidden native(?).
 
Level 18
Joined
Jan 1, 2018
Messages
728
This is what confuses me, because i've seen the reforged patch details and i don't find any additional native added.
Might be a hidden native(?).
No hidden natives, just the devs being too lazy to mention when they add any new ones.
You can check common.j and diff with an earlier version to find newly added natives.
I also have a list of all natives added since 1.29 here: Drake53/War3App
 
Level 5
Joined
Dec 25, 2014
Messages
111
No hidden natives, just the devs being too lazy to mention when they add any new ones.
You can check common.j and diff with an earlier version to find newly added natives.
I also have a list of all natives added since 1.29 here: Drake53/War3App
Now i've seen it
There are some great natives, wow.
But still, do they work?
Since i'm still using classic, there are still many natives added in 1.31 that doesn't work. Are they working in 1.32?
 
Level 18
Joined
Jan 1, 2018
Messages
728
Now i've seen it
There are some great natives, wow.
But still, do they work?
Since i'm still using classic, there are still many natives added in 1.31 that doesn't work. Are they working in 1.32?
I'm also still on 1.31 so I can't answer that.
 
Level 12
Joined
May 16, 2020
Messages
660
Hi Bribe,

I'm having troubles with the LethalDamageEvent = 1.00 and setting LethalDamageHP to 1 (which I understand should leave the DamageEventTarget with 1 HP).

For some reason it doesn't always prevent the DamageEventTarget from dying; more often than not the lethal damage which I want to prevent is lethal. Is there anything wrong with how I use this function?

  • Death Coil
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Death Coil
    • Actions
      • Set VariableSet DeathCoil_Caster = (Triggering unit)
      • Set VariableSet DeathCoil_Index = (DeathCoil_Index + 1)
      • Unit - Cause DeathCoil_Caster to damage DeathCoil_Caster, dealing (50.00 + (25.00 x (Real((Level of Death Coil for DeathCoil_Caster))))) damage of attack type Chaos and damage type Universal
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • DeathCoil_Index Equal to 1
        • Then - Actions
          • Trigger - Turn on Death Coil Damage <gen>
          • Trigger - Turn on Death Coil Lethality <gen>
        • Else - Actions
  • Death Coil Damage
    • Events
      • Game - DamageModifierEvent becomes Equal to 1.00
    • Conditions
      • IsDamageCode Equal to False
      • (DamageEventTarget has buff Death Coil ) Equal to True
      • (Level of Death Coil for DamageEventSource) Greater than 0
    • Actions
      • Unit - Remove Death Coil buff from DamageEventTarget
      • Set VariableSet DeathCoil_Index = (DeathCoil_Index - 1)
      • Set VariableSet DamageEventAmount = 0.00
      • Set VariableSet DeathCoil_Amount = (75 + (45 x (Level of Death Coil for DamageEventSource)))
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (DamageEventTarget belongs to an ally of (Owner of DamageEventSource).) Equal to True
        • Then - Actions
          • Unit - Set life of DamageEventTarget to ((Life of DamageEventTarget) + (Real(DeathCoil_Amount)))
        • Else - Actions
          • Set VariableSet NextDamageType = DamageTypeCode
          • Unit - Cause DamageEventSource to damage DamageEventTarget, dealing (Real(DeathCoil_Amount)) damage of attack type Spells and damage type Magic
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • DeathCoil_Index Equal to 0
        • Then - Actions
          • Trigger - Turn off (This trigger)
          • Trigger - Turn off Death Coil Lethality <gen>
        • Else - Actions
  • Death Coil Lethality
    • Events
      • Game - LethalDamageEvent becomes Equal to 1.00
    • Conditions
      • DamageEventSource Equal to DamageEventTarget
      • (Level of Death Coil for DamageEventSource) Greater than 0
    • Actions
      • Game - Display to (All players) for 2.00 seconds the text: SAVED
      • Set VariableSet LethalDamageHP = 1.00

EDIT: Added the missing trigger section - sorry!
 
Last edited:
Top