• 🏆 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...
Level 35
Joined
Feb 5, 2009
Messages
4,552
Yeah, I mean there's no -99999 value or anything like that in those circumstances. I've tried it with removing the random integer, too, although upon the critical strike occurring, that would be when the armor should be pierced. So far it's displaying that it's just not doing it for some reason here.

I do hope this isn't a Reforged issue, partly due to those being particularly annoying, and yet... surprisingly prevalent. Although I am unsure if Bribe is using Reforged or not himself.
 
Level 20
Joined
Aug 13, 2013
Messages
1,696
Yeah, I mean there's no -99999 value or anything like that in those circumstances. I've tried it with removing the random integer, too, although upon the critical strike occurring, that would be when the armor should be pierced. So far it's displaying that it's just not doing it for some reason here.
So there's no -99999 value displayed but you said that there's 0 & 5 value showing and that ensures BlzGetUnitArmor() works properly.
The intriguing part here is whether if BlzSetUnitArmor() is broken or setArmor() in that event isn't called or the pierce value is strangely zeroed.
Can you test that native on your end? Try to set a unit's armor and see if it works properly? This is my last request for you to do
And I'll leave this up to Bribe. As I'm always concerned about the stability of the systems I'm using (although I don't use this yet but soon)

I do hope this isn't a Reforged issue, partly due to those being particularly annoying, and yet... surprisingly prevalent. Although I am unsure if Bribe is using Reforged or not himself.
I'm sure he is using reforged editor as I can't open it. We must also be aware that these new patches
may cause glitches/problems inside the game as this is just part of development obviously: some things may get broken and fixed unknowingly.
But yeah, can't blame reforged if the case is isolated for your end only unless others complaint it too.
 
Level 35
Joined
Feb 5, 2009
Messages
4,552
Fixed the issue reported by @Wazzz and also adjusted the Report function in the demo map accordingly (I had tweaked it to suit something I was testing for myself awhile back but forgot to restore it back to normal).

This update is recommended for all users but only requires the JASS script be updated.

Nice, this works for me now, thank you :)

The values coming up from it do seem a little strange in some respects, it doesn't seem to go into super negative armor to the point of dealing a great amount of bonus damage, yet at the same time when the armor is pierced, it seems to be dealing more damage than it normally would against the armor type. I wonder if that's an area blizzard may have sort of... played around with, especially seeing as the legacy version seemed to have no issue going that far into negatives.

So, I did some investigation on this. As it turns out, this may or may not be a fix from Blizzard, or something different, but when armor goes into negative, it scales the exact same way as it would if it went into positive. So, -50 armor has a damage reduction of approximately 71%. -1000 armor, however, has a damage reduction of... exactly the same. At that point the scaling peters off, so when you reach a certain amount of armor reduction, you'll be dealing the same amount of damage, but it will still be much higher than you would normally do.

So, system works perfectly in representing this, and that makes me very happy :D
 
I LOVE damage engine. It lets me add spell damage scaling to Wc3 which is something I always wanted for heroes. My only minor issue for now is that the compatibility script for damage interface doesn't compile so I won't be able to use this together with New Bonus v1.7 until its fixed. If you uncomment untitled trigger 001 in this test map you get an error.
 

Attachments

  • damage engine wrapper test.w3m
    52 KB · Views: 110

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Thanks @KitsuneTailsPrower , this has been fixed in version 5.7.0.3. You will need to update both the Damage Engine JASS script as well as the DamageInterface plugin to the latest (the first stable release in fact).

Version 5.7.0.3 is recommended for anyone who relies on the vJass custom events with built-in boolean checks and also adds some additional extensibility for those who would like to tinker around with their own plugins.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
How can I heal an ally with this system?

Depends on if you want the heal to take place before or after armor reduction. Usually it's before armor reduction I'd suggest.

  • Heal Ally
    • Events
      • Game - DamageModifierEvent becomes Equal to -420.69
    • Conditions
      • DamageEventTarget is an enemy of (Owner of DamageEventSource) Equal to False
    • Actions
      • Set DamageEventAmount = (0.00 - DamageEventAmount)
      • Set DamageEventDamageT = DAMAGE_TYPE_UNIVERSAL
      • Set DamageEventOverride = True
 
Level 6
Joined
Jul 12, 2017
Messages
139
Depends on if you want the heal to take place before or after armor reduction. Usually it's before armor reduction I'd suggest.

  • Heal Ally
    • Events
      • Game - DamageModifierEvent becomes Equal to -420.69
    • Conditions
      • DamageEventTarget is an enemy of (Owner of DamageEventSource) Equal to False
    • Actions
      • Set DamageEventAmount = (0.00 - DamageEventAmount)
      • Set DamageEventDamageT = DAMAGE_TYPE_UNIVERSAL
      • Set DamageEventOverride = True


So it is possible to use this system to heal an ally, but I kinda don't get what you mean by armor reduction, like do I have to acid bomb my ally and set a negative number in order to heal them?
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
So it is possible to use this system to heal an ally, but I kinda don't get what you mean by armor reduction, like do I have to acid bomb my ally and set a negative number in order to heal them?

No I mean the Damage first comes as damage, but then converting the damage to negative turns it into a heal (see the Archmage's Water Elementals and Archimonde's attacks in my demo map).

If you do that before armor you should set the damage type to UNIVERSAL to prevent the damage from being reduced to 0 instead of regaining as a negative amount.
 
Level 6
Joined
Jul 12, 2017
Messages
139
No I mean the Damage first comes as damage, but then converting the damage to negative turns it into a heal (see the Archmage's Water Elementals and Archimonde's attacks in my demo map).

