• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Pet/Companion system 1.4

Intro

features

triggers

Demo triggers

huge demo example


I got a request from aeroblyctos, when I finished it he suggested that I could upload it here and now that's done :p.
The system is MUI and could be very useful in maps with many units. This way allows you to make it easier to controll all those units.

The system allows you to:
* set AI units that will follow and protect any unit

* each AI can have their own master
* each master can have a unlimited ammout of pets (if you would use too many they could not move anyway :p)
* modes for the pets, passive mode, normal mode and aggresive mode
* unit 1 can have passive mode on while unit 2 can have normal mode

  • Init
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Hashtable - Create a hashtable
      • Set AI_hash = (Last created hashtable)
      • -------- SETUP --------
      • Set AI_move[1] = 500.00
      • Set AI_move[2] = 300.00
      • Set AI_move[3] = 500.00
      • Set AI_order_return[1] = 1000.00
      • Set AI_order_return[2] = 1000.00
      • Set AI_order_return[3] = 1500.00
      • Set AI_order_return_instant[1] = 1200.00
      • Set AI_order_return_instant[2] = 1200.00
      • Set AI_order_return_instant[3] = 2000.00
      • Set AI_order_attack[1] = 800.00
      • Set AI_order_attack[2] = 500.00
      • Set AI_order_attack[3] = 1200.00
  • AI loop
    • Events
      • Time - Every 2.00 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in AI_group and do (Actions)
        • Loop - Actions
          • Custom script: local integer h
          • Set t_unit = (Picked unit)
          • Custom script: set h = GetHandleId(udg_t_unit)
          • Custom script: set udg_Not_AI = LoadUnitHandle(udg_AI_hash, h, 4)
          • Custom script: set udg_AI_mode = LoadInteger(udg_AI_hash, h, 5)
          • Set t_loc_3 = (Position of Not_AI)
          • Set t_loc = (Position of t_unit)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Distance between t_loc and t_loc_3) Greater than or equal to AI_order_return_instant[AI_mode]
            • Then - Actions
              • Unit - Move t_unit instantly to t_loc_3
            • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Distance between t_loc and t_loc_3) Greater than or equal to AI_order_return[AI_mode]
                • Then - Actions
                  • Unit - Order t_unit to Move To t_loc_3
                • Else - Actions
          • Custom script: set bj_wantDestroyGroup = true
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Issued order) Not equal to (Order(attack))
            • Then - Actions
              • Unit - Order t_unit to Attack (Random unit from (Units within AI_order_attack[AI_mode] of t_loc_3 matching ((((Matching unit) belongs to an enemy of (Owner of t_unit)) Equal to True) and ((((Matching unit) is alive) Equal to True) and ((Matching unit) Not equal to No unit)))))
            • Else - Actions
          • Custom script: set udg_t_loc_2 = LoadLocationHandle(udg_AI_hash, h, 1)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Or - Any (Conditions) are true
                • Conditions
                  • (Current order of t_unit) Equal to (Order(<Empty String>))
                  • (Distance between t_loc and t_loc_2) Less than or equal to 50.00
            • Then - Actions
              • Set t_loc_2 = (t_loc_3 offset by (Random real number between 1.00 and AI_move[AI_mode]) towards (Random real number between 1.00 and 360.00) degrees)
              • Custom script: call RemoveLocation(LoadLocationHandle(udg_AI_hash, h, 1))
              • Custom script: call SaveLocationHandle(udg_AI_hash, h, 1, udg_t_loc_2)
              • Unit - Order t_unit to Move To t_loc_2
            • Else - Actions
          • Custom script: call RemoveLocation(udg_t_loc)
          • Custom script: call RemoveLocation(udg_t_loc_3)
  • AI Attack back
    • Events
      • Game - damageEventTrigger becomes Equal to 1.00
    • Conditions
      • (source belongs to an enemy of (Owner of target)) Equal to True
      • target Equal to Not_AI
      • (target is in AI_group) Equal to True
    • Actions
      • Set AI_p[2] = (Position of target)
      • Unit Group - Pick every unit in AI_group and do (Actions)
        • Loop - Actions
          • Custom script: local integer h = GetHandleId(GetEnumUnit())
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Issued order) Not equal to (Order(attack))
            • Then - Actions
              • Set AI_p[1] = (Position of (Picked unit))
              • Custom script: set udg_AI_mode = LoadInteger(udg_AI_hash, h, 5)
              • Custom script: if DistanceBetweenPoints(udg_AI_p [1], udg_AI_p [2]) <= udg_AI_order_return [udg_AI_mode] then
              • Unit - Order (Picked unit) to Attack source
              • Custom script: endif
              • Custom script: call RemoveLocation(udg_AI_p[1])
            • Else - Actions
      • Custom script: call RemoveLocation(udg_AI_p[2])
  • AI Functions
    • Events
    • Conditions
    • Actions
      • Custom script: endfunction
      • -------- ----------- --------
      • -------- ----------- --------
      • -------- ----------- --------
      • Custom script: function AiPrepare takes unit u, unit master, location p returns nothing
      • Custom script: local integer h = GetHandleId(u)
      • Custom script: set udg_t_loc_2 = PolarProjectionBJ(p, GetRandomReal(1.00, 500.00), GetRandomReal(1.00, 360.00))
      • Custom script: call IssuePointOrderLoc(u, "move", udg_t_loc_2 )
      • Custom script: call SaveLocationHandle(udg_AI_hash, h, 1, udg_t_loc_2)
      • Custom script: call SaveUnitHandle(udg_AI_hash, h, 4, master)
      • Custom script: call SaveInteger(udg_AI_hash, h, 5, 1)
      • Custom script: call SaveBoolean(udg_AI_hash, h, 6, true)
      • Custom script: call GroupAddUnit(udg_AI_group, u)
      • Custom script: call SaveLocationHandle(udg_AI_hash, h, 1, udg_t_loc_2)
      • Custom script: endfunction
      • -------- ----------- --------
      • -------- ----------- --------
      • -------- ----------- --------
      • Custom script: function AiRemove takes unit u returns nothing
      • Custom script: local integer h = GetHandleId(u)
      • Custom script: call GroupRemoveUnit(udg_AI_group, u)
      • Custom script: call RemoveLocation(LoadLocationHandle(udg_AI_hash, h, 1))
      • Custom script: call FlushChildHashtable(udg_AI_hash, h)
  • AI Remove
    • Events
      • Unit - A unit Dies
    • Conditions
      • ((Triggering unit) is in AI_group) Equal to True
    • Actions
      • Custom script: call AiRemove(GetTriggerUnit())

  • Demo init AI
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Set Not_AI = Paladin 0000 <gen>
      • Set AI_units[1] = Footman 0001 <gen>
      • Set AI_units[2] = Footman 0002 <gen>
      • Set AI_units[3] = Footman 0003 <gen>
      • Set t_loc = (Position of Not_AI)
      • Set AI_max = 3
      • For each (Integer A) from 1 to AI_max, do (Actions)
        • Loop - Actions
          • Custom script: call AiPrepare(udg_AI_units [bj_forLoopAIndex], udg_Not_AI, udg_t_loc)
      • Custom script: call RemoveLocation(udg_t_loc)
  • Item summon AI demo
    • Events
      • Unit - A unit Uses an item
    • Conditions
      • (Item-type of (Item being manipulated)) Equal to Baba
    • Actions
      • Custom script: local integer h
      • Set TempLoc = (Position of (Hero manipulating item))
      • Unit - Create 1 Peasant for Player 1 (Red) at TempLoc facing Default building facing degrees
      • Unit - Add a 60.00 second Generic expiration timer to (Last created unit)
      • Special Effect - Create a special effect attached to the origin of (Last created unit) using Abilities\Spells\Orc\HealingWave\HealingWaveTarget.mdl
      • Special Effect - Destroy (Last created special effect)
      • Custom script: call AiPrepare(bj_lastCreatedUnit, GetManipulatingUnit(), udg_TempLoc)
      • Custom script: call RemoveLocation(udg_TempLoc)

  • Companion Passive Mode
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Passive Mode
    • Actions
      • Unit Group - Pick every unit in AI_group and do (Actions)
        • Loop - Actions
          • Custom script: local integer h = GetHandleId(GetEnumUnit())
          • Set AI_mode = 2
          • Custom script: call SaveInteger(udg_AI_hash, h, 5, udg_AI_mode)
  • Companion Passive Mode Target
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Passive Mode Target
    • Actions
      • Custom script: local integer h = GetHandleId(GetTriggerUnit())
      • Set AI_mode = 2
      • Custom script: call SaveInteger(udg_AI_hash, h, 5, udg_AI_mode)
  • Normal Mode
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Normal Mode
    • Actions
      • Unit Group - Pick every unit in AI_group and do (Actions)
        • Loop - Actions
          • Custom script: local integer h = GetHandleId(GetEnumUnit())
          • Set AI_mode = 1
          • Custom script: call SaveInteger(udg_AI_hash, h, 5, udg_AI_mode)
  • Normal Mode Target
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Normal Mode Target
    • Actions
      • Custom script: local integer h = GetHandleId(GetTriggerUnit())
      • Set AI_mode = 1
      • Custom script: call SaveInteger(udg_AI_hash, h, 5, udg_AI_mode)
  • Agressive Mode
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Agressive Mode
    • Actions
      • Unit Group - Pick every unit in AI_group and do (Actions)
        • Loop - Actions
          • Custom script: local integer h = GetHandleId(GetEnumUnit())
          • Set AI_mode = 3
          • Custom script: call SaveInteger(udg_AI_hash, h, 5, udg_AI_mode)
  • Agressive Mode Target
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Agressive Mode Target
    • Actions
      • Custom script: local integer h = GetHandleId(GetTriggerUnit())
      • Set AI_mode = 3
      • Custom script: call SaveInteger(udg_AI_hash, h, 5, udg_AI_mode)
  • Companion Enable AI Target
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Enable/Disable AI Target
    • Actions
      • Custom script: local integer h
      • Set AI_temp_unit = (Target unit of ability being cast)
      • Custom script: set h = GetHandleId(udg_AI_temp_unit)
      • Custom script: set udg_AI_check_target = LoadBoolean(udg_AI_hash, h, 6)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • AI_check_target Equal to True
        • Then - Actions
          • Unit Group - Remove AI_temp_unit from AI_group
          • Set AI_check_target = False
        • Else - Actions
          • Unit Group - Add AI_temp_unit to AI_group
          • Set AI_check_target = True
      • Custom script: call SaveBoolean(udg_AI_hash, h, 6, udg_AI_check_target)
  • Command
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Command
    • Actions
      • Custom script: local integer h = GetHandleId(GetSpellTargetUnit())
      • Set Not_AI = (Triggering unit)
      • Custom script: call SaveUnitHandle(udg_AI_hash, h, 4, GetTriggerUnit())
  • Untitled Trigger 001
    • Events
      • Player - Player 1 (Red) Selects a unit
    • Conditions
      • (Unit-type of (Triggering unit)) Equal to (Restore Panel)
    • Actions
      • Selection - Select Game Panel 0018 <gen> for Player 1 (Red)


