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

GUI Friendly Shield System 1.00b

A shield system for someone with a fetish pure unadulterated love for shields.

Requirements:

Installation:
  • Install GUI Unit Indexer 1.4.0.0
  • Install Bribe's Damage Detection 5.4.2.2 or newer
  • Copy and paste the "ShieldSystem" folder in the triggers into your map

Features:
  • Easy creation of shields that can stack with each other, with one shield being evaluated before the next (rather than all of them being damaged at once).
  • Some control over which shields are damaged first.
  • Specific Shield events, set when creating a shield.
    • Expires
      • When the duration of the shield hits 0. Expiration also removes a shield.
    • Breaks
      • When a shield breaks from blocking damage. Breaking a shield usually causes it to be removed, but can be set so that the shield does not get removed upon breaking.
    • Damaged
      • When a shield is damaged (does not run if other shields block the damage)
    • UnitDamaged
      • Runs whenever the shielded unit is damaged, regardless of whether the damage was blocked or not.
    • Removed
      • Runs when the shield is removed.
    • Periodic
      • Runs 32 times a second
  • Checking if a unit has a specific type of shield (searches by shield type id value)
  • Custom block conditions, select or modify the conditions required for the shield to block damage.
  • General events
    • (v0.90)
    • Any shield added
    • Any shield removed
    • Unit with shield is done being evaluated for damage event
    • Unit with shield is done being evaluated for periodic event
    • (1.00)
    • Any shield has health/maxhealth modified (done via periodic check, not instant)
Not included:
  • Built in customizable displays for shields.
    • There's probably no universally good way to display shields, so I'll leave that to the user to implement.
    • There is however an example in the map for how one could potentially display shields of a unit, using features of the map.

Possible future additions:

  • Better documentation on how to use the system, but the examples in the map should be suffice for now.
  • All shield events
    • Things to run when any shield does something
      • could be useful for setting up your own visual displays e.g. Any Shield Damaged -> Update some special effect or texttag that displays shield health.
      • Maybe even global shield damage modifiers based on damage type.
    • Any Shield Created event, also useful for attaching UI effects to a unit, such as a health bar, etc.
  • Features that enough people request, assuming it's reasonable to include.

Somewhat Technical stuff:
  • Shield index of 0 means no shield, or a nonexistent shield.
  • Index 0 is also used to initialize shield stats, instead of having nearly a dozen extra globals to clog up the list.
  • Shields are stored as a very funky linked list of linked lists, which happens to also be sorted at the top.
    • Evaluation order: AAABBCDDEE
    • List-Or-Messed-Up-Tree.png
  • Newest shields are added to the bottom, assuming there are shields of that type-id already.
    • If not, then it creates a new entry, wherever it should go, in order to keep it sorted.

Anyhow, this is my first submission TheHiveWorkshop, and probably one of the few things I'd bother to submit, knowing the actual systems I use in my own maps tend to be less than sane and would probably not ever get approved.

As such, I also have no idea about most of the conventions for map submission, so if there's anything that needs to be changed for readability, or var name conflicts, I'll do my best to comply as it gets brought up.

Change log:
  • 0.80 First released
    • Missing some potentially useful features, but contains enough core features to warrant existing, probably.
  • 0.90 Shield visualization stuff
    • Added global/general events, and an example of potentially how to use them for displaying shield bars.
  • 0.90a Compatibility update for damage engine 5.4.2.0
    • Beware of unusual interactions with recursion (or lack of) if damage is done immediately in shield events.
    • Really, just delay damage by 0.00 seconds if you have to, or deal damage with custom projectiles.
    • Please don't use Waits, or Sleep.
  • 1.00a
    • Minor optimizations, converted some GUI triggers into JASS, but left behind a disabled GUI version in case someone cared about how it worked, but doesn't appreciate JASS.
    • Swapped ForGroup() with a BlzGroupUnitAt() loop in main periodic event, also left behind the pre 1.31+ compatible one in case someone cared about as well.
    • Changed to damage engine 5.4.2.2
  • 1.00b (basically a hotfix)
    • How did I let this happen. Everything actually broke around v0.90 and I didn't notice until now.
    • Removal queue fixed, things get removed properly now. Shields also shouldn't get put into the removal queue multiple times now.
    • Display system fixed to not break spells that might be using ForLoopIntegerA, or other variables.
