I have been pondering how I am going to create a good threat system; and the best notion that comes to mind is:
-When a unit takes damage, save that damage to a custom value for the unit; equal to the player number of the player dealing the damage.
-Damage can be muliplied by a units "threat increase" to alter threat output, by setting a custom value to the attacking unit.
This is pretty cut and paste. The questions come in with:
What would be the best way to set the highest threat player as the target? periodic, every second do a check? What if said player is fleeing? couldnt 2 long ranged units "threat kite" a boss? Or, if they are hiding behind a wall of other players units, ranged attacking a melee; ect. What about the monsters abilities? will they still target the attack target? What conditions could be set/actions taken to avoid these problems?
Most impprtantly: would the lag from this cause a game to be unplayable on lower end PC's? taking into account that a "unit takes damage" trigger may be called 400 times in a second; in the most extreme situations of abuse and comedy.
I don't really want to weight atm but just for some out of the box thinking you could use a data damage response buff to keep track of number of hits and then have a slower .1 sec trigger loop to check them through the units.
I will most likely make it so only high tier units are taken into account with the threat system; this should make it so no more than a dozen or so units will ever be gathering aggro at a given time. I was hoping there would be a much cleaner way to do it though; I dislike periodics.
I'm using thread with 16-members array which updates every 0.0625 secs and stores damage taken during last second in AI-controled unit's custom value. By evaluating that amount i'm ordering unit to respond appropriately (heal, regroup, chase, use abils). But i rly don't know how it affect performance in multiplayer cuz i'm working on single player rpg and have triggered health bars with opacity disappearing and all the crazy stuff with no lag issues.
I'm also turning thread off after this value drops to 0. And launching again when unit takes damage.
Edit: For multiplayer i'd use this system but also add second unit custom value that will store number of player/id of a unit which was last attacker. This is most precise stuff i could think of.
Data solution would be set of damage response effects (issue order) which using different current health validators. But it will be primitive crap.
Data/trigger solution could use same data setup, but using apply behaviour effect instead of direct issue order and then running apropriate trigger on "Behaviour state changes" event.
If your game has only one unit per player (hero), then your custom value approach will work and is very clever. Custom values are very fast (faster than buffs) and you should not get any lag problems.
As for finding the attack target:
Most of your questions really cant be answered, since those are design decisions that YOU have to make. You could add things like a line of sight check, a max distance and so on. I think in general the periodic check is the way to go. In fact, periodic triggers are not necessarily bad (especially because they cant stack up, such as events) and pretty much have a constant, low overhead.
You should try to find optimizations for your periodic check though. For example: Does it really need to pick ALL units, or can you maybe exclude certain units from the calculation (Distance from players, owner, ...)?
In general you should not worry about lag too much. As long as you dont notice any problems, there is no need to go crazy with optimization. Its wise to keep performance in mind when designing systems like this though.
I am always worried about lag. The reason I worry about this, is because I would be adding it into my current dialog hero UI; which I feel is already putting more strain on the system than I would like.
Roughly, the trigger:
-Every .33 seconds
-Pick all players in (Custom Player Group (active+has selected their hero))
-set string variable = current health / max halth
-Dialog - Set label = string variable (to display the units life)
-set real variable = (original width of dialog item below / 100) *% of life)) (This gives the width the bar will need to be to represent life remaining)
-Dialog = Set image size = smaller width based on % of current life (scales the size of the life bar, shield bar, and energy bar)
-Does the same thing for whatever target the player has selected; there is another similar setup for enemy life bars ect.
-Every 5 cycles of this (set via increasing integers)
Set the tooltip for the hero (when you hover over the icon in the UI) to show his more important stats (damage, range, spell damage, speed, and attack speed) This used to show 14 stats, but I lowered it to the most important ones, to reduce variable settings.
This is 5 variable sets to get the values*
- loop 1-5 set text= combine all of the above
- Set dialog tooptip to whatever
- Does the same thing for whatever target the player has selected
I assume that is easier than trying to decode a trigger copy/paste. Playing solo with the debugger window open, that has a .2ms run time. I run it through a loop of 8 as a stress test (max players is 6) and it has a run time of 1.9ms. nearly 2ms on a .33 loop seems pretty high to me; for a single function.
With that in mind, I can assume that adding a threat system (Which would only need to go off every 5 cycles as well) would have a max potential to double that time.
@ abvdzh: I think something that runs so frequently would cause insane lag in a multiplayer game. To test it, I set my above trigger to run every .05 and it bogged my computer right down; and there isnt much sc2 can do to bog me down. (I have a nerd computer). It is insanely difficult to try to do tests for potential lag in a 6 player game.
With the "unit takes damage" if I am just setting a custom values, you dont think it will lag then? That is my biggest concern; a trigger which may fire 500 times per second; even if it has a tiny run time. I think with the way my game is setup; I can easily get it so no more than a dozen units will be "in the system" at once.
Arghhhhh; guess I will trial and error this thing! I will post the performance results, in case any lurkers are interested. Wish me luck!
To be honest, setting variables that often will not lag the game. That's such a trivial operation in the scheme of things. I made a nice Threat System back in WC3. You can checkout the code and see how i put that together here -> http://peeeq.de/code.php?id=7067 And some Examples of it's use here -> http://peeeq.de/code.php?id=7069
There is also a new function in the editor called Unit Tag, which returns a unique integer for each unit. So you could set it up to use an array and store more information per unit. For example...
yea i don't know what is slowing down your computer but it's definitely not this periodic trigger. You did online testing while get slowdowns or testlaunch from the editor? I have shitton of periodic threads and 0 difference in performance between 1 and 0.0625 period. Basicaly map doodads lagging more than calculations within the trigger
I have a damage based threat system rigged up; seems to be working well enough; though it has nearly doubled the run time of my periodic (to update dialogs, maintain itself, and issue attack orders) Units outside of X range lose 10% of their generated threat per cycle, units which can have threat will also have push priority; to prevent walling melee units, ect. Only units matching specific conditions are "picked" during the loop; rather specific conditions.
as it is; latency isnt an issue... yet. looping it at 8; my hypothetical max time, with all conditions passing and functions firing; we are looking at 2.5ms-4,0ms of run time, every .33 seconds. I am a little upset about this, a 1% latency issue for a single map feature; on a good computer. A low quality computer might feel it with a full house and a lot of instances running. Playing solo, it is only about a .35 ms run time; not bad. You guys were right about the "takes damage" trigger as well. the average fail time is .2 and run time .02. not sure why the fail time is so long; checking an or condition.
Now I am struck with yet another major problem. ... Does anyone know how to incorporate healing into this custom value system? Really; to get the healing value from one unit to another. I refuse to use a "vitals change" event. Tried it once; it runs about 25 times per second; due to life/shield/energy regeneration. I would really prefer not to have to manually set values for each spell cast either. Healing will be done with healers; with negative attack damage, negative spell damage; and can be amplified through behaviors ect. A simple catalog field get wouldn't work, and equating it all out would be a painnnn.
Instead of "vital changes" you can use same periodic thread for vitals comparsion, but i tried it and this doesnt work properly. For example there are many occasional situations when in the same game period (1/16) unit get for example, heal 40 and damage 35 in this case you will get heal amount of 5, using method which monitoring unit's health every 0.0625 sec. On the other hand, using vital change never fails is precise and basicaly, what you need. I don't see any point in doing wrong math for performance win, it's pointless. In that case you will need some alternative approach.
What i think can be done instead:
Use custom value on a caster that will define current strength of healing spell (with dummy "set" effect), and then use "Unit using ability" event for healing done detection.
I'm personaly using custom values almost for everything i even changed default unit's attack and now i'm setting everything with a string from data tables like
(Damage Min) (Damage Max) ("Weapon Effect String") (Attack Speed) (Crit Chance) (Crit Multiplier) ("Attack Anim Name"), etc.
and then just using WordFromString for setting unit's custom values. (For string values some other method)
I like your word from string setup. I use it to set the values for all of my randomly generated item, potions, and the such. I also use it to keep track of spent attribute points, skills, skill points and all of that (for compressed banking purposes mostly). Property change couldn't work if I wanted it to; because I want to increase threat for the player casting the heal; and dont want threat to build for someone regenerating. Granted; I could trigger that; but having more than 1-2 variable sets running that frequently would be an end of days.
I have thought of a very... "cheap" work around; I am gonna give a shot. I have a custom value on units set for their threat multiplier. I could create a buff to apply to the caster for .1 seconds or something of that nature; which increases that multiplier by a massive %, relative to the strength of the heal; then with every heal cast; deal 1 damage to all units in the threat search area (12) around the target healed. The damage would more-or-less be ignored; but it would build threat through the existing threat system; and I could use my existing upgrade system for abilities to increase the threat along with healing done.
I plan to have all positive buffs increase threat on the caster for X seconds anyway; so this shouldn't be too hard to implement in a similar fashion!
@Mille, you must have some super secret awesome way of doing this -Behind that iron curtain there!