Keywords:
pet, companion, help, AI, ai, system, Chaosy
Contents

bwrwrbwb (Map)

Reviews
Pet/Companion system 1.4 | Reviewed by Maker | 01.01.14 Concept[/COLOR]] Pets are a cool addition and are fittinng in a lot of maps Triggers[/COLOR]] The system has required options like insta teleport. It is also MUI There is a...

Moderator

M

Moderator


Pet/Companion system 1.4 | Reviewed by Maker | 01.01.14

[COLOR="gray"

[COLOR="gray"

[COLOR="gray"

Concept[/COLOR]]
126248-albums6177-picture66521.png
  • Pets are a cool addition and are fittinng in a lot of maps
Triggers[/COLOR]]
126248-albums6177-picture66521.png
  • The system has required options like insta teleport. It is also MUI
126248-albums6177-picture66523.png
  • There is a Issued order if/then/else in the AI loop. There is no Issued order
    Same thing in AI Attack back
  • The looping trigger could be initially off and turned off
    when the group is empty
  • You could load pets for each master in the looping trigger.
    Not master for each pet
Rating[/COLOR]]
CONCEPTTRIGGERSRATINGSTATUS
126248-albums6177-picture75359.jpg
126248-albums6177-picture75358.jpg
126248-albums6177-picture75358.jpg
APPROVED



