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

[Trigger] Units not added properly to unit group?

Status
Not open for further replies.
Hello

I am trying to make a spell that absorbs all damage over 15 seconds, then deals 20% of that damage to all units within 350 range that hit the shielded unit. It kinda works, but the units that are actually damaged at the end of the shield time seems to be picked at random. Here's how it looks (please look away from possible leaks if any, it will be cleaned up and fixed when the spell mechanics are working properly).

  • Sacred Shield Spell
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • ((Ability being cast) Equal to Sacred Shield LvL 1 ) or ((Ability being cast) Equal to Sacred Shield LvL 2 )
    • Actions
      • Set ShieldBoolean = True
      • Set ShieldCaster = (Triggering unit)
      • Set SacredShieldLocation[1] = (Position of ShieldCaster)
      • Special Effect - Create a special effect attached to the weapon of ShieldCaster using Abilities\Spells\Orc\Disenchant\DisenchantSpecialArt.mdl
      • Special Effect - Create a special effect at SacredShieldLocation[1] using Abilities\Spells\Items\ResourceItems\ResourceEffectTarget.mdl
      • Unit - Set Unit: ShieldCaster's Integer Field: Armor Type ('uarm') to Value: ARMOR_TYPE_ETHEREAL
      • Special Effect - Create a special effect attached to the origin of ShieldCaster using SacredShield.mdx
      • Set ShieldEffect = (Last created special effect)
      • Sound - Play ManaShieldCaster1 <gen> at 100.00% volume, located at SacredShieldLocation[1] with Z offset 0.00
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Level of Sacred Shield LvL 1 for ShieldCaster) Equal to 1
        • Then - Actions
          • Wait 12.00 seconds
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Level of Sacred Shield LvL 2 for ShieldCaster) Equal to 1
        • Then - Actions
          • Wait 15.00 seconds
        • Else - Actions
      • Unit - Set Unit: ShieldCaster's Integer Field: Armor Type ('uarm') to Value: ARMOR_TYPE_FLESH
      • Set ShieldUnitsNearby = (Units within 350.00 of SacredShieldLocation[1] matching ((((Matching unit) is in ShieldUnitGroup) Equal to True) and (((Matching unit) is alive) Equal to True)))
      • Unit Group - Pick every unit in ShieldUnitsNearby and do (Actions)
        • Loop - Actions
          • Camera - Shake the camera for Player 1 (Red) with magnitude 8.00
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Level of Sacred Shield LvL 1 for ShieldCaster) Equal to 1
            • Then - Actions
              • Unit - Cause ShieldCaster to damage (Picked unit), dealing (DamageTotalShield x 0.15) damage of attack type Spells and damage type Magic
            • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Level of Sacred Shield LvL 2 for ShieldCaster) Equal to 1
            • Then - Actions
              • Unit - Cause ShieldCaster to damage (Picked unit), dealing (DamageTotalShield x 0.20) damage of attack type Spells and damage type Magic
            • Else - Actions
          • Special Effect - Create a special effect attached to the chest of (Picked unit) using Abilities\Spells\Human\HolyBolt\HolyBoltSpecialArt.mdl
          • Special Effect - Destroy (Last created special effect)
      • Set ShieldBoolean = False
      • Custom script: call DestroyGroup(udg_ShieldUnitsNearby)
      • Wait 0.00 seconds
      • Camera - Stop swaying/shaking the camera for Player 1 (Red)
      • Unit Group - Pick every unit in ShieldUnitGroup and do (Actions)
        • Loop - Actions
          • Unit Group - Remove (Picked unit) from ShieldUnitGroup
      • Set ShieldCaster = No unit
      • Set DamageTotalShield = 0.00
      • Special Effect - Destroy ShieldEffect
      • Custom script: call RemoveLocation(udg_SacredShieldLocation[1])
      • Custom script: call RemoveLocation(udg_SacredShieldLocation[2])

  • Accumulate Damage
    • Events
      • Game - DamageEvent becomes Equal to 1.00
    • Conditions
      • ShieldBoolean Equal to True
      • DamageEventSource Not equal to ShieldCaster
      • (DamageEventSource belongs to an enemy of (Owner of ShieldCaster)) Equal to True
      • DamageEventTarget Equal to ShieldCaster
    • Actions
      • Set DamageTotalShield = (DamageTotalShield + DamageEventPrevAmt)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ((Picked unit) is Magic Immune) Equal to False
          • ((Picked unit) is A structure) Equal to False
          • ((Picked unit) is invulnerable) Equal to False
        • Then - Actions
          • Unit Group - Add DamageEventSource to ShieldUnitGroup
        • Else - Actions
      • Game - Display to (All players) the text: (String(DamageTotalShield))

  • Absorb Damage
    • Events
      • Game - DamageModifierEvent becomes Equal to 1.00
    • Conditions
      • ShieldBoolean Equal to True
      • (DamageEventSource belongs to an enemy of (Owner of ShieldCaster)) Equal to True
      • DamageEventTarget Equal to ShieldCaster
    • Actions
      • Set DamageEventAmount = 0.00