If you do that before armor you should set the damage type to UNIVERSAL to prevent the damage from being reduced to 0 instead of regaining as a negative amount.

Alright I'll try that, thanks.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Uh, in the middle of playing the map, my damage detection stop working, like unit stop having bonus damage from abilities... What happened? This rarely happen but it did anyway?
Which version is your Damage Engine on?

Just a little detail for your next versions. The 2 following variables seem to be disused but still here:

JASS:
udg_NextDamageWeaponT
udg_DamageEventTrigger

Thanks for the heads-up! WeaponT does need to be a thing but DamageEventTrigger is twice retired now.
 
Level 6
Joined
Jul 12, 2017
Messages
139
The newest one 5.7.0.3, like it stopped working completely, all abilities that used trigger like this are not working at all.

  • Staff of the Inferno Item
    • Events
      • Game - DamageModifierEvent becomes Equal to 1.00
    • Conditions
      • IsDamageSpell Equal to True
      • (DamageEventSource has an item of type Staff of the Inferno) Equal to True
    • Actions
      • Set VariableSet NextDamageType = DamageTypePure
      • Set VariableSet Real1 = (Real((Intelligence of DamageEventSource (Include bonuses))))
      • Unit - Cause DamageEventSource to damage DamageEventTarget, dealing (Real1 x 2.50) damage of attack type Spells and damage type Normal
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
The newest one 5.7.0.3, like it stopped working completely, all abilities that used trigger like this are not working at all.

  • Staff of the Inferno Item
    • Events
      • Game - DamageModifierEvent becomes Equal to 1.00
    • Conditions
      • IsDamageSpell Equal to True
      • (DamageEventSource has an item of type Staff of the Inferno) Equal to True
    • Actions
      • Set VariableSet NextDamageType = DamageTypePure
      • Set VariableSet Real1 = (Real((Intelligence of DamageEventSource (Include bonuses))))
      • Unit - Cause DamageEventSource to damage DamageEventTarget, dealing (Real1 x 2.50) damage of attack type Spells and damage type Normal

Please send me over the map you're using and let me know at what point you notice things breaking. Ideally you'd want to tell me what units were fighting each other right before the problem occurred.
 
Level 6
Joined
Jul 12, 2017
Messages
139
The map is pretty big with 1000+ triggers, but most of them are in attribute based abilities. I think it was me Malfurion killed something, but not sure.

I'll include that match when it happened as well.
 

Attachments

  • LastReplay.w3g
    1.1 MB · Views: 59
  • Azeroth Heroes Survival 2.5fd.w3x
    13.2 MB · Views: 54
Level 20
Joined
May 16, 2012
Messages
635
The newest one 5.7.0.3, like it stopped working completely, all abilities that used trigger like this are not working at all.

  • Staff of the Inferno Item
    • Events
      • Game - DamageModifierEvent becomes Equal to 1.00
    • Conditions
      • IsDamageSpell Equal to True
      • (DamageEventSource has an item of type Staff of the Inferno) Equal to True
    • Actions
      • Set VariableSet NextDamageType = DamageTypePure
      • Set VariableSet Real1 = (Real((Intelligence of DamageEventSource (Include bonuses))))
      • Unit - Cause DamageEventSource to damage DamageEventTarget, dealing (Real1 x 2.50) damage of attack type Spells and damage type Normal

It looks like this will cause an infinite loop, or at least it will run as many times as the recursion safety from Damage Engine allows it. You are detecting a Spell damage in conditions and in the actions you are dealing Spell damage, this maybe has something to do with it. Try changing the attack type Spells to something else and see if it still breaking.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
It looks like this will cause an infinite loop, or at least it will run as many times as the recursion safety from Damage Engine allows it. You are detecting a Spell damage in conditions and in the actions you are dealing Spell damage, this maybe has something to do with it. Try changing the attack type Spells to something else and see if it still breaking.
That won't be it because Damage Engine doesn't require users to worry about recursion. The above trigger will not run more than twice.
 
Level 19
Joined
Aug 16, 2007
Messages
881
I've decided to update DamageEngine to the latest version, up from 5.4.2.3. I'm taking it slow, as it's such a huge difference between these versions.

I understand the documentation isn't complete, but I've read through the code and the documentation there is, but I've ran into a strange issue.

I'm trying to register a simple DamageEvent for the Footman unit-type, just to get a better understanding and to try out the recent version and its featues.

For some reason I must register the DamageEvent twice for it to fire (see attached image).
I'm also unable to get the configuration to work, it fires for any unit-type. As I understand it, when registering a DamageEngineEvent, it sets and returns lastRegistered and I figured I could use this index as a reference for the last created DamageEngineEvent, no?