Pet/Companion system 1.4 | Reviewed by Maker | 15th Feb 2013
NEEDS FIX


126248-albums6177-picture66522.png


  • You leak in AI loop, if the order is null. Don't overwrite hashtable data
  • If taking friendly fire, the pets are ordered to attack the source

    I think you should only order the pets of the damaged unit to attack,
    and not attack friendlies
126248-albums6177-picture66523.png


  • The pets move around too much
  • It would be nice to be able to order the pets to hold position
[tr]

Pet/Companion system 1.3 | Reviewed by Maker | 1st Jun 2013
NEEDS FIX


126248-albums6177-picture66522.png


  • You leak a unit group when you order a unit to attack random unit
    The random unit can be null and the attack order still given
    from group
  • You overwrite locations in the hashtable and thus leak in AI loop
  • In Functions you store a loc into the hashtable but remove it right away
126248-albums6177-picture66523.png


  • Take actions that you are going to do anyway out of if/then/else
  • AI Attack back doesn't need to use an array for the locations
[tr]


Pet/Companion system 1.2 | Reviewed by Maker | 28th May 2013
NEEDS FIX

126248-albums6177-picture66522.png


  • In Functions, remove locations if they are stored in the hashtable
    before flushing the table
  • In Functions you store a loc into the hashtable but remove it right away
  • If the pet dies, data related to it stays in the hashtable -> leaks
  • You are overwriting locations in the hashtable in the looping trigger
126248-albums6177-picture66523.png


  • Your trigger names are too generic
  • You order the pet to attack targets it might not be able to attack
  • Take actions that you are going to do anyway out of if/then/else
