Element RPG System

Level 2
Joined
Jul 1, 2020
Messages
8
Hello! I been keep working on my RPG map for some time, slow but steady, now i try to make a element system like on almost all rpg games, i try and seek but never find a good reference to follow, so now i ask here

What I'm trying to do is a add elements that affect enemies, abilities, and items, like a monster being weak, resistant, immune, or absorbing certain elements.

For example, a water elemental absorbs water (recovering health with water abilities and spells) but is weak to lightning (taking more damage from lightning abilities and spells).

But it should also be affected by items, for example when a hero takes a "ring," he gain resistance to a specific element.

Any help or references would be appreciated. :thumbs_up:
 
There isn't any good/easy way to do this.

First, very limited, option is to re-use gameplay constants and modify damage bonus of all attack types against all armor types. For example "Small" armor could be considered "Water" armor which all water elementals have. Heavy armor could be "Fire" armor for fire-based creatures, etc.
You could consider for example "Magic" attack type to be "Lightning" attack. Then in gameplay constants you would set that "Magic" attack type deals bonus damage to "Small" armor to simulate the lightning damage bonus to water-based creatures.

The disadvantage of this option is simple: you cannot add new attack type nor armor type, so you are limited to the base 8 attack types and 8 armor types.

----
Second option is to trigger everything yourself, which could give you more freedom, but requires way more work.
For example, base resistances, which are tied to types (unit-type, item-type, etc.) and (de)buffs could be stored in hashtable.
Resistances of actual units could be stored in an array and would represent the sum of:
  • unit's base resistance (loaded from hashtable by its unit-type)
  • resistances given to the unit from items
  • resistances given to unit by buffs.
This could work well if you use unit indexer, as such unit would have a unique number stored in its custom value, which you could use to load resistances.

Next, you would have a trigger with 'A Unit about to take damage' event, use the target's custom value to detect their resistance and modify damage done accordingly.

Check triggers below as an example:

  • Map Initialization
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Hashtable - Create a hashtable
      • Set VariableSet ResistanceHashtable = (Last created hashtable)
      • -------- ------------------------------------------------------ --------
      • Set VariableSet UnitType = Water Elemental (Level 1)
      • Custom script: set udg_RawCode = udg_UnitType
      • Hashtable - Save 150.00 as (Key WaterResistance.) of RawCode in ResistanceHashtable.
      • -------- ------------------------------------------------------ --------
      • Set VariableSet UnitType = Lava Spawn (Level 1)
      • Custom script: set udg_RawCode = udg_UnitType
      • Hashtable - Save -50.00 as (Key WaterResistance.) of RawCode in ResistanceHashtable.
      • -------- ------------------------------------------------------ --------
      • Set VariableSet ItemType = Ring of Protection +1
      • Custom script: set udg_RawCode = udg_ItemType
      • Hashtable - Save 25.00 as (Key WaterResistance.) of RawCode in ResistanceHashtable.
This initializes the 'Resistance' hashtable with data. Doing this in GUI bloats the trigger with many actions, I would advice creating a custom jass function and just calling that directly.
Anyway, in that trigger you can see that I initialize 'WaterResistance' for Water Elemental to 150.00, which stands for 150%, so the assumption here is that water damage would heal Water Elemental for half of the damage done instead of damaging it. On the other hand Lava Spawn would have -50% resistance, meaning it would take bonus 50% damage.
There's also a Ring of Protection stored, which give +25% water resistance.

  • Resistance Unit creation
    • Events
      • Unit - A unit enters (Playable map area)
    • Conditions
    • Actions
      • -------- assuming here that the unit has already been detected by unit indexer and has a unique number assigned to its custom value --------
      • -------- --------------------------------------------- --------
      • Set VariableSet CV = (Custom value of (Triggering unit))
      • Set VariableSet UnitType = (Unit-type of (Triggering unit))
      • Custom script: set udg_RawCode = udg_UnitType
      • -------- --------------------------------------------- --------
      • Set VariableSet WaterResistances[CV] = (Load (Key WaterResistance.) of RawCode from ResistanceHashtable.)
      • -------- ... the above would repeat for each elemental resistance --------