I've set USE_GUI to false.
JASS:
library DamageLib initializer DamageLibInit requires DamageEngine

  private function OnDamage_Footman3 takes nothing returns nothing
    call BJDebugMsg("OnDamage_Footman3")
  endfunction

  private function OnDamage_Footman2 takes nothing returns nothing
    call BJDebugMsg("OnDamage_Footman2")
  endfunction

  private function OnDamage_Footman1 takes nothing returns nothing
    call BJDebugMsg("OnDamage_Footman1")
  endfunction

  private function DamageLibInit takes nothing returns nothing
    local trigger t1 = CreateTrigger()
    local trigger t2 = CreateTrigger()
 
    //===========================================================================
    // THIS WORKS
    call TriggerAddAction(t1, function OnDamage_Footman1)
    call TriggerRegisterDamageEngineEx(t1, "", 1.0, DamageEngine_FILTER_OTHER)
 
    call RegisterDamageEngineEx(function OnDamage_Footman1, "", 1.0, DamageEngine_FILTER_OTHER)
    set DamageTrigger.lastRegistered.sourceType = 'hfoo'
    set DamageTrigger.lastRegistered.configured = true
 
    //===========================================================================
    // THIS DOESN'T WORK
    call TriggerAddAction(t2, function OnDamage_Footman2)
    call TriggerRegisterDamageEngineEx(t2, "", 1.0, DamageEngine_FILTER_OTHER)
    set DamageTrigger.lastRegistered.sourceType = 'hfoo'
    set DamageTrigger.lastRegistered.configured = true
 
    //===========================================================================
    // THIS DOESN'T WORK
    call RegisterDamageEngineEx(function OnDamage_Footman3, "", 1.0, DamageEngine_FILTER_OTHER)
    set DamageTrigger.lastRegistered.sourceType = 'hfoo'
    set DamageTrigger.lastRegistered.configured = true
 
 
    //===========================================================================
    set t1 = null
    set t2 = null
    call BJDebugMsg("DamageLibInit")
  endfunction
endlibrary


UPDATE 1: The RegisterDamageEngine functions do work as intended when not configurating the members; so I'm not sure if I'm doing that wrong or if something is broken. I saw your message via the reputation notification.

UPDATE 2: I've managed to get it to work, it seems atleast, but please reach out if I'm configurating in a non-intended way.

I had to manually configure attackType and damageType in order to pass the checkConfiguration method.

JASS:
library DamageLib initializer DamageLibInit requires DamageEngine

  private function OnDamage_Shaman takes nothing returns nothing
    call BJDebugMsg("OnDamage_Shaman")
  endfunction

  private function OnDamage_Footman takes nothing returns nothing
    call BJDebugMsg("OnDamage_Footman")
  endfunction

  private function DamageLibInit takes nothing returns nothing
    call RegisterDamageEngineEx(function OnDamage_Footman, "", 1.0, DamageEngine_FILTER_OTHER)
    set DamageTrigger.lastRegistered.attackType = -1
    set DamageTrigger.lastRegistered.damageType = -1
    set DamageTrigger.lastRegistered.sourceType = 'hfoo'
    set DamageTrigger.lastRegistered.configured = true
 
    call RegisterDamageEngineEx(function OnDamage_Shaman, "", 1.0, DamageEngine_FILTER_OTHER)
    set DamageTrigger.lastRegistered.attackType = -1
    set DamageTrigger.lastRegistered.damageType = -1
    set DamageTrigger.lastRegistered.sourceType = 'oshm'
    set DamageTrigger.lastRegistered.configured = true
    call BJDebugMsg("DamageLibInit")
  endfunction
endlibrary
 

Attachments

  • WC3ScrnShot_072520_121611_001.png
    WC3ScrnShot_072520_121611_001.png
    6.4 MB · Views: 46
Last edited:
Level 12
Joined
May 16, 2020
Messages
660
Hi Bribe, is it possible to recognize the Order ID from a damage source which is already over by the time the damage happens?

I'm creating a "Counterspell", which reflects all single target spells back to the caster. Currently it works based on the point in time when the enemy ability is cast. However, ideally I want to be able to activate the Counterspell while the enemy projectile is still in the air, and then reflect it back (= not "starts the effect of an ability", but "DamageEvent becomes Equal to 1.00").

So I need a trigger which recognizes that a) a damage source is a spell, and more importantly, b) which spell it was, so that I can take the same order ID and reflect it.

  • Counterspell Counter
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • ((Target unit of ability being cast) has buff Counterspell ) Equal to True
    • Actions
      • Set VariableSet Counterspell_Order = (Current order of (Triggering unit))
      • Set VariableSet Counterspell_Caster = (Target unit of ability being cast)
      • Set VariableSet Counterspell_Target = (Triggering unit)
      • Set VariableSet Counterspell_Point = (Position of Counterspell_Caster)
      • Unit - Create 1 Dummy (Ground/Speed 522) for (Owner of Counterspell_Caster) at Counterspell_Point facing Default building facing degrees
      • Set VariableSet Counterspell_Dummy = (Last created unit)
      • Unit - Add (Ability being cast) to Counterspell_Dummy
      • Unit - Set level of (Ability being cast) for Counterspell_Dummy to (Level of (Ability being cast) for Counterspell_Target)
      • Custom script: call IssueTargetOrderById(udg_Counterspell_Dummy, udg_Counterspell_Order, udg_Counterspell_Target)
      • Unit - Add a 1.00 second Generic expiration timer to Counterspell_Dummy
      • Custom script: call RemoveLocation (udg_Counterspell_Point)
      • Unit - Add Spell Immunity (Archimonde) to Counterspell_Caster
      • Trigger - Turn on Counterspell No Damage <gen>
      • Game - Display to (All players) the text: Counter no damage: ...
      • Trigger - Turn off (This trigger)
      • Game - Display to (All players) the text: Counter Spell Count...
  • Counterspell No Damage
    • Events
      • Game - DamageEvent becomes Equal to 1.00
    • Conditions
      • (DamageEventTarget has buff Counterspell ) Equal to True
      • (DamageEventTarget belongs to an enemy of (Owner of DamageEventSource).) Equal to True
      • DamageEventAttackT Equal to ATTACK_TYPE_SPELLS
    • Actions
      • Set VariableSet DamageEventAmount = 0.00
      • Unit - Remove Spell Immunity (Archimonde) from DamageEventTarget
      • Game - Display to (All players) the text: Counter no damage: ...
      • Trigger - Turn off (This trigger)
 