[tr]
 
Non-constant global variables shouldn't be lower-cased,ItShouldBeLikeThis.
Group filters shall be done inside the group enumeration,for readabilty increase.
The "Functions" Trigger should be written in the map header. Not in GUI,it doesn't look good.
Use a Unit Indexer to get rid of hashtable limits.
GetEnumUnit() > cache this.
in the AI group, integer h should be done after setting the PickedUnit var.
 

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,219
"
-You leak a unit group when you order a unit to attack random unit
The random unit can be null and the attack order still given
from group
-You overwrite locations in the hashtable and thus leak in AI loop
-In Functions you store a loc into the hashtable but remove it right away"

1. fixed
2. I think I fixed it
3. fixed

will try to fix the footman issue before updating tho

EDIT: I found nothing wrong with the movement of the footmans
 
Last edited:
Level 37
Joined
Mar 6, 2006
Messages
9,243
You still have the unit group leak when ordering to attack random unit.

Don't do this
  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
    • Then - Actions
      • Custom script: call RemoveLocation(udg_t_loc)
      • Custom script: call RemoveLocation(udg_t_loc_3)
    • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
        • Then - Actions
          • Custom script: call RemoveLocation(udg_t_loc)
          • Custom script: call RemoveLocation(udg_t_loc_3)
        • Else - Actions
          • Custom script: call RemoveLocation(udg_t_loc)
          • Custom script: call RemoveLocation(udg_t_loc_3)
Do this
  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
    • Then - Actions
    • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
        • Then - Actions
        • Else - Actions
  • Custom script: call RemoveLocation(udg_t_loc)
  • Custom script: call RemoveLocation(udg_t_loc_3)

In my opinion the footmen don't have to move around that often, they block my way all the time.
 
Hello I really think this is a cool idea for a system. Havent seen it before... but now, so I ve tested it.
________________

When my soldier attacked my hero(on purpose), it ended in chaos and all tryed to kill each other :D
Same if one of them attacks another one.. maybe you could do they all only attack the attacking unit, but that they all kill each other is strange.

Then I attacked an enemy.. I aimed the closest enemy there was, my soliders were following me.
Then they recognized a new enemy and so they all decided to leave my hero alone and attacked the new enemy (which was a bit far away :s)

This one ...
  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
      • (Distance between t_loc and t_loc_2) <= 50.00
    • Then - Actions
      • Set t_loc_2 = (t_loc_3 offset by (Random real number between 1.00 and AI_move[AI_mode]) towards (Random real number between 1.00 and 360.00) degrees)
      • Custom script: call RemoveLocation(LoadLocationHandle(udg_AI_hash, h, 1))
      • Custom script: call SaveLocationHandle(udg_AI_hash, h, 1, udg_t_loc_2)
      • Unit - Order t_unit to Bewegen nach t_loc_2
      • Else - Actions
        • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • (Current order of t_unit) == (Order(<Empty String>))
          • Then - Actions
            • Set t_loc_2 = (t_loc_3 offset by (Random real number between 1.00 and AI_move[AI_mode]) towards (Random real number between 1.00 and 360.00) degrees)
            • Custom script: call RemoveLocation(LoadLocationHandle(udg_AI_hash, h, 1))
            • Custom script: call SaveLocationHandle(udg_AI_hash, h, 1, udg_t_loc_2)
            • Unit - Order t_unit to Bewegen nach t_loc_2
          • Else - Actions
Could be shorted to this, or I'm wrong?
  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
      • Or - Conditions
        • (Distance between t_loc and t_loc_2) <= 50.00
        • (Current order of t_unit) == (Order(<Empty String>))
    • Then - Actions
      • Set t_loc_2 = (t_loc_3 offset by (Random real number between 1.00 and AI_move[AI_mode]) towards (Random real number between 1.00 and 360.00) degrees)
      • Custom script: call RemoveLocation(LoadLocationHandle(udg_AI_hash, h, 1))
      • Custom script: call SaveLocationHandle(udg_AI_hash, h, 1, udg_t_loc_2)
      • Unit - Order t_unit to Bewegen nach t_loc_2
      • Else - Actions
Also in your "Companion Enable AI Target" trigger you make a same line in Then and in Else actions, you can set the...
  • Custom script: call SaveBoolean(udg_AI_hash, h, 6, udg_AI_check_target)
behind the ITE block.
________________

Greetings... I defintly think this can be very useful.
 

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,219
You revived To The Bitter End thread.
Srsly why bump?

because I updated it. :p

@ice
I will look into this in a second

and I think youre right. I will do that.

edit:
I thought I had fixed that issue before but now it's fixed. I actually made a pretty big mistake in the attack back trigger.
 
Top