• 🏆 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 Combat System 3.0

This bundle is marked as useful / simple. Simplicity is bliss, low effort and/or may contain minor bugs.

-Feel free to post suggestions in terms of features-

Introduction
I created this system since I there's only one approved combat system in the spell section and it's very bad in my opinion. I could mention the negative sides of that particular system but I don't want to insult the creator more than I have to.
Anyway, this system allows you to check if a unit is in combat, which means if a unit has taken damage or dealt damage they are in combat. Systems like this is mostly used in RPG maps, but I can imagine a few scenarios when this can be useful for almost any type of map.

A few examples you can use this system for.

  • You can only enter buildings/cities when you aren't in combat.
  • You can only use certain skills/abilities outside combat. (teleport and rest for example)
  • You cannot turn in quest or start quests while in combat.
  • You cannot finish a map in combat. (for campaigns)
  • You can only use certain battle abilities in combar. (to prevent missclicks and waste mana)


  • CS Init
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Hashtable - Create a hashtable
      • Set CS_hash = (Last created hashtable)
      • -------- Time it takes before a unit is considered 'out of combat' from the moment he deals damage. --------
      • Set CS_combat_time = 5.00
      • Set CS_friendly_fire = True
  • CS Enter Combat
    • Events
      • Game - GDD_Event becomes Equal to 0.00
    • Conditions
      • Or - Any (Conditions) are true
        • Conditions
          • CS_friendly_fire Equal to True
          • (GDD_DamagedUnit belongs to an enemy of (Owner of GDD_DamageSource)) Equal to True
    • Actions
      • Trigger - Run CS Add <gen> (checking conditions)
  • CS Add
    • Events
    • Conditions
    • Actions
      • Custom script: local integer udg_CS_handle1
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (CS_group is empty) Equal to True
        • Then - Actions
          • Trigger - Turn on CS Loop <gen>
        • Else - Actions
      • Set CS_event_unit = GDD_DamageSource
      • Custom script: set udg_CS_handle1 = GetHandleId(udg_CS_event_unit)
      • Hashtable - Save 0.00 as 1 of CS_handle1 in CS_hash
      • Set CS_combat_event = 1.00
      • Set CS_combat_event = 0.00
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (GDD_DamageSource is in CS_group) Equal to False
        • Then - Actions
          • Unit Group - Add GDD_DamageSource to CS_group
        • Else - Actions
      • Set CS_event_unit = GDD_DamagedUnit
      • Custom script: set udg_CS_handle1 = GetHandleId(udg_CS_event_unit)
      • Hashtable - Save 0.00 as 1 of CS_handle1 in CS_hash
      • Set CS_combat_event = 1.00
      • Set CS_combat_event = 0.00
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (GDD_DamagedUnit is in CS_group) Equal to False
        • Then - Actions
          • Unit Group - Add GDD_DamagedUnit to CS_group
        • Else - Actions
  • CS Loop
    • Events
      • Time - Every 0.03 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in CS_group and do (Actions)
        • Loop - Actions
          • Custom script: local integer udg_CS_handle1
          • Set CS_unit = (Picked unit)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (CS_unit is dead) Equal to True
            • Then - Actions
              • Hashtable - Clear all child hashtables of child CS_handle1 in CS_hash
              • Unit Group - Remove CS_unit from CS_group
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (CS_group is empty) Equal to True
                • Then - Actions
                  • Trigger - Turn off (This trigger)
                • Else - Actions
            • Else - Actions
              • Custom script: set udg_CS_handle1 = GetHandleId(udg_CS_unit)
              • Set CS_counter = ((Load 1 of CS_handle1 from CS_hash) + 0.03)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • CS_counter Greater than or equal to CS_combat_time
                • Then - Actions
                  • Hashtable - Clear all child hashtables of child CS_handle1 in CS_hash
                  • Set CS_event_unit = CS_unit
                  • Set CS_combat_event = 2.00
                  • Set CS_combat_event = 0.00
                  • Unit Group - Remove CS_unit from CS_group
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (CS_group is empty) Equal to True
                    • Then - Actions
                      • Trigger - Turn off (This trigger)
                    • Else - Actions
                • Else - Actions
                  • Hashtable - Save CS_counter as 1 of CS_handle1 in CS_hash