Level 19
Joined
Aug 16, 2007
Messages
881
Thanks for the update, great to see more customization options that allow you to disable part of the code you don't have any use for. I can confirm that my previous reported issue is solved regarding the configuration. However, I've found a new issue with the latest version, v5.7.1.0.

I'm using the same code as before, in order to test.
JASS:
library DamageLib initializer DamageLibInit requires DamageEngine

  private function OnDamage_LichPhysical takes nothing returns nothing
    call BJDebugMsg("OnDamage_LichPhysical | Dealt " + R2S(Damage.index.amount) + " damage.")
  endfunction

  private function OnDamage_LichSpell takes nothing returns nothing
    call BJDebugMsg("|cff3264c8OnDamage_LichSpell | Dealt " + R2S(Damage.index.amount) + " damage.|r")
  endfunction

  private function DamageLibInit takes nothing returns nothing
    call RegisterDamageEngineEx(function OnDamage_LichSpell, "", 1.0, DamageEngine_FILTER_SPELL)
    set DamageTrigger.lastRegistered.sourceType = 'Ulic'
    set DamageTrigger.lastRegistered.configured = true
   
    call RegisterDamageEngineEx(function OnDamage_LichPhysical, "", 1.0, DamageEngine_FILTER_ATTACK)
    set DamageTrigger.lastRegistered.sourceType = 'Ulic'
    set DamageTrigger.lastRegistered.configured = true
    call BJDebugMsg("DamageLibInit")
  endfunction
endlibrary
I've set the new config boolean to USE_MELEE_RANGE= false
This completely breaks the events in my code above. If it's set to true it works as intended.

I also have the following issue, which unfortunately makes the system unusable for me, as I have to be able to detect multiple damage instances at once from the same damage source.

The call RegisterDamageEngineEx(function OnDamage_LichSpell, "", 1.0, DamageEngine_FILTER_SPELL) only fires once when simultaneous damage is dealt (see attached image).

As you can see the OnSpell damage text is only displayed once, even though the Frost Nova hit 6 targets.

It might be a setting I'm missing though? It shouldn't be considered recursive damage as it's seperate damage instances?
 

Attachments

  • WC3ScrnShot_072620_115610_001.png
    WC3ScrnShot_072620_115610_001.png
    7 MB · Views: 46

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
I see the problem. To fix it while disabling MELEE/RANGE, you will need to change this:

JASS:
static if USE_MELEE_RANGE then// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            if d.damageType == DAMAGE_TYPE_NORMAL and d.isAttack then
                set d.isMelee           = IsUnitType(d.sourceUnit, UNIT_TYPE_MELEE_ATTACKER)
                set d.isRanged          = IsUnitType(d.sourceUnit, UNIT_TYPE_RANGED_ATTACKER)
                if d.isMelee and d.isRanged then
                    set d.isMelee       = d.weaponType != null  // Melee units play a sound when damaging
                    set d.isRanged      = not d.isMelee         // In the case where a unit is both ranged and melee, the ranged attack plays no sound.
                endif
                if d.isMelee then
                    set eventFilter     = FILTER_MELEE
                elseif d.isRanged then
                    set eventFilter     = FILTER_RANGED
                else
                    set eventFilter     = FILTER_ATTACK
                endif
            else
                if d.isSpell then
                    set eventFilter     = FILTER_SPELL
                else
                    set eventFilter     = FILTER_OTHER
                endif
                set d.isMelee           = false
                set d.isRanged          = false
            endif
endif// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

To this:

JASS:
            if d.damageType == DAMAGE_TYPE_NORMAL and d.isAttack then
static if USE_MELEE_RANGE then// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                set d.isMelee           = IsUnitType(d.sourceUnit, UNIT_TYPE_MELEE_ATTACKER)
                set d.isRanged          = IsUnitType(d.sourceUnit, UNIT_TYPE_RANGED_ATTACKER)
                if d.isMelee and d.isRanged then
                    set d.isMelee       = d.weaponType != null  // Melee units play a sound when damaging
                    set d.isRanged      = not d.isMelee         // In the case where a unit is both ranged and melee, the ranged attack plays no sound.
                endif
                if d.isMelee then
                    set eventFilter     = FILTER_MELEE
                elseif d.isRanged then
                    set eventFilter     = FILTER_RANGED
                else
                    set eventFilter     = FILTER_ATTACK
                endif
else
                set eventFilter         = FILTER_ATTACK
endif// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            else
                if d.isSpell then
                    set eventFilter     = FILTER_SPELL
                else
                    set eventFilter     = FILTER_OTHER
                endif
static if USE_MELEE_RANGE then// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                set d.isMelee           = false
                set d.isRanged          = false
endif// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            endif

Thanks again for the bug report! I will have this bundled with the next update. If I don't get any additional bug reports in the next 12 hours then this will be the only change included in 5.7.1.1.

I think the reason why the Spell portion is not working is because you might be using NextDamageIsMelee or NextDamageIsRanged somewhere in your map. With that boolean disabled it does not reset their flags back to False.
 
Last edited:
Level 19
Joined
Aug 16, 2007
Messages
881
I see the problem. To fix it while disabling MELEE/RANGE, you will need to change this:

