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

[General] Attribute scaling abilities

Status
Not open for further replies.
Level 1
Joined
Apr 22, 2015
Messages
2
Hello guys, how can I make abilities scale with hero attributes? For example, I'd like to make an ability that makes my hero do bonus damage on attacks equal to its agility stat, or a mage that shoots a fireball that deals extra damage based on intelligence (I know I can use the trigger Damage target of ability being cast, but then it does damage before the impact of the spell, how do I fix that so it does damage exactly when the spell lands on the target?) etc. Thanks.:thumbs_up:
 
Level 25
Joined
Sep 26, 2009
Messages
2,378
You need to trigger the whole spell. That means even the projectile flying, etc. Then you can easily determine if the projectile is close enough to the enemy to deal damage or not... and if it is, you can cause your own damage modified by stat.
 
Level 3
Joined
Apr 23, 2015
Messages
22
I use this system, it hasn't failed me yet.

  • SpellInitialization
    • Events
      • Unit - A unit Starts the effect of ability
    • Conditions
      • (Ability being cast) equals to Ability
    • Actions
      • Set Caster = (Casting unit)
      • Set Target = (Target unit of ability being cast)
      • Trigger - Add to Spell <gen> the event (Unit - Target takes damage)
  • Spell
    • Events
    • Conditions
      • (Target has buff Buff) equals to Yes
    • Actions
      • Unit - Cause Caster to damage Target, dealing (Damage of your spell) damage of type Spell and damage type Normal
 

XMI

XMI

Level 2
Joined
Mar 28, 2021
Messages
5
I use this system, it hasn't failed me yet.

  • SpellInitialization
    • Events
      • Unit - A unit Starts the effect of ability
    • Conditions
      • (Ability being cast) equals to Ability
    • Actions
      • Set Caster = (Casting unit)
      • Set Target = (Target unit of ability being cast)
      • Trigger - Add to Spell <gen> the event (Unit - Target takes damage)
  • Spell
    • Events
    • Conditions
      • (Target has buff Buff) equals to Yes
    • Actions
      • Unit - Cause Caster to damage Target, dealing (Damage of your spell) damage of type Spell and damage type Normal
This is awesome, thnx!

There's just a tiny bug to this, it seems that if, say you have an ability with a very very low cooldown (like 0seconds) e.g. a storm bolt of such kind, and you selected (while holding Shift down) multiple single targets, only the last target you selected will take the additional damage. I tested it plenty of times in various ways no clue why it does that, however I figured how to prevent this other bug where it run the second trigger "Spell" for like 98 times or so meaning that instead of doing e.g. 100 additional damage once, it does that 98x times, so more like 9800 additional damage, I simply used a bool in my case....

  • Spell Init
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Storm Bolter
    • Actions
      • Set VariableSet TriggeredOnce = False
      • Set VariableSet Caster = (Casting unit)
      • Set VariableSet Target = (Target unit of ability being cast)
      • Trigger - Add to Spell <gen> the event (Unit - Target Takes damage)
  • Spell
    • Events
    • Conditions
      • TriggeredOnce Equal to False
      • (Target has buff Stormbolt Stunned (Pause)) Equal to True
    • Actions
      • Set VariableSet TriggeredOnce = True
      • Game - Display to (All players) the text: (Name of Target)
      • Unit - Cause Caster to damage Target, dealing 100.00 damage of attack type Spells and damage type Normal
 
Last edited:
Level 25
Joined
Sep 26, 2009
Messages
2,378
Afaik stormbolt "deals damage" two times - one is 0 damage and applies stun, the other is the X damage it deals each level... or at least firebolt does that.
So it may be worth checking if damage taken is greater than 0 or 0.001

As for the weird damage, I think you had something of an infinite loop.
Looking at your "Spell" trigger, if the "TriggeredOnce" condition is missing then the following happens:
  1. The trigger starts when "Target_unit" takes damage
  2. The trigger deals damage to Target_unit
  3. Dealing damage via action above once again triggers the "Target_unit takes damage" event, going back to step 1
The above will run as long as unit is alive.

Edit: Also note that if you have very low cooldown (so low that you can shoot 2 or more stormbolts at the nearly same time) then you should make the spell MUI, else the spell will not behave as expected.

Last but not least, you may want to consider using a damage detection system (DDS) for detecting when unit takes damage rather that trigger that yourself. DDS usually takes care of things like the 0 damage and infinte loop I wrote above, etc.
 

XMI

XMI

Level 2
Joined
Mar 28, 2021
Messages
5
Afaik stormbolt "deals damage" two times - one is 0 damage and applies stun, the other is the X damage it deals each level... or at least firebolt does that.
So it may be worth checking if damage taken is greater than 0 or 0.001