--DEMOS--

  • unit enters combat
    • Events
      • Game - CS_combat_event becomes Equal to 1.00
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (CS_entering_unit is in CS_group) Equal to False
        • Then - Actions
          • Game - Display to (All players) the text: ((Name of CS_entering_unit) + is now in combat!)
        • Else - Actions
  • unit leaves combat
    • Events
      • Game - CS_combat_event becomes Equal to 2.00
    • Conditions
    • Actions
      • Game - Display to (All players) the text: ((Name of CS_leaving_unit) + is no longer in combat!)


Q - Does this support other Damage Detection Systems? (DDS)
A - Yes, you are not forced to use the one provided in the attached map. However you need to edit a line or two in order for it to work correctly. Check the "enter combat" trigger.


Keywords:
system, GUI, combat, Chaosy, best thing ever
Contents

GUI Combat System (Map)

Reviews
19.02.2016 BPower: The in-combat event should not be 100 % equal to an on damage event. Proper trigger naming is appreciated. I summarized it here aswell. You can stay with GDD if you have to. 12th Dec 2015 IcemanBo: For long time as NeedsFix...

Moderator

M

Moderator

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
  • Hashtable - Save CS_counter as 2 of CS_handle1 in CS_hash
before the actual check for "leave combat" event? First check the condition, then save if needed.
You might consider using array instead of hashtable, whatmore switch groupenum with iteration method (through an array).

GDD_ is the weeps DDS y? If so, please add support for Bribes and looking_for_help ones. Bribes is the most popular GUI DDS system and propably the best one for them. If they want an alternative, the lfh' one should be the next choice. Weep's is getting deprecated these days.
 

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,183
Bools in hashtable are not needed, just check if unit is in group. :p
LOL! that's very true actually, I will edit within the hour.

You say you want the user to customoize abilities etc for the unit. Maybe mark it with comments where exactly the user can add remove these values.
I will put it on my. "stuff that I might to do when am bored" list :)

before the actual check for "leave combat" event? First check the condition, then save if needed.
You might consider using array instead of hashtable, whatmore switch groupenum with iteration method (through an array).
I like to work with hashtables, it's my style of doing things I suppose ^^

GDD_ is the weeps DDS y? If so, please add support for Bribes and looking_for_help ones. Bribes is the most popular GUI DDS system and propably the best one for them. If they want an alternative, the lfh' one should be the next choice. Weep's is getting deprecated these days.

I am aware of that. I pointed out where to change the unit variables.
  • -------- Change the two scripts bellow to the variables that your DDS use. "udg_unit_variable" --------
  • Custom script: local integer udg_CS_handle1 = GetHandleId(udg_GDD_DamageSource)
  • Custom script: local integer udg_CS_handle2 = GetHandleId(udg_GDD_DamagedUnit)

Thanks for the replies!
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
In regard to "check", you probably missed my point. This is some bad design:
  • Set CS_counter = (Load 2 of CS_handle1 from CS_hash)
  • Set CS_counter = (CS_counter + 0.03)
  • Hashtable - Save CS_counter as 2 of CS_handle1 in CS_hash
  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
      • CS_counter Greater than or equal to CS_combat_time
You should not call save function before the condition check. If the counter is greater than your threshold, the call of interest will be redundant.
 

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,183
  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
      • CS_counter Greater than or equal to CS_combat_time
    • Then - Actions
      • Hashtable - Clear all child hashtables of child CS_handle1 in CS_hash
      • Hashtable - Save False as 1 of CS_handle1 in CS_hash
      • Unit Group - Remove (Picked unit) from CS_group
    • Else - Actions
      • Hashtable - Save CS_counter as 1 of CS_handle1 in CS_hash
this is the correct one? right?

I hope it is because.. updated!
 
Level 14
Joined
Nov 17, 2010
Messages
1,265
Nice, I like the overall simplicity of it too. I don't know enough about coding to critique this as far as your triggers go, but it seems to work right. I'll implement it and let you know if I have any problems. Cheers
 
Level 8
Joined
Nov 9, 2011
Messages
326
I dont know if its important but ive noticed that in
  • check combat
    • Events
      • Player - Player 1 (Red) skips a cinematic sequence
    • Conditions
    • Actions
      • Unit Group - Pick every unit in (Units in (Playable map area)) and do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • ((Picked unit) is in CS_group) Equal to True
            • Then - Actions
              • Game - Display to (All players) the text: ((Name of u) + IS in combat right now!)
            • Else - Actions
              • Game - Display to (All players) the text: ((Name of u) + IS NOT in combat right now!)