JASS:
static if USE_MELEE_RANGE then// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            if d.damageType == DAMAGE_TYPE_NORMAL and d.isAttack then
                set d.isMelee           = IsUnitType(d.sourceUnit, UNIT_TYPE_MELEE_ATTACKER)
                set d.isRanged          = IsUnitType(d.sourceUnit, UNIT_TYPE_RANGED_ATTACKER)
                if d.isMelee and d.isRanged then
                    set d.isMelee       = d.weaponType != null  // Melee units play a sound when damaging
                    set d.isRanged      = not d.isMelee         // In the case where a unit is both ranged and melee, the ranged attack plays no sound.
                endif
                if d.isMelee then
                    set eventFilter     = FILTER_MELEE
                elseif d.isRanged then
                    set eventFilter     = FILTER_RANGED
                else
                    set eventFilter     = FILTER_ATTACK
                endif
            else
                if d.isSpell then
                    set eventFilter     = FILTER_SPELL
                else
                    set eventFilter     = FILTER_OTHER
                endif
                set d.isMelee           = false
                set d.isRanged          = false
            endif
endif// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

To this:

JASS:
            if d.damageType == DAMAGE_TYPE_NORMAL and d.isAttack then
static if USE_MELEE_RANGE then// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                set d.isMelee           = IsUnitType(d.sourceUnit, UNIT_TYPE_MELEE_ATTACKER)
                set d.isRanged          = IsUnitType(d.sourceUnit, UNIT_TYPE_RANGED_ATTACKER)
                if d.isMelee and d.isRanged then
                    set d.isMelee       = d.weaponType != null  // Melee units play a sound when damaging
                    set d.isRanged      = not d.isMelee         // In the case where a unit is both ranged and melee, the ranged attack plays no sound.
                endif
                if d.isMelee then
                    set eventFilter     = FILTER_MELEE
                elseif d.isRanged then
                    set eventFilter     = FILTER_RANGED
                else
                    set eventFilter     = FILTER_ATTACK
                endif
else
                set eventFilter         = FILTER_ATTACK
endif// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            else
                if d.isSpell then
                    set eventFilter     = FILTER_SPELL
                else
                    set eventFilter     = FILTER_OTHER
                endif
static if USE_MELEE_RANGE then// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                set d.isMelee           = false
                set d.isRanged          = false
endif// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            endif

Thanks again for the bug report! I will have this bundled with the next update. If I don't get any additional bug reports in the next 12 hours then this will be the only change included in 5.7.1.1.

I think the reason why the Spell portion is not working is because you might be using NextDamageIsMelee or NextDamageIsRanged somewhere in your map. With that boolean disabled it does not reset their flags back to False.

Glad to help!

I'm using your Demo map in order to test the system, I've not changed anything except setting USE_GUI to false and made my small testing script. See attached map if you can find any issues.

Using Chain Lightning with the Lich, the debug message appears for every damage instance, but both Frost Nova and Flame Strike only reports the damage once, regardless of targets hit.
 

Attachments

  • Damage Engine v5.7.1.0_test.w3x
    85.5 KB · Views: 37
Level 12
Joined
Feb 5, 2018
Messages
521
Hello Bribe, can you help me with one thing? I'm trying to make a super simple damage reduction event with your system and it does not work.

  • Anti Magic Shell
    • Events
      • Game - DamageEvent becomes Equal to 1.00
    • Conditions
      • (DamageEventTarget has buff Anti-Magic Shell (Custom)) Equal to True
    • Actions
      • Set VariableSet DamageEventAmount = (DamageEventAmount x 0.01)
I will change it to reduce only damage from magic & spells, when it actually even works like this. :D
 
Level 12
Joined
May 16, 2020
Messages
660
Hello Bribe, can you help me with one thing? I'm trying to make a super simple damage reduction event with your system and it does not work.

  • Anti Magic Shell
    • Events
      • Game - DamageEvent becomes Equal to 1.00
    • Conditions
      • (DamageEventTarget has buff Anti-Magic Shell (Custom)) Equal to True
    • Actions
      • Set VariableSet DamageEventAmount = (DamageEventAmount x 0.01)
I will change it to reduce only damage from magic & spells, when it actually even works like this. :D

I think you need to use "DamageModifierEvent" - at least that works in my map:

  • Events
    • Game - DamageModifierEvent becomes Equal to 1.00
  • Conditions
    • DamageEventAttackT Equal to ATTACK_TYPE_SPELLS
  • Actions
    • Set VariableSet DamageEventAmount = 0.00
 
Level 12
Joined
Feb 5, 2018
Messages
521
I think you need to use "DamageModifierEvent" - at least that works in my map:

  • Events
    • Game - DamageModifierEvent becomes Equal to 1.00
  • Conditions
    • DamageEventAttackT Equal to ATTACK_TYPE_SPELLS
  • Actions
    • Set VariableSet DamageEventAmount = 0.00

Thanks, got it! :)
 
Level 3
Joined
Mar 15, 2015
Messages
53
Having problem opening the 5.7.1.1 map, LUA map works just fine
I'm currently using 1.3.1, is it just me or anyone have the same problem?:vw_wtf:
 
Level 19
Joined
Aug 16, 2007
Messages
881
I've not found any issues with 5.7.1.1, everything seems to work as intended. The API compared to the older versions is much easier to work with and it's a great addition to allow the user to disable certain features they won't have any use for.

However, the performance of 5.7.x.x versions are unfortunately much worse compared to 5.4.2.3 (that I previously used).

Comparing both versions, using the same setup, 5.7.1.1 ended up running with <1 fps, while 5.4.2.3 is running at around ~45 fps.

For context I'm using one trigger function for each event (OnDamage, Modifier and Lethal) and my Line Tower Wars map will cause several hundreds of event calls every second due to the amount of creeps and towers.

I've tried to seperate each event for every unit with 5.7.1.1 using the new filter configuration as well, but it didn't make any noticeable difference, compared to 5.4.2.3.

I'm not sure why this is the cause, but thought you might want to know.

I'll make sure to try out any new major update in the future and report back.