Previews
Contents

GUIShieldSystem (Map)

Reviews
MyPad
A weird bug related to the Flame shield effect appears if you keep adding shields of different types, and that type to a certain unit. Otherwise, the system is functional, and works independently of these effects. Approved
Level 4
Joined
May 2, 2019
Messages
15
Updated to do more stuff, and also a basic shield display. Might look into aligning texttags and such, but I probably won't do that unless people decide to use my default shield visualization instead of making their own.
Onion.png

A very safe peasant, hiding behind 9 shields, of 5 different types.
 
Level 4
Joined
May 2, 2019
Messages
15
From what I can tell of The Witcher's system though, is that a unit only ever has one shield at a time, adding another just causes it to remove the previous one.

The difficulty is in designing something that can offer visual feedback of that shields on the unit. Since there are too many different ways one can go about designing and using shields, I've mostly left that as an exercise to the user - as one might wish to use special effects to visualize shield bars, not have a shield bar at all, or some other option that suits their map best.

The real troublesome thing is that when people can go wild with stacking shields and such, it becomes difficult to offer a good solution that would adequately cover enough unusual use cases.

For example, the shield system in the video above at 13:22 or so is only really applicable if shields always block all forms of damage, and that shields are always evaluated first applied, first damaged order. I think it looks nice though, but that could be my personal bias from having made it in the first place.

Another potential option is to select a color for each type of blocking condition, and compress the visuals into a single bar above the unit, but even then it can be difficult to read, and I'm sure someone could think of a case where it wouldn't look right. This tends to be the common approach, as seen in games like League of Legends, and Heroes of the Storm - but they also only have at most, two different types of block conditions or so, blocking all damage, or blocking magic/spell damage.

Hence, my reluctance to actually pursue a "standard" or "universal" type of shield display. If someone however has a specific display in mind for their maps and use cases, and needs help getting it implemented, I would be glad to help write something up though.

But for now, the sideways-bar-graph look easily conveys a lot of information and is probably the most useful for debugging purposes too, even if it tends to blot out everything else around it, so it'll probably remain the default unless someone argues a convincing enough case to change it.
 
Level 24
Joined
Feb 9, 2009
Messages
1,783
I said the same thing and even did some fancy pants MSPaint pictures to nail it home, however Aten has a good point is that LOL has simplified shields into three damage types, but assuming an individual wants to add all damage specific shields (chaos, piercing, siege, etc) then the UI will become useless.

Attached because I'm sure we'll spiral more into this discussion that I'm so favorable of~

Example1
Shield stack.png
is stages has two examples:
- the first four bars are stages from 1 - 4 (starting from the top), and then the final one cramming multipurpose shields in there as to maintain a universal bar size.

Shield_bar_stacking (1).png
shows an example that very much sits at the same size as the default health bar and reflects what it would be if the unit's health was at it's same value.(i.e. 110 shield on 220 hp peasant would result in 50% hp looking shield.)

Shield_bar_stacking.png
is addressing Aten's fear of shields in the previous scenario reaching above the unit's maximum hp, and echoing what Bribe has said about League's bar system, in particular lol has segments reflecting every 100 hp, meaning your bar would have 19 segments denoting 1900 hp.
Taking this in mind every separated bar could result in a unit of maximum above the unit (Think metroid games and their energy tanks)


Shield bar stacking.png
Finally using the example from fungeon, example shows "shield 2" over lapping "shield 1" but as Aten has pointed out the scenario of a unique damage type shield blocking the view of generic type shields it would fall on behind the curtain.[/spoiler]
 
Last edited:
Level 4
Joined
May 2, 2019
Messages
15
Here's another shield onion, and the map with it.

