Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
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.)
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:
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).
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:
Use WarCraft 3 Version 1.32
If you're upgrading from 3.8 or prior, please delete the entire "Damage Engine" category from your map.
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. --------
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.
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
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...
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.
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.
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.
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.
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
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.
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.
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?
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.
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.
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?
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?
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.
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.
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.
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.
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
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)
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.
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?
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
I hope this is helpful, feel free to ask if there's anything odd and I'll try to answer.
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.
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?
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?
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).
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.
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.
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.
There's no direct way of detecting this kind of events, but you could use something like Damage Interface v1.6 to have custom events like that, and Damage Engine have plugins that allows both systems to coexist.
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 site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
By continuing to use this site, you are consenting to our use of cookies.