I'd suggest looking at making a very light-weight version of Damage Engine, designed to handle up towards hundreds/thousands of event calls every second.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
I've not found any issues with 5.7.1.1, everything seems to work as intended. The API compared to the older versions is much easier to work with and it's a great addition to allow the user to disable certain features they won't have any use for.

However, the performance of 5.7.x.x versions are unfortunately much worse compared to 5.4.2.3 (that I previously used).

Comparing both versions, using the same setup, 5.7.1.1 ended up running with <1 fps, while 5.4.2.3 is running at around ~45 fps.

For context I'm using one trigger function for each event (OnDamage, Modifier and Lethal) and my Line Tower Wars map will cause several hundreds of event calls every second due to the amount of creeps and towers.

I've tried to seperate each event for every unit with 5.7.1.1 using the new filter configuration as well, but it didn't make any noticeable difference, compared to 5.4.2.3.

I'm not sure why this is the cause, but thought you might want to know.

I'll make sure to try out any new major update in the future and report back.

I'd suggest looking at making a very light-weight version of Damage Engine, designed to handle up towards hundreds/thousands of event calls every second.
There should NOT be a 4500% performance delta between the versions so this is very weird to hear about. I will need to hear more details about your map, what changed, what features you're using/etc.

The only way to cut down on evaluations is to customize the events yourself wherever possible and to do so as efficiently as possible. Damage Engine tries to automate and standardize some of those event responses where possible, but I may have to end uo scrapping or "offloading to an extension resource" the configuration booleans if they turn out to be more trouble than they are worth.
 
Level 19
Joined
Aug 16, 2007
Messages
881
There should NOT be a 4500% performance delta between the versions so this is very weird to hear about. I will need to hear more details about your map, what changed, what features you're using/etc.

The only way to cut down on evaluations is to customize the events yourself wherever possible and to do so as efficiently as possible. Damage Engine tries to automate and standardize some of those event responses where possible, but I may have to end uo scrapping or "offloading to an extension resource" the configuration booleans if they turn out to be more trouble than they are worth.
No, it is very strange indeed. I did mix up the frame rate of the two setups I did with 5.7.1.1 though and I also did a 3rd test now with a single event.


My setup with 5.4.2.3 is the following
JASS:
    // Register events
    set TriggerDamageEventModifier = CreateTrigger()
    call TriggerRegisterVariableEvent(TriggerDamageEventModifier, "udg_DamageModifierEvent", EQUAL, 1.00)
    call TriggerAddCondition(TriggerDamageEventModifier, Filter(function DamageEventModifier))
 
    set TriggerDamageEventOnDamage = CreateTrigger()
    call TriggerRegisterVariableEvent(TriggerDamageEventOnDamage, "udg_DamageEvent", EQUAL, 1.00)
    call TriggerAddCondition(TriggerDamageEventOnDamage, Filter(function DamageEventOnDamage))
 
    set TriggerDamageEventLethal = CreateTrigger()
    call TriggerRegisterVariableEvent(TriggerDamageEventLethal, "udg_LethalDamageEvent", EQUAL, 1.00)
    call TriggerAddCondition(TriggerDamageEventLethal, Filter(function DamageEventLethal))
Each of these functions checks the unit-type ID for the source and the target and run an additional function if conditions are met.
JASS:
  function DamageEventModifier takes nothing returns boolean
    local integer sourceType
    local integer targetType
    // Condition(s)
    if (udg_DamageEventAmount < 5.0) then
      return false
    endif

    set sourceType = GetUnitTypeId(udg_DamageEventSource)
    set targetType = GetUnitTypeId(udg_DamageEventTarget)

    if (not udg_IsDamageSpell) then
      // PHYSICAL MODIFIERS
      if (sourceType == TOWER_A) then
        call TOWER_A_Function()
      elseif (sourceType == TOWER_B) then
        call TOWER_A_Function()
      elseif(...)
        // etc...
      endif
    else
      // SPELL MODIFIERS
      //....
    endif

    return false
  endfunction

With the same test between 5.4.2.3 and 5.7.1.1, the 5.4.2.3 code runs at about 60 - 80 frame rate, it fluctuates a bit as Warcraft always does. You can see how many times the events were called, ~6.65k average.
5.4.2.3.png

With version 5.7.1.1 I made 3 different tests, using the same setup as 5.4.2.3.

I've setup the DamageEngine config to the following
JASS:
    private constant boolean USE_GUI        = false      //If you don't use any of the GUI events, set to false to slightly improve performance
                                                   
    private constant boolean USE_SCALING    = false   //If you don't need or want to use DamageScalingUser/WC3 then set this to false
    private constant boolean USE_EXTRA      = false      //If you don't use DamageEventLevel or AOEDamageEvent, set this to false
    private constant boolean USE_ARMOR_MOD  = false      //If you do not modify nor detect armor/defense, set this to false
    private constant boolean USE_MELEE_RANGE= false      //If you do not detect melee nor ranged damage, set this to false
    private constant boolean USE_LETHAL     = true      //If you do not use LethalDamageEvent nor negative damage (explosive) types, set this to false