Are any of you able to see what might be wrong here?
 
Level 39
Joined
Feb 27, 2007
Messages
5,010
Bo is correct, that's the error. I have some suggestions:
  • Why are the two levels of the ability separate abilities? You can check the level with an integer comparison or save it as an integer and use it in computation: damagereturn = 0.10 + 0.05*LVL.
  • Everything happening in Accumulate Damage could also just happen in Absorb Damage instead so you would have one less trigger.
  • I presume the spell is channeled since the position isn't being updated constantly if the caster was moving? If the spell is cancelled early or the unit is stunned/silenced out of the channel time the spell will continue to function even though it should have ended. Instead of the Waits, a better method (since you don't seem to care if this is MUI anyway) would be to use a separate trigger that detects when a unit Stops Casting the ability (finishes only applies when the channel fully completes if you want to use that instead).
  • You could add those if-block conditions to the main trigger conditions itself and not use the if-block(s).
 
Why are the two levels of the ability separate abilities? You can check the level with an integer comparison or save it as an integer and use it in computation: damagereturn = 0.10 + 0.05*LVL.

The hero doesn't get abilities the normal way, so I use the leftover space for more abilities. If I add an ability with more than one level that space will be occupied by the red cross icon that lets me choose abilities when I level up.

Everything happening in Accumulate Damage could also just happen in Absorb Damage instead so you would have one less trigger.

I see. I will merge them then.

I presume the spell is channeled since the position isn't being updated constantly if the caster was moving? If the spell is cancelled early or the unit is stunned/silenced out of the channel time the spell will continue to function even though it should have ended. Instead of the Waits, a better method (since you don't seem to care if this is MUI anyway) would be to use a separate trigger that detects when a unit Stops Casting the ability (finishes only applies when the channel fully completes if you want to use that instead).

The spell is instant, non channeled. I just haven't added a hero dies/cancels spell function yet.

EDIT: Aaaaand that's the problem of course. I'm not updating the position of the caster before the damage is applied :p

You could add those if-block conditions to the main trigger conditions itself and not use the if-block(s).

That is true, I will change it accordingly.


The condition at the damage trigger which checks for (Picked unit) is most likely wrong, because (Picked unit) is meant to work only for PickAllUnitsInGroup actions. (Picked unit) is like a global variable, always having the last picked unit stored from ... any PickAllUnitsInGroup action.

According to this logic shouldn't this trigger also not be working?
  • Untitled Trigger 001
    • Events
      • Player - Player 1 (Red) types a chat message containing 1 as An exact match
    • Conditions
    • Actions
      • Unit Group - Pick every unit in (Units in (Playable map area)) and do (Actions)
        • Loop - Actions
          • Unit Group - Add (Picked unit) to GenericGroup


  • Untitled Trigger 001 Copy
    • Events
      • Player - Player 1 (Red) types a chat message containing 2 as An exact match
    • Conditions
    • Actions
      • Unit Group - Pick every unit in GenericGroup and do (Actions)
        • Loop - Actions
          • Unit - Remove (Picked unit) from the game

The above trigger however works just fine, and follows the same logic as in my main trigger. The shield trigger just picks all units in a unit group that matches condition and applies damage to the picked units.


EDIT:

LOL, I didn't realize I had Picked unit references in my if then else block. That also explains it. Just sloppy from my side of course. I am guessing this is what @IcemanBo was talking about then.

  • Accumulate Damage
    • Events
      • Game - DamageEvent becomes Equal to 1.00
    • Conditions
      • ShieldBoolean Equal to True
      • DamageEventSource Not equal to ShieldCaster
      • (DamageEventSource belongs to an enemy of (Owner of ShieldCaster)) Equal to True
      • DamageEventTarget Equal to ShieldCaster
    • Actions
      • Set DamageTotalShield = (DamageTotalShield + DamageEventPrevAmt)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ((Picked unit) is Magic Immune) Equal to False
          • ((Picked unit) is A structure) Equal to False
          • ((Picked unit) is invulnerable) Equal to False
        • Then - Actions
          • Unit Group - Add DamageEventSource to ShieldUnitGroup
        • Else - Actions
      • Game - Display to (All players) the text: (String(DamageTotalShield))
 