As for the weird damage, I think you had something of an infinite loop.
Looking at your "Spell" trigger, if the "TriggeredOnce" condition is missing then the following happens:
  1. The trigger starts when "Target_unit" takes damage
  2. The trigger deals damage to Target_unit
  3. Dealing damage via action above once again triggers the "Target_unit takes damage" event, going back to step 1
The above will run as long as unit is alive.

Edit: Also note that if you have very low cooldown (so low that you can shoot 2 or more stormbolts at the nearly same time) then you should make the spell MUI, else the spell will not behave as expected.

Last but not least, you may want to consider using a damage detection system (DDS) for detecting when unit takes damage rather that trigger that yourself. DDS usually takes care of things like the 0 damage and infinte loop I wrote above, etc.
OMG i feel so stupid for not thinking of this endless loop, like i was literally trying to debug it, but since I'm such a newb (like i literally started getting my hands on the wc3 WE almost 3 weeks ago), I didn't consider the way things flow triggers, I'm more accustomed to coding... :p.. Anyways, thnx!

Thank you a lot for the highly useful informations ♥ I appreciate it as a newcomer

I will look up more about MUI and DDS thanks again, also do you have anything to suggest e.g. for things like Changing the Cooldowns of Abilities like e.g. item that grants hero -50% ability cooldown, or Affecting %wise the Spell Damage of Abilities e.g. or buff that grants +50% spell/ability damage? Thanks in advance ^^
 
Level 25
Joined
Sep 26, 2009
Messages
2,378
well, I am not sure if there is any native way of doing so (i.e. an already existing buff/item). You can trigger this of course, but it has its own drawbacks and things to watch out for.

Increasing damage by X or X% if your unit has item / buff is rather easy - just use DDS. The DDS detects "damage taken" by a unit before the damage is actually applied, so you can fiddle with the damage value (like nullify the damage - so for example a unit cannot be brought below 1hp; or increase the damage).
In your case you would like to increase the damage. For example if you use Bribe's DDS (Damage Engine 5.7.1.2) you would modify the damage like this:
  • Untitled Trigger 002
    • Events
      • Game - DamageEvent becomes Equal to 1.00
    • Conditions
      • Or - Any (Conditions) are true
        • Conditions
          • DamageEventSource Equal to Your_unit
          • (Unit-type of DamageEventSource) Equal to Your_unit_type
      • Or - Any (Conditions) are true
        • Conditions
          • (DamageEventSource has buff Your_buff) Equal to True
          • (DamageEventSource has an item of type Your_item) Equal to True
    • Actions
      • Set VariableSet DamageEventAmount = (DamageEventAmount x 1.50)
      • Set VariableSet DamageEventAmount = (DamageEventAmount + (Real((Strength of DamageEventSource (Exclude bonuses)))))
I put there multiple conditions to show how you can check the event by unit/unit-type and checking the buff/item. From the trigger actions you would need only one - I used two as an example:
  • In one case the damage is increased by flat 50%
  • in the other the damage is increased by Strength attribute of the unit.
The trigger will increase the overall damage of "Your_unit". You can differentiate between melee, ranged and spell damage (and the system even detects damage type), but afaik you cannot detect which spell actually did the damage.
For example you may have a very slow moving firebolt (deals fire spell damage) and before the firebolt hits the target, you may hit the target with flamestrike (also deals fire spell damage) from the same caster. From triggers you will have very hard time detecting which of the two spells dealt the damage... so this approach has its own drawbacks that have to be considered.


You can change the damage and cooldown of an ability for specific unit via triggers as well, but there are multiple drawbacks:
  1. You need to detect when unit should gain bonuses to the spell and when it should lose those bonuses.
  2. You would need to track the original damage/cooldown of the spell (this can be further complicated if damage/cooldown changes per level)
  3. You would have to make sure that if multiple items/buffs can affect you unit's spell damage/cooldown at the same time, that you properly stack the effects and properly remove them (meaning that the spell properties after modifiers are removed are the same as the spell properties before modifiers are applied)
  4. You need to take into account edge cases like when unit dies (and thus may be resurrected later) or when hero levels up a spell that has been modified.
  5. Very important - what you want to modify is also very important - some fields are universal (i.e. cooldown) while some fields are not (i.e. damage).