//...

    //Map-makers should comment-out any booleans they will never need to check for.
    method checkConfiguration takes nothing returns boolean
        if this.userType != 0 and udg_DamageEventType != this.userType then
        //elseif this.source != null and this.source != udg_DamageEventSource then
        //elseif this.target != null and this.target != udg_DamageEventTarget then
        //elseif this.attackType >= 0 and this.attackType != udg_DamageEventAttackT then
        //elseif this.damageType >= 0 and this.damageType != udg_DamageEventDamageT then
        //elseif this.sourceType != 0 and GetUnitTypeId(udg_DamageEventSource) != this.sourceType then
        //elseif this.targetType != 0 and GetUnitTypeId(udg_DamageEventTarget) != this.targetType then
        //elseif this.sourceBuff != 0 and GetUnitAbilityLevel(udg_DamageEventSource, this.sourceBuff) == 0 then
        //elseif this.targetBuff != 0 and GetUnitAbilityLevel(udg_DamageEventTarget, this.targetBuff) == 0 then
        elseif udg_DamageEventAmount > this.damageMin then
            return true
        endif
        return false
    endmethod

TEST 1
I mixed up this code with Test 2 below, this doesn't run at below 1 fps.

As with what I did with 5.4.2.3 I use one major function for each Damage Event (without the additional condition as the engine handles that); but with 5.7.1.1 I could split them between attack and spell damage.
JASS:
    call RegisterDamageEngineEx(function DamageEvent_ModifierPhysical, "Modifier", 1.0, DamageEngine_FILTER_ATTACK)
    set DamageTrigger.lastRegistered.damageMin = 1.0
    set DamageTrigger.lastRegistered.configured = true
    call RegisterDamageEngineEx(function DamageEvent_ModifierSpell, "Modifier", 1.0, DamageEngine_FILTER_SPELL)
    set DamageTrigger.lastRegistered.damageMin = 1.0
    set DamageTrigger.lastRegistered.configured = true

    call RegisterDamageEngineEx(function DamageEvent_OnDamagePhysical, "", 1.0, DamageEngine_FILTER_ATTACK)
    set DamageTrigger.lastRegistered.damageMin = 1.0
    set DamageTrigger.lastRegistered.configured = true
    call RegisterDamageEngineEx(function DamageEvent_OnDamageSpell, "", 1.0, DamageEngine_FILTER_SPELL)
    set DamageTrigger.lastRegistered.damageMin = 1.0
    set DamageTrigger.lastRegistered.configured = true
 
    call RegisterDamageEngineEx(function DamageEvent_OnLethal, "Lethal", 1.0, DamageEngine_FILTER_OTHER)
This code runs at around 40 - 50 fps. It's roughly the same amount of event calls as 5.4.2.3.
5.7.1.1 split setup.png

TEST 2
I tried to split every tower and creep into its own event. I never actually finished converting the entire code before scrapping it due to performance issues. I had to re-do this test as I've removed the old scenario where I reported <1 fps. This code below actually crashes the game after a few seconds due to the amount of events called at the start.

JASS:
  // I made a custom function in order to easier registering the events for each type.
  private function RegisterDamageFunction takes integer sourceType, integer targetType, string s, code func, real value, integer eventFilter returns nothing
    call RegisterDamageEngineEx(func, s, value, eventFilter)
    if (sourceType != 0) then
      set DamageTrigger.lastRegistered.sourceType = sourceType
    endif
    if (targetType != 0) then
      set DamageTrigger.lastRegistered.targetType = targetType
    endif
    set DamageTrigger.lastRegistered.damageMin = 1.0
    set DamageTrigger.lastRegistered.configured = true
  endfunction

  //...
  // Here are only a couple of tower events registered
    call RegisterDamageFunction(TOWER_UFIRELORD, 0, "", function OnDamage_UltimateFirelord, 1.0, DamageEngine_FILTER_ATTACK)
    call RegisterDamageFunction(TOWER_ICICLE, 0, "Modifier", function Modifier_Icicle, 1.0, DamageEngine_FILTER_ATTACK)
    call RegisterDamageFunction(TOWER_TRICICLE, 0, "Modifier", function Modifier_Tricicle, 1.0, DamageEngine_FILTER_ATTACK)
    call RegisterDamageFunction(TOWER_UCRYSTAL, 0, "Modifier", function Modifier_UltimateCrystal, 1.0, DamageEngine_FILTER_ATTACK)
    call RegisterDamageFunction(TOWER_VOLTAGE, 0, "Modifier", function Modifier_Voltage, 1.0, DamageEngine_FILTER_ATTACK)
    call RegisterDamageFunction(TOWER_HIGHVOLTAGE, 0, "Modifier", function Modifier_HighVoltage, 1.0, DamageEngine_FILTER_ATTACK)
    call RegisterDamageFunction(TOWER_WATERELEMENTAL, 0, "Modifier", function Modifier_WaterElemental, 1.0, DamageEngine_FILTER_ATTACK)
    call RegisterDamageFunction(TOWER_VWATERELEMENTAL, 0, "Modifier", function Modifier_VolatileWaterElemental, 1.0, DamageEngine_FILTER_ATTACK)
    call RegisterDamageFunction(TOWER_USCORPION, 0, "Modifier", function Modifier_UltimateScorpion, 1.0, DamageEngine_FILTER_ATTACK)
    call RegisterDamageFunction(TOWER_UARCANEORB, 0, "Modifier", function Modifier_UltimateArcaneOrb, 1.0, DamageEngine_FILTER_ATTACK)
    call RegisterDamageFunction(TOWER_UDIABOLIST, 0, "Modifier", function Modifier_UltimateDiabolist, 1.0, DamageEngine_FILTER_ATTACK)
The only event actually firing here is the call RegisterDamageFunction(TOWER_UFIRELORD, 0, "", function OnDamage_UltimateFirelord, 1.0, DamageEngine_FILTER_ATTACK), as that's the tower I'm testing with.

I managed to get a screenshot right before the game crashed. The event calls are declining every second and roughly 2 fps before crash. I also noticed in this screenshot that all the test creeps being attacked were actually killed, due to the current gold, which should be impossible at that time frame.