In this one, while it's less cluttered and shows distinct shields, and their types - the bar itself being fixed length doesn't easily convey how much health it has, since using additional dividers to show both health and different shields, gets messy quickly, and would also be a pain to implement mostly due to the thing being a texttag and a string. In the end though, it would basically boil down to a choice between dividers to show the distinct shields, or dividers to show health - assuming one is interested in maintaining some form of visual clarity.

Also, here's a video of how peculiar it can look when some shields don't meet their conditions to be blocked under this display style.

So, what I'm trying to say is that there are a lot of ways to display shield bars, and there may be some very unusual cases, that a typical display would not be appropriate for. So rather than thinking of the most messed up situations I can imagine under this system, and coming up a good way to reconcile all the options, I'd rather wait for someone to describe how they would like for their shields to be displayed, and I could help write that instead (assuming they don't already know how).

Though I'm not sure whether I should add it to the main demo map, or add a separate map for a different style of shielding.
 

Attachments

  • ShieldOnion.png
    ShieldOnion.png
    91.7 KB · Views: 253
  • 2019-06-17 01-15-31.avi
    3.3 MB · Views: 236
  • GUIShieldSystem.w3x
    94.5 KB · Views: 138

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
  • Beware of unusual interactions with recursion (or lack of) if damage is done immediately in shield events.
  • Really, just delay damage by 0.00 seconds if you have to, or deal damage with custom projectiles.
Not necessary at all. Instead of:

  • Shield Handling
    • Events
      • DamageModifierEvent becomes Equal to 4.00
    • Conditions
    • Actions
      • -------- Process shields --------
      • If (Conditions)
        • Then
          • Unit - Cause Target to damage Source
        • Else
Do the following 3 triggers:
  • Shield Handling
    • Events
      • DamageModifierEvent becomes Equal to 4.00
    • Conditions
    • Actions
      • -------- Process shields --------
      • If (Conditions)
        • Then
          • Trigger - Turn on Shield damage <gen>
        • Else
  • Shield damage <initially off>
    • Events
      • DamageEvent becomes Equal to 1.00
    • Conditions
    • Actions
      • Unit - Cause Target to damage Source
      • Trigger - Turn off (this trigger)
In case you want to make sure the DamageEvent trig is turned off in all scenarios, you can move the turn-off trigs to the AfterDamageEvent:

Do the following two triggers:
  • Shield Handling
    • Events
      • DamageModifierEvent becomes Equal to 4.00
    • Conditions
    • Actions
      • -------- Process shields --------
      • If (Conditions)
        • Then
          • Trigger - Turn on Shield damage <gen>
          • Trigger - Turn on Shield after damage <gen>
        • Else
  • Shield damage <initially off>
    • Events
      • DamageEvent becomes Equal to 1.00
    • Conditions
    • Actions
      • Unit - Cause Target to damage Source
  • Shield after damage <initially off>
    • Events
      • AfterDamageEvent becomes Equal to 1.00
    • Conditions
    • Actions
      • Trigger - Turn off Shield damage <gen>
      • Trigger - Turn off Shield after damage <gen>
The reason why this works is that the trigger whose event is detected to be problematic is the one that's frozen - all other events always run (unless otherwise turned off). In this example, trig 1 is never frozen, while trig2 will get ignored in the system once it hits recursion. The backup "AfterDamageEvent" trigger will also never be frozen.
 
Last edited:
Quite a powerhouse of a Shield System (It even comes with its' own Shield Display).
There are some lines which would need optimizing:

JASS:
exitwhen udg_ShieldIndex == 0  or udg_SystemShieldIterationStop == true

There are instances where the Boolean variable SystemShieldIterationStop is being compared to the value true. The comparison can be removed, leaving only SystemShieldIterationStop

The following triggers contain instances of these boolean assertions (usually within loops):
  • (Some Functions Disabled) ForAllShieldsOfUnit
  • (Some Functions Disabled) ForAllShieldsOfUnitDisplayOrder
  • (Some Functions Disabled) ForAllShieldsOfUnitBackward
The trigger RemoveShield can benefit from being written in pure JASS instead, given the amount of conditions that would be generated.

If the map is using a game version of 1.31 or higher, you can easily substitute
  • Unit Group - Pick every unit in SystemShieldedUnits and do (Actions)
with a loop iteration based on BlzGroupUnitAt(group, index) and BlzGroupGetSize(group).

(The break condition is when the iterator index reaches the BlzGroupGetSize()'s value.)

Since that trigger is expected to be executed 32 times every second, optimizing the iteration process may be necessary.
 
Level 4
Joined
May 2, 2019
Messages
15
Added those optimizations, but also included the older disabled GUI versions of the triggers in case someone unfamiliar with JASS wanted to look through it. Unlikely, but possible. Might rewrite more parts in JASS, but will probably also keep GUI variants around somewhere.

There are probably more optimizations that could be possible, but would otherwise sacrifice some friendliness to more basic users snooping around trying to understand it.

Also did some testing with the shield display. It was unbearably laggy with only 100 shields updating 32 times a second. Reduced bars from 66 characters to 50 characters (132 characters to 100 since '|' requires "||" to display), increased font size slightly to compensate. Changed around part of the shield system, added the "shield health modified" generic event, and updated the current default display system.

You can see how laggy it is by typing "-shieldall" in chat. It's still very bad, but it stops lagging once the shield bars stop updating, due to now only updating the string/texttag when necessary, rather than all the time.

Short of redoing everything in Lua, for faster string manipulation, and better data manipulation (no need for linked lists, dynamic arrays + cache benefits, etc), I can't think of other ways to get meaningful speed increases out of it.

One such non Lua possibility was to do everything in trigger conditions, or rather, all the TriggerExecute() calls could be swapped for TriggerEvaluate() (which for whatever reason is faster), but GUI users can't actually do things in the condition part of a trigger, unfortunately.
 
Last edited:
Level 4
Joined
May 2, 2019
Messages
15
@MyPad Thanks for the report, and the approval
Found the source of the bug, apparently the removal queue wasn't always working.

Sometimes when multiple shields were broken, say because rifleman did 20 damage and broke two weak 10 hp flame shields shields in one attack, when the shields were queued to be removed, it'd remove the first, and the act of removing the shield caused it to iterate through shields again - but ended up breaking the recursion tracking so that it wasn't considered recursive iteration. This ended up resetting the queued shields count, and breaking out of the loop before all shields could be removed properly.

With the subsequent shields not actually being removed , it wouldn't run the event for destroying the special effect as it should have (among other cleanup details). It was however still flagged as "should be removed" and thus ignored in the actual damage evaluation part the next time around, even without being actually removed.

Will probably upload a fix soon, hopefully without breaking things.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Added those optimizations, but also included the older disabled GUI versions of the triggers in case someone unfamiliar with JASS wanted to look through it. Unlikely, but possible. Might rewrite more parts in JASS, but will probably also keep GUI variants around somewhere.

There are probably more optimizations that could be possible, but would otherwise sacrifice some friendliness to more basic users snooping around trying to understand it.

Also did some testing with the shield display. It was unbearably laggy with only 100 shields updating 32 times a second. Reduced bars from 66 characters to 50 characters (132 characters to 100 since '|' requires "||" to display), increased font size slightly to compensate. Changed around part of the shield system, added the "shield health modified" generic event, and updated the current default display system.

You can see how laggy it is by typing "-shieldall" in chat. It's still very bad, but it stops lagging once the shield bars stop updating, due to now only updating the string/texttag when necessary, rather than all the time.

Short of redoing everything in Lua, for faster string manipulation, and better data manipulation (no need for linked lists, dynamic arrays + cache benefits, etc), I can't think of other ways to get meaningful speed increases out of it.

One such possibility was to do everything in trigger conditions, or rather, all the TriggerExecute() calls could be swapped for TriggerEvaluate() (which for whatever reason is faster), but GUI users can't actually do things in the condition part of a trigger, unfortunately.
If you use Lua Damage Engine with Lua Fast Triggers, nothing will be evaluated or executed - only called.
 
Level 4
Joined
May 2, 2019
Messages
15
Made many minor but significant changes to the system. Removal queue should be working properly now.

Found out the display system broke some of the spells, because it was using the same temp values as the abilities in some points, such as ForLoopIntegerA, and some TempReal values. Changed some of the events to not update immediately, but instead to update on the next update loop when drawing the shield bar, this should make sure the display doesn't override any of the values, at least until after they're done being used.

This should make certain shields spells functional again, and ensure users do not need to worry about tracking what variables are used where, and how they might get accidentally overridden, at least until someone uses the "any shield" events without creating their own variables specifically for it.

Will probably look into Lua at some point, but I'm curious as to whether GUI users will find it more convenient to swap to Lua mode, considering most resources out there are already in JASS, especially things that are unlikely to get updated. Perhaps at some point people will rewrite everything for those sweet performance boosts, and I'll have no excuse.
 

deepstrasz

Map Reviewer
Level 68
Joined
Jun 4, 2009
Messages
18,706
So while this is nifty and all, it lags like snails, tortoises and even absolute zero if there are too many units (tried with the peasants+12x12 footmen) on the map with shields on at the same time.
Not only that but floating text has a limit of appearance. Only about a certain number of them can be seen/created at the same time.

It's good for about 10 heroes/units or so at a time but can't be used for full scale battles like in StarCraft.
 
Last edited:

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
So while this is nifty and all, it lags like snails, tortoises and even absolute zero if there are too many units (tried with the peasants+12x12 footmen) on the map with shields on at the same time.
Not only that but floating text has a limit of appearance. Only about a certain number of them can be seen/created at the same time.

It's good for about 10 heroes/units or so at a time but can't be used for full scale battles like in StarCraft.

Too many events. Lua allows function calling to replace the trigger evaluations, so that's not a blanket solution.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
I 99% use GUI.

Can Lua bypass the floating text appearance/creation limitation or the staggering of units due to multiple commands when they are 100+ under one player?

Lua Damage Engine speeds up GUI triggers. It simply calls the conditions and actions functions when using my Lua Fast Triggers resource.

For the other two, no.

(Edited this post so as to not confuse future readers)
 
Last edited:

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
I don't know the system but I believe there exist more critical performance issues in GUI, other than calling function vs trigger evaluations.
Well that's your opinion, but since WC3 is far more sluggish since the introduction of the latest patch, people are noticing performance issues where there previously were none. With Damage Engine the performance of the event execution sequence is very critical. The minor performance delta in coding with GUI or script is nothing compared to being able to prevent trigger execution spam many times per second in battle.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
You're evidently stating something as you know for sure that the Lua way of calling functions is the fix for having lags. And I'm saying there may be other potentials risks. Unit group operations by its nature for example have and had always perfomance issues, when done too often. Especially in GUI.


That's true, and it reminds me - the ForGroupBJ mechanic can also be overwritten in Lua to experience the same performance improvement. I actually forgot to write that script but I'll get on it.
 

deepstrasz

Map Reviewer
Level 68
Joined
Jun 4, 2009
Messages
18,706
For the other two, no, but Ubersplats can work as a text tag alternative.
Eh? How? You can't attach them to units. They're basically some default dead things effect. You can't scale them, you can't move them only destroy and recreate them, I don't know... Do they always stay on top like health/mana bars and floating text? They're basically images. You can't manipulate them as in change them according to integer/string variables.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Eh? How? You can't attach them to units. They're basically some default dead things effect. You can't scale them, you can't move them only destroy and recreate them, I don't know... Do they always stay on top like health/mana bars and floating text? They're basically images. You can't manipulate them as in change them according to integer/string variables.
I have no idea what my memory just conjured up then - I tried Googling what I understood was the source of that info but definitely nothing.

Sorry!
 
Pretty sure Bribe meant textsplats or also known as images which would be way better then floating text and doesn't have a limit of 100 per player which critical strike and evasion as well terrain level evasion uses up of the limit for floating texts too. In 1.28.5 I managed 3,000 images with 3,000 units all moving at the same time while being above 25 fps. Images would also allow for much better control over display instead of just text, also they can be given height as well and display over terrain and units/heroes.
 
Top