Last edited:
Unit abilities can have multiple levels and don't add the level up command card icon.

That's not the only reason. The hero you play is very frequently replaced with another hero. There might be an easier way to go about it but the hero system I have right now is working very well.

How would you go about doing it?
 
Level 39
Joined
Feb 27, 2007
Messages
5,010
What the other reasons are is unclear to me. Why would replacing the unit frequently have relevance to this 2-abilities-1-level vs. 1-abilitiy-2-levels choice? In either case you have to add the appropriate ability (at the appropriate level) to the other unit when it's replaced. Without having any knowledge of what you're doing and why, my best answer is that I would use 1 ability with 2 levels and I would morph the heroes into each other with a reverse bear form. If the abilities are added with triggers (rather than the OE) I would also use UnitMakeAbilityPermanent() on them so they are retained when morphing.
 
What the other reasons are is unclear to me. Why would replacing the unit frequently have relevance to this 2-abilities-1-level vs. 1-abilitiy-2-levels choice? In either case you have to add the appropriate ability (at the appropriate level) to the other unit when it's replaced. Without having any knowledge of what you're doing and why, my best answer is that I would use 1 ability with 2 levels and I would morph the heroes into each other with a reverse bear form. If the abilities are added with triggers (rather than the OE) I would also use UnitMakeAbilityPermanent() on them so they are retained when morphing.

Morphing isn't an alternative as the hero changes between 5 different models, and the abilities, stats, max HP/Mana, items, and other things are saved and transferred every time. If I'm not mistaken a morphing ability only enables you to change back and forth to/from two heroes/units?

The hero has many abilities with everything from 1 to 5 different ability levels. I found that removing the lower level ability and replacing it with a higher level ability as separate spells was the easiest way to go about the hero system I have in place.
 
Level 39
Joined
Feb 27, 2007
Messages
5,010
I said “reverse” bear form for a reason; it works kind of like Chaos should have if it wasn’t somewhat bugged. Read the tutorial I linked. If the 5 forms are sequential you would need 5 morph abilities (or 9 if it goes both ways). If any form can change into any other form you would need 20 morph abilities. I would store information about which morph ability to use in a hashtable with the starting and ending forms as a key.

That might sound like a lot of OE data (it’s not in the grand scheme of things) but the advantage is massive: the unit keeps its items, current order, and buffs. Any variable references to the unit are preserved instead of needing to be reset.
 
I said “reverse” bear form for a reason; it works kind of like Chaos should have if it wasn’t somewhat bugged. Read the tutorial I linked. If the 5 forms are sequential you would need 5 morph abilities (or 9 if it goes both ways). If any form can change into any other form you would need 20 morph abilities. I would store information about which morph ability to use in a hashtable with the starting and ending forms as a key.

That might sound like a lot of OE data (it’s not in the grand scheme of things) but the advantage is massive: the unit keeps its items, current order, and buffs. Any variable references to the unit are preserved instead of needing to be reset.