Also, since the trigger actions that modify specific unit's properties (like ability damage, etc.) came with reforged, many of them are buggy or have some quirks. Check the trigger below - it decreases specific unit's firebolt damage from the base 100 damage down to 10, but lowers cooldown from base 8.00 seconds to 0.5 second.
  • Untitled Trigger 001
    • Events
      • Player - Player 1 (Red) skips a cinematic sequence
    • Conditions
    • Actions
      • Ability - Set Ability: (Unit: Footman 0000 <gen>'s Ability with Ability Code: Firebolt (Neutral Hostile))'s Real Level Field: Cooldown ('acdn') of Level: 0 to 0.50
      • Ability - Set Ability: (Unit: Footman 0000 <gen>'s Ability with Ability Code: Firebolt (Neutral Hostile))'s Real Level Field: Damage ('Ucs1') of Level: 0 to 10.00
Now notice a few things:
  • The actions are set for Level 0 - that is because some of these actions actually use zero-based indexing (meaning first level has index 0... so by settings the value here to 0, I am actually affecting level 1 of the ability). But some other actions actually use one-based indexing (so index 1 = level 1). This discrepancy makes it really hard to fix things if you are not aware of it
  • In both actions I modify real fields Cooldown and Damage. But for example the real field "Damage" is present multiple times in the list (but at different positions, since the list is not sorted). There are actually at least 5 "Damage" fields to choose from and each has different code in brackets (i.e. "Damage ('Hbz2')", "Damage ('Ucs1')"). In the case of Firebolt, the "Damage ('Hbz2')" field does not affect the spell's damage while "Damage ('Ucs1')" does change it (while the Damage field for the spell in Object Editor actually has code 'Htb1'... go figure). So this again serves to further confuse anyone using these actions...
To my knowledge there is no native way to get all spells of a given unit, so you would need to make a list of spells per unit-type that your items/buffs can modify.

As an example, I created triggers that reduce Blood Mage's cooldowns by 50% for as long as he has Orb Of Lightning. Do note that the edge cases (like dying or leveling up the ability, etc.) are not taken care of. It is just an example, a proper system would become more complex.

  • Map initialization
    • Events
      • Map initialization
    • Conditions
    • Actions
      • -------- Store all abilities of the blood-mage in an array --------
      • Set VariableSet BloodMage_Abils[1] = Flame Strike
      • Set VariableSet BloodMage_Abils[2] = Banish
      • Set VariableSet BloodMage_Abils[3] = Siphon Mana
      • Set VariableSet BloodMage_Abils[4] = Phoenix
      • -------- --------------------------------------------------------------------------------------------------------------- --------
      • -------- Store the base cooldown of each of the four abilities --------
      • -------- Note that the index must match that of the spell --------
      • -------- i.e. Flamestrike is stored under index 1 and its cooldown (10 sec) is also stored under index 1 --------
      • Set VariableSet BloodMage_AbilsBaseCD[1] = 10.00
      • Set VariableSet BloodMage_AbilsBaseCD[2] = 0.00
      • Set VariableSet BloodMage_AbilsBaseCD[3] = 6.00
      • Set VariableSet BloodMage_AbilsBaseCD[4] = 180.00
  • Blood Mage Acquires Orb
    • Events
      • Unit - A unit Acquires an item
    • Conditions
      • (Unit-type of (Triggering unit)) Equal to Blood Mage
      • (Item-type of (Item being manipulated)) Equal to Orb of Lightning
    • Actions
      • -------- The loop iterates over the arrays we set up in Map Initialization trigger --------
      • -------- Since we used indices 1,2,3 and 4, the loop is set to iterate from 1 to 4 --------
      • For each (Integer loopInt) from 1 to 4, do (Actions)
        • Loop - Actions
          • Set VariableSet AbilityToUpdate = (Unit: (Triggering unit)'s Ability with Ability Code: BloodMage_Abils[loopInt])
          • Set VariableSet AbilityIndex = ((Level of BloodMage_Abils[loopInt] for (Triggering unit)) - 1) //value is decreased by 1 due to zero-based indexing
          • Set VariableSet NewCooldown = (BloodMage_AbilsBaseCD[loopInt] x 0.50)
          • Ability - Set Ability: AbilityToUpdate's Real Level Field: Cooldown ('acdn') of Level: AbilityIndex to NewCooldown
  • Blood Mage Loses Orb
    • Events
      • Unit - A unit Loses an item
    • Conditions
      • (Unit-type of (Triggering unit)) Equal to Blood Mage
      • (Item-type of (Item being manipulated)) Equal to Orb of Lightning
    • Actions
      • For each (Integer loopInt) from 1 to 4, do (Actions)
        • Loop - Actions
          • Set VariableSet AbilityToUpdate = (Unit: (Triggering unit)'s Ability with Ability Code: BloodMage_Abils[loopInt])
          • Set VariableSet AbilityIndex = ((Level of BloodMage_Abils[loopInt] for (Triggering unit)) - 1)
          • Ability - Set Ability: AbilityToUpdate's Real Level Field: Cooldown ('acdn') of Level: AbilityIndex to BloodMage_AbilsBaseCD[loopInt]
 
Status
Not open for further replies.
Top