u forgot to array the unit ''u'' :p
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
  • ...
    • Set CS_counter = (Load 1 of CS_handle1 from CS_hash)
    • Set CS_counter = (CS_counter + 0.03)
=>
  • Set CS_counter = ((Load 1 of CS_handle1 from CS_hash)+ 0.03)
also I recommend you to use FirstOfGroup loop enumeration since this system could affects a huge amount of units. I don't know is that required for GUI or no, but still recommended.
 
  • Set CS_combat_time = 5.00
A short definition would be useful for the user.

  • (CS_group is empty) Equal to True
^Using an integer counter and comparing it with "0" would be more efficient.

  • Custom script: local integer udg_CS_handle1 = GetHandleId(udg_GDD_DamageSource)
  • Custom script: local integer udg_CS_handle2 = GetHandleId(udg_GDD_DamagedUnit)
  • Hashtable - Save 0.00 as 1 of CS_handle1 in CS_hash
  • Hashtable - Save 0.00 as 1 of CS_handle2 in CS_hash
^You can make only 2 custom scripts out of it. No need of the real variables.

As mentioned by Dalvengyr:
  • Set CS_counter = (Load 1 of CS_handle1 from CS_hash)
  • Set CS_counter = (CS_counter + 0.03)
-->
  • Set CS_counter = (Load 1 of CS_handle1 from CS_hash) + 0.03
  • Hashtable - Save False as 1 of CS_handle1 in CS_hash
^This is not needed anymore. :p

Maybe the value "0.03" can be replaced by a config variable "ACCURACY".

Else I think this might be useful. :)
 
Level 17
Joined
Nov 13, 2006
Messages
1,814
isn't faster if u use unit indexer and array instead hashtable?
if u store unit custome value then with unit indexer u can get back easily the unit (or owner player)

don't need unit group, neither unit array, just 2 integer array, 1 integer

i did something like this:

JASS:
//in 1 sec periodic trigger ofc turn off if not used but other stuff use it too
    //I2CV -> index in combast system to custom value, like [1] = 342 (where 342 is unit custom value)
    if udg_CombatIndex > 0 then
        set i = 1
        loop
            exitwhen i > udg_CombatIndex
            set cv = udg_CombatI2CV[i]
            set udg_CombatTimer[cv] = udg_CombatTimer[cv] - 1
            if udg_CombatTimer[cv] < 1 then
                set udg_CombatTimer[cv] = 0
                if i != udg_CombatIndex then
                    set udg_CombatI2CV[i] = udg_CombatI2CV[udg_CombatIndex]
                    set udg_CombatTimer[udg_CombatI2CV[i]] = udg_CombatTimer[udg_CombatI2CV[udg_CombatIndex]]
                endif
                set udg_CombatIndex = udg_CombatIndex - 1
                set i = i - 1
            endif
            set i = i + 1
        endloop
    else
      //turn off this trigger
    endif

in dmg modifier trigger
JASS:
    //tcv = custom value of attacked unit, acv = custome value of attacking unit

    //attacked/target unit
    if udg_CombatTimer[tcv] < 1 then
        set udg_CombatTimer[tcv] = 10 
        set udg_CombatIndex = udg_CombatIndex + 1
        set udg_CombatI2CV[udg_CombatIndex] = tcv
        if udg_CombatIndex == 1 then
            //turn on periodic trigger
        endif
    else
        //here reset it the unit timer if already was in combat mode
        set udg_CombatTimer[tcv] = 10 
    endif

    //attacker unit
    if udg_CombatTimer[acv] < 1 then
        set udg_CombatTimer[acv] = 10
        set udg_CombatIndex = udg_CombatIndex + 1
        set udg_CombatI2CV[udg_CombatIndex] = acv
    else
        set udg_CombatTimer[acv] = 10
    endif
 
As mentioned before:


  • Custom script: local integer udg_CS_handle1 = GetHandleId(udg_GDD_DamageSource)
  • Custom script: local integer udg_CS_handle2 = GetHandleId(udg_GDD_DamagedUnit)
  • Hashtable - Save 0.00 as 1 of CS_handle1 in CS_hash
  • Hashtable - Save 0.00 as 1 of CS_handle2 in CS_hash