This trigger detects when a unit was created/appears in map. It loads all resistances tied to its type from the hashtable and stores that in an array. The array represents resistances of specific units.
For example, if this was Water Elemental (Level 1), it would load the '150%' water resistance.

  • Resistance Item acquisition
    • Events
      • Unit - A unit Acquires an item
    • Conditions
    • Actions
      • Set VariableSet CV = (Custom value of (Triggering unit))
      • Set VariableSet ItemType = (Item-type of (Item being manipulated))
      • Custom script: set udg_RawCode = udg_ItemType
      • -------- --------------------------------------------- --------
      • Set VariableSet Resistance = (Load (Key WaterResistance.) of RawCode from ResistanceHashtable.)
      • Set VariableSet WaterResistances[CV] = (WaterResistances[CV] + Resistance)
      • -------- ... the above would repeat for each elemental resistance --------
  • Resistance Item loss
    • Events
      • Unit - A unit Loses an item
    • Conditions
    • Actions
      • Set VariableSet CV = (Custom value of (Triggering unit))
      • Set VariableSet ItemType = (Item-type of (Item being manipulated))
      • Custom script: set udg_RawCode = udg_ItemType
      • -------- --------------------------------------------- --------
      • Set VariableSet Resistance = (Load (Key WaterResistance.) of RawCode from ResistanceHashtable.)
      • Set VariableSet WaterResistances[CV] = (WaterResistances[CV] - Resistance)
      • -------- ... the above would repeat for each elemental resistance --------
These two triggers showcase how item resistances could work. When unit acquires/loses an item, we load that item's resistances from hashtable and add/subtract it from total resistances of the unit manipulating that item.
A Water Elemental (Level 1) acquiring Ring of Protection +1 would gain +25% water resistance. It would add that to its base resistance of 150% for a total of 175%.

  • Damage Resistance Bonus
    • Events
      • Unit - A unit About to take damage
    • Conditions
    • Actions
      • -------- assuming we know that the damage done is 'water' damage --------
      • Set VariableSet CV = (Custom value of (Damage Target))
      • Set VariableSet Resistance = WaterResistances[CV]
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Resistance Greater than or equal to 100.00
        • Then - Actions
          • Set VariableSet HealAmount = ((Resistance - 100.00) x (0.01 x (Damage taken)))
          • Unit - Set life of (Damage Target) to ((Life of (Damage Target)) + HealAmount)
          • Event Response - Set Damage of Unit Damaged Event to 0.00
        • Else - Actions
          • Event Response - Set Damage of Unit Damaged Event to (((100.00 - Resistance) x 0.01) x (Damage taken))
Finally, this trigger detects damage about to be done, loads target's water resistance and check if that resistance is above 100% (in which case, the damage is completely absorbed and may heal the target instead). If resistance is below 100%, the damage done is modified.

For example, Water Elemental (Level 1) with Ring of Power +1 will have 175% water resistance. As it is above 100%, it would take the remaining 75% and for that amount heal the elemental, e.g. a 200 'water' damage would heal the unit for 150.

The problem here is how to detect damage type. If damage type is tied to unit-type, then you could use similar approach to resistances - in hashtable you would store damage type of each unit-type.
However if you want to use WC3's damage type component, then you would need to trigger all your spells, as the default WC3 spells have a pre-defined damage type which cannot be changed (for example Shockwave always deals attack type Spells, damage type Sonic, no matter how you modify it).
 
I worked on something like that using exclusively dummy abilities just to represent properties (e.g. 1 ability Absorb Fire, 1 Weakness Water etc.), then have 1 dummy caster unit per element, then you can detect if the damage source is e.g. the Fire dummy and if the target has the Resist Fire ability, then you do damage x 50%, and so on

Pros: it also works with items, if you do an integer check to see whether an unit has X ability level 1, it will detect abilities contains in items carried, then it's only a matter of giving these abilities to your units and the system does the rest
Cons: all elemental damage must be triggered and dealt by dummy units, so that can be annoying
 
That's right, turn to be a little more complicated that i though.
Have set each enemies they element setting and detect the element damage type, some ideas was make each skill that use elements a trigger to set the element damage type and make a unit index is actually a good idea, this already give me some extra ideas that i will try.
I will been working on that and post my result or in case I get stuck with the trigger will ask help again, thank to both of you
If someone else have another solution I would appreciate it
 