It sounds like a good way to go about it. I could have used that system instead probably, but I have already put a lot of work into an already working system, so changing it at this point would be too much of a hassle. The only downside to using my system over this one is the fact that my unit doesn't keep the buffs. To be honest I didn't even think of that. Here's how every single replace trigger I have looks (there are 16 of them in total, to seamlessly change back and forth between heroes):

  • Evil hero change 1
    • Events
      • Game - AlingnmentPoints becomes Less than or equal to -20.00
    • Conditions
    • Actions
      • Set HeroCurrentHP = (Life of Hero)
      • Set HeroCurrentMana = (Mana of Hero)
      • Set HeroInt = (Intelligence of Hero (Exclude bonuses))
      • Set HeroStr = (Strength of Hero (Exclude bonuses))
      • Set HeroAgi = (Agility of Hero (Exclude bonuses))
      • Set HeroLevel = (Level of Hero)
      • Set ItemSlot_1 = (Item carried by Hero in slot 1)
      • Set ItemSlot_2 = (Item carried by Hero in slot 2)
      • Set ItemSlot_3 = (Item carried by Hero in slot 3)
      • Set ItemSlot_4 = (Item carried by Hero in slot 4)
      • Set ItemSlot_5 = (Item carried by Hero in slot 5)
      • Set ItemSlot_6 = (Item carried by Hero in slot 6)
      • Unit - Replace Hero with a Lythienne Yindan Shandris model using The old unit's relative life and mana
      • Special Effect - Create a special effect attached to the origin of Hero using GeneralHeroGlow.mdx
      • Set Hero = (Last replaced unit)
      • Unit - Change color of Hero to Red
      • Hero - Set Hero Hero-level to HeroLevel, Hide level-up graphics
      • Special Effect - Create a special effect attached to the origin of Hero using Abilities\Spells\Undead\DeathCoil\DeathCoilSpecialArt.mdl
      • Selection - Select Hero for (Owner of Hero)
      • Hero - Give ItemSlot_1 to Hero
      • Hero - Give ItemSlot_2 to Hero
      • Hero - Give ItemSlot_3 to Hero
      • Hero - Give ItemSlot_4 to Hero
      • Hero - Give ItemSlot_5 to Hero
      • Hero - Give ItemSlot_6 to Hero
      • Hero - Modify Strength of Hero: Set to HeroStr
      • Hero - Modify Agility of Hero: Set to HeroAgi
      • Hero - Modify Intelligence of Hero: Set to HeroInt
      • Trigger - Turn on Evil hero change back 4 <gen>
      • Trigger - Turn off (This trigger)
      • Special Effect - Create a special effect attached to the origin of Hero using Aura.mdx
      • Unit - Add Necrotic Blast LvL 1 to Hero
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Hero level of Hero) Greater than or equal to 2
        • Then - Actions
          • Unit - Add Rapid Fire to Hero
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Hero level of Hero) Greater than or equal to 6
        • Then - Actions
          • Unit - Add Multishot (neutral) to Hero
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Hero level of Hero) Greater than or equal to 10
        • Then - Actions
          • Unit - Add Monster Lure to Hero
        • Else - Actions
      • Trigger - Run Replace Pouch <gen> (checking conditions)
      • Trigger - Run Replace Rune <gen> (checking conditions)
      • If (InCavesInteger Equal to 1) then do (Unit - Add Item Sight Range Bonus (Custom) to Hero) else do (Do nothing)
      • If (FireRuneInteger Greater than or equal to 1) then do (Special Effect - Create a special effect attached to the origin of Hero using Providence Aura.mdx) else do (Do nothing)
      • If (NatureRuneInteger Greater than or equal to 1) then do (Special Effect - Create a special effect attached to the origin of Hero using Providence Aura Green.mdx) else do (Do nothing)
      • If (NatureRuneInteger Equal to 1) then do (Unit - Add Mana Regeneration 1 to Hero) else do (Do nothing)
      • If (NatureRuneInteger Equal to 2) then do (Unit - Add Mana Regeneration 2 to Hero) else do (Do nothing)
      • If (NatureRuneInteger Equal to 3) then do (Unit - Add Mana Regeneration 3 to Hero) else do (Do nothing)
      • If (NatureRuneInteger Equal to 1) then do (Unit - Add Health Regeneration 1 to Hero) else do (Do nothing)
      • If (NatureRuneInteger Equal to 2) then do (Unit - Add Health Regeneration 2 to Hero) else do (Do nothing)
      • If (NatureRuneInteger Equal to 3) then do (Unit - Add Health Regeneration 3 to Hero) else do (Do nothing)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • WaterRuneInteger Equal to 1
        • Then - Actions
          • Unit - Set Max HP of Hero to ((Max HP of Hero) + 300)
          • Unit - Set Max Mana of Hero to ((Max Mana of Hero) + 300)
          • Unit - Set life of Hero to HeroCurrentHP
          • Unit - Set mana of Hero to HeroCurrentMana
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • WaterRuneInteger Equal to 2
        • Then - Actions
          • Unit - Set Max HP of Hero to ((Max HP of Hero) + 400)
          • Unit - Set Max Mana of Hero to ((Max Mana of Hero) + 400)
          • Unit - Set life of Hero to HeroCurrentHP
          • Unit - Set mana of Hero to HeroCurrentMana
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • WaterRuneInteger Equal to 3
        • Then - Actions
          • Unit - Set Max HP of Hero to ((Max HP of Hero) + 500)
          • Unit - Set Max Mana of Hero to ((Max Mana of Hero) + 500)
          • Unit - Set life of Hero to HeroCurrentHP
          • Unit - Set mana of Hero to HeroCurrentMana
        • Else - Actions
      • If (LightningRuneInteger Greater than or equal to 1) then do (Special Effect - Create a special effect attached to the origin of Hero using Providence Aura Teal.mdx) else do (Do nothing)
 
Status
Not open for further replies.
Top