^Can be done in 2 custom script lines.

  • Hashtable - Clear all child hashtables of child CS_handle1 in CS_hash
  • Hashtable - Save False as 1 of CS_handle1 in CS_hash
^Can be removed.

  • Set CS_counter = (Load 1 of CS_handle1 from CS_hash)
  • Set CS_counter = (CS_counter + 0.03)
->
  • Set CS_counter = (Load 1 of CS_handle1 from CS_hash) + 0.03
What stays is that you add a unit to a group, and remove it after certain duration. User can use this boolean to his needs.
Seems user can easily make this on his own, if he imports any DDS. :/
 

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,183
Didn't bother to update it before since there wasn't any moderator to review it anyway. Seems like I can't run anymore though.

What stays is that you add a unit to a group, and remove it after certain duration. User can use this boolean to his needs.
Seems user can easily make this on his own, if he imports any DDS. :/

True enough. But I know that this is fairly useful for starters. Either way, not all map makers are very good with triggers. Their strengths might lie somewhere else.

edit: active moverator*
 
Last edited:
Level 37
Joined
Mar 6, 2006
Messages
9,240
Unit is in group -> hashtable value exists boolean.

  • Custom script: local integer udg_CS_handle1 = GetHandleId(udg_GDD_DamageSource)
  • Custom script: local integer udg_CS_handle2 = GetHandleId(udg_GDD_DamagedUnit)
  • Hashtable - Save 0.00 as 1 of CS_handle1 in CS_hash
  • Hashtable - Save 0.00 as 1 of CS_handle2 in CS_hash
^Can be done in 2 custom script lines.
:/

In my opinion as it is a GUI submission, those can be left as they are.
 
Nice to see you updated it. But now you don't save 0 into hashtable at damage event. At the moment you get the HandleId for nothing. :)

Now some probably final suggestions. :p

1. Add some simple Enter/Leave combat events with help of reals. Same method like used for DDSs.

2.
Unit should automatically leave combat if it's dead.

3.
Add a configuration variable that defines if source/target must be enemies.

 

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,183
-Removed the local handle ids' from the the "Enter Combat" trigger
-enter/leave events has been added
-units who're dead are automatically removed
-friendly fire is now an possible option in the init trigger

sadly I had to restructure some stuff in order to get it to work. *crosses fingers* no issues plz.

edit: anyone know what I can't change the preview image? I tried 5 times and nothing happens.
I tried using this pic:
kcbkm8.png
 
- Units combat time does not refresh on new damage. This should be automatically done in your "add to system trigger" so user does not have to bother with it.
- Extra dead trigger is not really needed. You can check for dead unit in your lopp and then just remove it.
- Your "enter combat copy" trigger could simply be structured like this:
  • enter combat Copy
    • Events
      • Game - GDD_Event becomes == 0.00
    • Conditions
      • Or - Any (Conditions) are true
        • Conditions
          • CS_friendly_fire == True
          • (GDD_DamagedUnit belongs to an enemy of (Owner of GDD_DamageSource)) == True
    • Actions
      • Trigger - Run add to system <gen> (checking conditions)
^Now you could just move the actions from the other trigger into this one. So the triggers can easily be merged now. Also rename it "enter combat Copy" is an inproper name.

It's nice to see you added the "friendly fire" feature and added the enter/leave evnts.

Ah, and btw.... why this weird picture with the soldier in spell description? It seems a bit spammy.

Needs Fix
 

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,183
That's more or less true yeah, if I think the changes the mod ask for is either too bothersome I usually just don't do it.
I can understand the perfectionist mentality and thus not approving my stuff (especially the jass ones).
But what I don't quite like that they get removed from the section completely. Everything I upload does what I intended after all.
Thing is I don't got the skills to back up my rant, otherwise I would have brought it to the staff contact long ago.

The "Who am I to.." mentality if you know what I mean.
 
Level 19
Joined
Apr 21, 2013
Messages
1,194
It is a bit harsh to remove it if you ask me too, I understand mods are working hard to keep this place working neat, but I think just a message below the topic like "This system needs fix" is enough.