EDIT: I think the crash wasn't caused by the Damage Engine, but one of my systems, I can't confirm though, but I'm fairly confident. Also, the event calls are reduced as the creeps are killed, that makes sense now, but they shouldn't be killed that quickly.

5.7.1.1 multiple tower_creep events.png

TEST 3
Just for a simple test I only registered the one tower I tested with, nothing else.
call RegisterDamageFunction(TOWER_UFIRELORD, 0, "", function OnDamage_UltimateFirelord, 1.0, DamageEngine_FILTER_ATTACK)

Resulted in 80-90 fps.
5.7.1.1 single tower registered.png

I hope this is helpful, feel free to ask if there's anything odd and I'll try to answer.
 
Last edited:

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Hi Bribe, is it possible to recognize the Order ID from a damage source which is already over by the time the damage happens?

Hi, sorry I am not sure what happened here, as I had a response typed up that must have gotten stuck before sending out.

Short answer: you want a spell reflection system, which is entirely different from a damage detection system.

I'm creating a "Counterspell", which reflects all single target spells back to the caster. Currently it works based on the point in time when the enemy ability is cast. However, ideally I want to be able to activate the Counterspell while the enemy projectile is still in the air, and then reflect it back (= not "starts the effect of an ability", but "DamageEvent becomes Equal to 1.00").

So I need a trigger which recognizes that a) a damage source is a spell, and more importantly, b) which spell it was, so that I can take the same order ID and reflect it.

You probably want some kind of Projectile or Missile system to base your spell on, because those have workarounds which allow you to change the direction of a missile en route.

@lolreported for your reported issue I think I will need more data because it doesn't make any sense to me. Maybe reach out to me on Discord so we can discuss it more.
 
Level 12
Joined
May 16, 2020
Messages
660
Hi, sorry I am not sure what happened here, as I had a response typed up that must have gotten stuck before sending out.

Short answer: you want a spell reflection system, which is entirely different from a damage detection system.

You probably want some kind of Projectile or Missile system to base your spell on, because those have workarounds which allow you to change the direction of a missile en route.

No worries - and thanks, good to know. The reflection should work more generic, not just for triggered missiles (so also for example point and click spells like Storm Bolt). I found this thread which I guess I can use:
[Spell] - Spell Return : Reflect back a spell to the caster


****

Edit: Sorry a separate question (this was probably asked before, but didn't find an answer via search function):

- How can I dected a Critical Hit?
- How can I detect a Bash?
 
Last edited:
So I have a question for a potential fringe case that I encountered once before with a different DDS. Now, I don't know how NextDamageType in DamageEngine works, but I'm assuming that when detecting a damage event, a DamageEvent/DamageModifierEvent fires and NextDamageType is set back to zero? If so, if you deal damage to a target via triggers and for some reason, the unit doesn't take any damage (invulnerable/dead/ethereal/magic immune/or something else), which can mean a damage detection event might not fire at all, will NextDamageType reset or will it remain the last integer it was set as?
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
So I have a question for a potential fringe case that I encountered once before with a different DDS. Now, I don't know how NextDamageType in DamageEngine works, but I'm assuming that when detecting a damage event, a DamageEvent/DamageModifierEvent fires and NextDamageType is set back to zero? If so, if you deal damage to a target via triggers and for some reason, the unit doesn't take any damage (invulnerable/dead/ethereal/magic immune/or something else), which can mean a damage detection event might not fire at all, will NextDamageType reset or will it remain the last integer it was set as?
It will remain as it was set in such cases, however there are ways to circumvent this such as using the Lua variant or calling Damage.apply instead of UnitDamageTarget (probably can also check if UnitDamageTarget returned positive or negative).
 
Level 5
Joined
Jul 31, 2020
Messages
103
Hey Bribe.

Been using your system for a while, it's amazing. Today I wanted to dabble in some armor piercing action, and noticed it simply didn't work, then I searched here, and found that Wazzz reported this issue over a month ago, and you fixed it in a version released on July 1. The current version I'm using is 5.6.2.0 as I haven't encountered any issues, so I haven't been checking regularly for updates. So my only question is, if I wanted to update to the newest one, is there anything I should be on the lookout for? Anything likely to break? Any difficulties in doing so? Just to make sure before making any drastic steps over here.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
- How can I dected a Critical Hit?
- How can I detect a Bash?

Bash deals Force damage type and the DamageEventLevel will be greater than 1. That should narrow it down enough to detect.

A critical strike does not have a clear method of detection. I could compare the raw amount with the damage base, dice and sides per die, and seeing if the damage amount is greater than the max sides, but that could get mixed up with a very large dice variation where a low roll might not register a crit. Also Searing Arrows and others will throw it off.

I see. Would setting NextDamageType to zero manual after each UnitDamageTarget risk disrupting DamageEngine in any way or is it safe to do?
Perfectly safe.
Hey Bribe.

Been using your system for a while, it's amazing. Today I wanted to dabble in some armor piercing action, and noticed it simply didn't work, then I searched here, and found that Wazzz reported this issue over a month ago, and you fixed it in a version released on July 1. The current version I'm using is 5.6.2.0 as I haven't encountered any issues, so I haven't been checking regularly for updates. So my only question is, if I wanted to update to the newest one, is there anything I should be on the lookout for? Anything likely to break? Any difficulties in doing so? Just to make sure before making any drastic steps over here.

If anything this version should be more stable. I'm very committed to squashing every reported bug and try to accommodate every feature request or opportunity.
 
Level 6
Joined
Jul 23, 2018
Messages
243
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
 
Top