All right, after 2 days working on this non-stop (it won't let me sleep) somehow I manage to make it work
  • MonsterElementSetup
    • Events
      • Map initialization
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Unit-type of MI_Unit) Equal to Fire Elemental
        • Then - Actions
          • Set VariableSet AbsorbeFire[MDX] = True
          • Set VariableSet WeakIce[MDX] = True
          • Set VariableSet ResistThunder[MDX] = True
          • Set VariableSet ImmuneWater[MDX] = True
        • Else - Actions
  • MonsterIndexSetup
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Set VariableSet MonsterIndex = 0
      • Unit Group - Pick every unit in (Units in (Playable map area) owned by Neutral Hostile) and do (Actions)
        • Loop - Actions
          • Set VariableSet MonsterIndex = (MonsterIndex + 1)
          • Set VariableSet MDX = MonsterIndex
          • Set VariableSet MD_Unit = (Picked unit)
          • Set VariableSet MonsterStoreUnit[MDX] = MD_Unit
  • Frostbolt Trigger
    • Events
      • Unit - A unit Begins casting an ability
    • Conditions
      • (Ability being cast) Equal to Frostbolt
    • Actions
      • Set VariableSet BaseDamage = (15.00 + (Real((Intelligence of (Triggering unit) (Include bonuses)))))
      • Set VariableSet FinalDamage = BaseDamage
      • Set VariableSet MDX = 0
      • For each (Integer A) from 1 to MonsterIndex, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • MonsterStoreUnit[(Integer A)] Equal to (Target unit of ability being cast)
            • Then - Actions
              • Set VariableSet MDX = (Integer A)
            • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • WeakIce[MDX] Equal to True
        • Then - Actions
          • Set VariableSet FinalDamage = (FinalDamage x 2.00)
          • Floating Text - Create floating text that reads |cffff0000Weak!|r above (Target unit of ability being cast) with Z offset 0.00, using font size 10.00, color (100.00%, 100.00%, 100.00%), and 0.00% transparency
          • Floating Text - Set the velocity of (Last created floating text) to 100.00 towards 45.00 degrees
          • Floating Text - Change (Last created floating text): Disable permanence
          • Floating Text - Change the lifespan of (Last created floating text) to 2.00 seconds
          • Floating Text - Change the fading age of (Last created floating text) to 0.50 seconds
          • Unit - Cause (Triggering unit) to damage (Target unit of ability being cast), dealing FinalDamage damage of attack type Spells and damage type Normal
        • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • ResistIce[MDX] Equal to True
            • Then - Actions
              • Set VariableSet FinalDamage = (FinalDamage x 0.50)
              • Floating Text - Create floating text that reads |cffd45e19Resist!|r above (Target unit of ability being cast) with Z offset 0.00, using font size 10.00, color (100.00%, 100.00%, 100.00%), and 0.00% transparency
              • Floating Text - Change (Last created floating text): Disable permanence
              • Floating Text - Set the velocity of (Last created floating text) to 100.00 towards 135.00 degrees
              • Floating Text - Change the lifespan of (Last created floating text) to 2.00 seconds
              • Floating Text - Change the fading age of (Last created floating text) to 0.50 seconds
              • Unit - Cause (Triggering unit) to damage (Target unit of ability being cast), dealing FinalDamage damage of attack type Spells and damage type Normal
            • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • ImmuneIce[MDX] Equal to True
                • Then - Actions
                  • Set VariableSet FinalDamage = 0.00
                  • Floating Text - Create floating text that reads |cffffff00Immune!|r above (Target unit of ability being cast) with Z offset 0.00, using font size 10.00, color (100.00%, 100.00%, 100.00%), and 0.00% transparency
                  • Floating Text - Change (Last created floating text): Disable permanence
                  • Floating Text - Set the velocity of (Last created floating text) to 100.00 towards 225.00 degrees
                  • Floating Text - Change the lifespan of (Last created floating text) to 2.00 seconds
                  • Floating Text - Change the fading age of (Last created floating text) to 0.50 seconds
                  • Unit - Cause (Triggering unit) to damage (Target unit of ability being cast), dealing FinalDamage damage of attack type Spells and damage type Normal
                • Else - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • AbsorbeIce[MDX] Equal to True
                    • Then - Actions
                      • Unit - Set life of (Target unit of ability being cast) to ((Life of (Target unit of ability being cast)) + FinalDamage)
                      • Floating Text - Create floating text that reads |cff00ff00Absorb!|r above (Target unit of ability being cast) with Z offset 0.00, using font size 10.00, color (100.00%, 100.00%, 100.00%), and 0.00% transparency
                      • Floating Text - Change (Last created floating text): Disable permanence
                      • Floating Text - Set the velocity of (Last created floating text) to 100.00 towards 315.00 degrees
                      • Floating Text - Change the lifespan of (Last created floating text) to 2.00 seconds
                      • Floating Text - Change the fading age of (Last created floating text) to 0.50 seconds
                    • Else - Actions
                      • Unit - Cause (Triggering unit) to damage (Target unit of ability being cast), dealing FinalDamage damage of attack type Spells and damage type Normal
      • Special Effect - Destroy (Last created special effect)
I'm actually scare to touch something, the only problem that I found was the this don't works with respawn enemies, i try period time but that don't work either, so i need you opinion, what do you think guys?
 
Last edited:
Back
Top