I had once uploaded a spell that worked as I wanted it to, it was not a very complicating thing to some of you but I worked some good days on it. Bcz it leaked it turned to needs fix status then after some time it got removed :(
 
Not too long ago I rejected many spells.
Maybe like 700-900 submissions it was.

I did this because we had so many resources as NeedsFix that noone paid attention to them anymore for many months or even years.

I was aware that in some cases the author might come back and speak up, and this is fine.

So in case Chaosy wants this resource available again (NeedsFix), there is no problem with it.
 
  • Can't open the map, but are there two "enter combat" triggers?
    I ask because in the presentation, there are two.
  • Is there a reason for the existance of "add to system trigger"?
    It looks like it can be inlined, directly into trigger where the unit takes damage.
  • CS_entering_unit can be removed I guess. DamagedUnit and DamageSoure variables can be used.
    Same seems with "CS_leaving_unit."
  • As suggestion. The user can directly remove the unit "out of combat" if he
    removes the unit from CS_group, if it's needed in a case. It might be a useful info to know.
 

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,183
  • Removed one of them, did not exist in the map last I checked :p
  • If you want to add units to the system yourself, this could be when you enter a certain region where you want a unit to be considered to be in combat and thus disable some features. At least that's what I think, I do not remember my original intention.
  • I will look into that EDIT: It's true that it would work but it would be more illogical syntax wise if you get what I mean. Like when referring to the unit that enters combat you use a variable named GDD_damaged unit.
 
Last edited:
Level 19
Joined
Mar 18, 2012
Messages
1,716
Out of many reasons GDD is one of the less good damage detection systems there are.
The settings of a recycle rate of 0.03 is also not very recommended.

The enter combat event should check internally if the unit was already in fight state.
Your enter combat event is currently equal to a damage detection event, which makes
it useless.

Give the triggers a proper name, so they can always identified as your system.
GDD is also not named as "add to system" for a good reason.

It's a bit simple in concept. Basically can be reproduced in 3 minutes.
Maybe useful for some map makers.
 

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,183
GDD is my personal preference because it does what I expect from a damage detection system without all the additional features included.
(Not to mention it does not require other systems in turn)

Kinda like buying a toaster and getting a chair included in the package.

That's why I think Bribe names his 'DDS' to Damage Engine because it describes it more accurately.
One can easily switch DDS to another one with very slight modification anyway, four lines or so if I remember the triggers correctly.

@event
fair enough

@names
Uh, I will put CombatSystem infront of the names then. (soon tm)

@concept
Well, yes.
 
Damage & friendly fire check is fine.

But there shuld be also events for unit attacking, and casting a spell onto an enemry unit which should bring into combat state. Think of spells which make no physical damage for example.

Instead of enetering/leaving unit there could be one generic variable that is used for both events.

You should consider of using a unit indexer to get rid off of hashtable.
They are more handy to use here, hashtables are limited, and most people probably should have one implemented in their map.

There's an empty If/Then/Else statement inside "CS Add".

It's only a local, but "handle1" is a really bad name for an handleId representer/integer variable.
Something like "id" "handleId" "parentKey" would be lot better.

Only load and increment the timer when the unit is not dead.

If you want to add units to the system yourself
If you really want this, I suggest you add a "CS_Register" trigger and probably also a "CS_Unregister" trigger.
The user can set the "CS_Unit" variable and then run the respective trigger to do actions.
 

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,183
But there shuld be also events for unit attacking, and casting a spell onto an enemry unit which should bring into combat state. Think of spells which make no physical damage for example.
I use a DDS to check for taking damage from any source, I do not really see your point.

Instead of enetering/leaving unit there could be one generic variable that is used for both events.
True. Will do.


You should consider of using a unit indexer to get rid off of hashtable.
They are more handy to use here, hashtables are limited, and most people probably should have one implemented in their map.
Sorry, hashtables is my style when it comes to GUI.

There's an empty If/Then/Else statement inside "CS Add".
Mistakes were made. Gonna fix.

Only load and increment the timer when the unit is not dead.
Makes sense, gonna do that.
 
Yes, but even there is no physical damage dealt in the end, a unit can be considered involded into confrontation with the enemy.
Maybe the damage was reduced to 0. Maybe someone casted a spell towards an enemy which does not make instant damage.
It's probably what BPower meant, too, when saying:
BPower: The in-combat event should not be 100 % equal to an on damage event.
 
Top