• 🏆 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] Wander v0.4

This bundle is marked as useful / simple. Simplicity is bliss, low effort and/or may contain minor bugs.
This system is not fully GUI (I think) because almost half of the code is custom script.

I been searching a system that will make units wandering around with
simple implementation and I can't find any. Most of it is JASS and takes lot of work.
Since I can't find it, I made this system and I made the implementation simple as I could.

This system will make registered unit move around certain area or everywhere
based on user configuration.
The system will stop forcing unit from wandering when the unit is unit combat
until the unit is out of combat.

For me, this kind of system would be useful for RPG mapping.
Making the forest and village looks lively.

This is just the base of the system, I'll update it with various kind of feature
if I see any support. Maybe I'll make the registered unit emotional likes
angry, panic, etc.

If you have any idea for the update, please tell me. TQ

How to import:
1. Copy all trigger in System and Requirements category. Don't the system inside
Requirement if you already have it.
2. For Damage Engine system, copy Cheat Death Ability in Object Editor > Ability
3. Paste the trigger and the custom ability into your map.
4. Check and enable disabled actions in systems trigger.

The triggers:

  • Wander
    • Events
    • Conditions
    • Actions
      • -------- -------------------------------- --------
      • -------- Any no unit registeration will be ignored. --------
      • -------- -------------------------------- --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • And - All (Conditions) are true
            • Conditions
              • WanderRegUnit Equal to No unit
              • WanderRemoveUnit Equal to No unit
        • Then - Actions
          • Custom script: debug call BJDebugMsg("Wander : No unit to be registered or removed.")
        • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • WanderRegUnit Not equal to No unit
            • Then - Actions
              • Custom script: call ExecuteFunc("WanderRegister")
            • Else - Actions
              • Custom script: call ExecuteFunc("WanderRemove")
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • WanderCoUnit Not equal to No unit
        • Then - Actions
          • Custom script: call ExecuteFunc("WanderCombatDetect")
        • Else - Actions
      • Custom script: endfunction
      • -------- -------------------------------- --------
      • -------- -------------------------------- --------
      • -------- -------------------------------- --------
      • -------- -------------------------------- --------
      • Custom script: function WanderCombatDelay takes nothing returns nothing
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (WanderCombatGroup is empty) Equal to True
        • Then - Actions
          • Countdown Timer - Pause WanderCoTimer
          • Set WanderTimerCheck[3] = False
        • Else - Actions
      • Unit Group - Pick every unit in WanderCombatGroup and do (Actions)
        • Loop - Actions
          • Set WanderUnit = (Picked unit)
          • Set WanderIndex = (Custom value of WanderUnit)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • WanderDelayCount[WanderIndex] Greater than 0.00
            • Then - Actions
              • Set WanderDelayCount[WanderIndex] = (WanderDelayCount[WanderIndex] - 0.50)
            • Else - Actions
              • Unit Group - Remove WanderUnit from WanderCombatGroup
      • Custom script: endfunction
      • -------- -------------------------------- --------
      • -------- -------------------------------- --------
      • -------- -------------------------------- --------
      • -------- -------------------------------- --------
      • Custom script: function WanderCombatDetect takes nothing returns nothing
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • WanderTimerCheck[3] Equal to False
        • Then - Actions
          • Custom script: call TimerStart(udg_WanderCoTimer, 0.50, true, function WanderCombatDelay)
          • Set WanderTimerCheck[3] = True
        • Else - Actions
      • Set WanderIndex = (Custom value of WanderCoUnit)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (WanderCoUnit is in WanderCombatGroup) Equal to False
        • Then - Actions
          • Unit Group - Add WanderCoUnit to WanderCombatGroup
        • Else - Actions
      • Set WanderDelayCount[WanderIndex] = WanderCoDelay[WanderIndex]
      • Set WanderCoUnit = No unit
      • Custom script: endfunction
      • -------- -------------------------------- --------
      • -------- -------------------------------- --------
      • -------- -------------------------------- --------
      • -------- -------------------------------- --------
      • -------- This function will remove any registered unit who in combat and add who out of combat. --------
      • -------- -------------------------------- --------
      • Custom script: function WanderAddRemove takes nothing returns nothing
      • -------- If there's no unit in this group, --------
      • -------- this one will pause the timer. --------
      • -------- By doing this, this system won't cause lag. --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (WanderRegisteredGroup is empty) Equal to True
        • Then - Actions
          • Countdown Timer - Pause WanderARTimer
          • Set WanderTimerCheck[1] = False
        • Else - Actions
      • -------- Check if the registered unit is in combat or not. --------
      • Unit Group - Pick every unit in WanderRegisteredGroup and do (Actions)
        • Loop - Actions
          • Set WanderUnit = (Picked unit)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (WanderUnit is in WanderCombatGroup) Equal to True
            • Then - Actions
              • Unit Group - Remove WanderUnit from WanderActiveGroup
            • Else - Actions
              • Unit Group - Add WanderUnit to WanderActiveGroup
              • -------- Resume the timer when there's a unit in group --------
              • Countdown Timer - Resume WanderWPTimer
              • Set WanderTimerCheck[2] = True
      • Custom script: endfunction
      • -------- -------------------------------- --------
      • -------- -------------------------------- --------
      • -------- -------------------------------- --------
      • -------- -------------------------------- --------
      • -------- This is the periodic function. --------
      • -------- and this function is the one that will make registered unit walk around. --------
      • -------- -------------------------------- --------
      • Custom script: function WanderPeriodic takes nothing returns nothing
      • -------- Checking unit group --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (WanderActiveGroup is empty) Equal to True
        • Then - Actions
          • Countdown Timer - Pause WanderWPTimer
          • Set WanderTimerCheck[2] = False
        • Else - Actions
      • -------- Pick all registered unit --------
      • Unit Group - Pick every unit in WanderActiveGroup and do (Actions)
        • Loop - Actions
          • Custom script: local real array x
          • Custom script: local real array y
          • Set WanderUnit = (Picked unit)
          • Set WanderIndex = (Custom value of WanderUnit)
          • -------- -------------------------------- --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • WanderDelayCount[WanderIndex] Greater than or equal to WanderDelay[WanderIndex]
            • Then - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • WanderIsAroundLoc[WanderIndex] Equal to True
                • Then - Actions
                  • Custom script: set udg_WanderPoint[1] = Location(udg_WanderLocX[udg_WanderIndex], udg_WanderLocY[udg_WanderIndex])
                • Else - Actions
                  • Set WanderPoint[1] = (Position of WanderUnit)
              • Custom script: loop
              • Set WanderPoint[2] = (WanderPoint[1] offset by (Random real number between WanderMinDist[WanderIndex] and WanderMaxDist[WanderIndex]) towards (Random angle) degrees)
              • Custom script: set x[1] = GetLocationX(udg_WanderPoint[2])
              • Custom script: set y[1] = GetLocationY(udg_WanderPoint[2])
              • Custom script: call MoveRectTo(udg_WanderPathRect, x[1], y[1])
              • Custom script: call SetItemPosition(udg_WanderPathChecker, x[1], y[1])
              • Custom script: set x[2] = GetItemX(udg_WanderPathChecker)
              • Custom script: set y[2] = GetItemY(udg_WanderPathChecker)
              • Item - Hide WanderPathChecker
              • Custom script: set udg_WanderPathCheck = ((x[2]-x[1])*(x[2]-x[1]) + (y[2]-y[1])*(y[2]-y[1]) <= 100) and (not IsTerrainPathable(x[1], y[1], PATHING_TYPE_WALKABILITY))
              • Custom script: exitwhen udg_WanderPathCheck == true
              • Custom script: endloop
              • Custom script: call IssuePointOrderLoc(udg_WanderUnit, udg_WanderOrder[udg_WanderIndex], udg_WanderPoint[2])
              • Custom script: call RemoveLocation(udg_WanderPoint[1])
              • Custom script: call RemoveLocation(udg_WanderPoint[2])
              • Set WanderDelayCount[WanderIndex] = 0.00
            • Else - Actions
              • Set WanderDelayCount[WanderIndex] = (WanderDelayCount[WanderIndex] + 0.50)
      • Custom script: endfunction
      • -------- -------------------------------- --------
      • -------- -------------------------------- --------
      • -------- -------------------------------- --------
      • -------- -------------------------------- --------
      • -------- This function will remove unit from this system. --------
      • Custom script: function WanderRemove takes nothing returns nothing
      • -------- Remove unit from system --------
      • Unit Group - Remove WanderRemoveUnit from WanderActiveGroup
      • Unit Group - Remove WanderRemoveUnit from WanderRegisteredGroup
      • -------- nulling variable --------
      • Set WanderRemoveUnit = No unit
      • Custom script: endfunction
      • -------- -------------------------------- --------
      • -------- -------------------------------- --------
      • -------- -------------------------------- --------
      • -------- -------------------------------- --------
      • -------- When registering units, all of the information will be --------
      • -------- send into this function and this function will store them into hashtable. --------
      • -------- -------------------------------- --------
      • Custom script: function WanderRegister takes nothing returns nothing
      • -------- Starting timer for functions. --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • WanderTimerCheck[1] Equal to False
        • Then - Actions
          • Custom script: call TimerStart(udg_WanderARTimer, 0.50, true, function WanderAddRemove)
          • Set WanderTimerCheck[1] = True
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • WanderTimerCheck[2] Equal to False
        • Then - Actions
          • Custom script: call TimerStart(udg_WanderWPTimer, 0.50, true, function WanderPeriodic)
          • Set WanderTimerCheck[2] = True
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • WanderIsAroundLoc[WanderIndex] Equal to True
        • Then - Actions
          • Custom script: set udg_WanderLocX[udg_WanderIndex] = GetLocationX(udg_WanderWPoint)
          • Custom script: set udg_WanderLocY[udg_WanderIndex] = GetLocationY(udg_WanderWPoint)
        • Else - Actions
      • -------- Registering unit into the system. --------
      • Unit Group - Add WanderRegUnit to WanderActiveGroup
      • Unit Group - Add WanderRegUnit to WanderRegisteredGroup
      • -------- nulling variable --------
      • Set WanderRegUnit = No unit
      • Custom script: call RemoveLocation(udg_WanderWPoint)
  • Wander CoDetect
    • Events
      • Unit - A unit Is issued an order targeting an object
      • Unit - A unit Is attacked
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ((Attacked unit) is in WanderRegisteredGroup) Equal to True
        • Then - Actions
          • Set WanderCoUnit = (Attacked unit)
          • Trigger - Run Wander <gen> (ignoring conditions)
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ((Attacking unit) is in WanderRegisteredGroup) Equal to True
        • Then - Actions
          • Set WanderCoUnit = (Attacking unit)
          • Trigger - Run Wander <gen> (ignoring conditions)
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ((Ordered unit) is in WanderRegisteredGroup) Equal to True
        • Then - Actions
          • Set WanderCoUnit = (Ordered unit)
          • Trigger - Run Wander <gen> (ignoring conditions)
        • Else - Actions
  • Demo
    • Events
      • Player - Player 1 (Red) types a chat message containing <Empty String> as An exact match
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Entered chat string) Equal to -add
        • Then - Actions
          • -------- I'm registering unit in playable map area. --------
          • Set TmpGroup[2] = (Units in (Playable map area))
          • Unit Group - Pick every unit in TmpGroup[2] and do (Actions)
            • Loop - Actions
              • -------- Set this to the unit you want to register --------
              • Set WanderRegUnit = (Picked unit)
              • Set WanderIndex = (Custom value of WanderRegUnit)
              • -------- You want the unit move around point (true) or anywhere (false) --------
              • Set WanderIsAroundLoc[WanderIndex] = True
              • -------- If the answer is true, then set the point. --------
              • Set WanderWPoint = (Position of WanderRegUnit)
              • -------- Order id --------
              • Set WanderOrder[WanderIndex] = attack
              • -------- How long the combat last --------
              • Set WanderCoDelay[WanderIndex] = 4.00
              • -------- How often the unit wander around. --------
              • Set WanderDelay[WanderIndex] = (Random real number between 4.00 and 8.00)
              • -------- Maximum wander distance. --------
              • Set WanderMaxDist[WanderIndex] = (Random real number between 400.00 and 500.00)
              • -------- Minimum wander distance. --------
              • Set WanderMinDist[WanderIndex] = (Random real number between 100.00 and 200.00)
              • -------- Now, run the system. --------
              • Trigger - Run Wander <gen> (ignoring conditions)
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Entered chat string) Equal to -remove
        • Then - Actions
          • -------- I'm removing unit in playable map area. --------
          • Set TmpGroup[2] = (Units in (Playable map area))
          • Unit Group - Pick every unit in TmpGroup[2] and do (Actions)
            • Loop - Actions
              • -------- Set this to the unit you want to remove --------
              • Set WanderRemoveUnit = (Picked unit)
              • -------- Now, run the system. --------
              • Trigger - Run Wander <gen> (ignoring conditions)
        • Else - Actions
      • Custom script: call DestroyGroup(udg_TmpGroup[2])
Updated!
--added feature to detect un-pathable location

v0.01
--first release
v0.2
--added feature to remove unit from the system
--removed periodic configuration
v0.3
--removed hashtable, used UnitIndexer
--changed variables name
--added feature to modify unit order id
--added feature to modify the combat delay
v0.4
--registered unit will only move to pathable location


Credit:
Unit Indexer by Bribe

Keywords:
wandering, moving around, live creep, live villager, GUI wander, rpg, rpg system, unit brain, patrol, village scene
Contents

Just another Warcraft III map (Map)

Reviews
23:53, 14th Nov 2015 BPower: Just a small review. Check my last post in the thread. Remove the debug keyword. 16:09, 6th Oct 2015 Bribe: Review

Moderator

M

Moderator

23:53, 14th Nov 2015
BPower: Just a small review. Check my last post in the thread.
Remove the debug keyword.

16:09, 6th Oct 2015
Bribe: Review
 
Level 5
Joined
May 2, 2015
Messages
109
For me its kinda great to have two version of a system.
Both version has its own features. :D

EDIT : Can someone tell me how to make the countdown work precisely. I mean, if the Wander_Delay is 0.50 scale and i set Wander_Periodic to any number that not 0.50 scale, how to calculate the countdown to make Wander_DelayCount == Wander_Delay and not Wander_DelayCount >= Wander_Delay
or should i make the timer periodic unconfigurable.
 
Last edited:

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
Improvements:
- Only start the timers if they weren't already started
- Instead of a hashtable, use arrays and the custom value of the unit as the array index.
Arrays names:

WanderLocX/Y
WanderMin/MaxDist
WanderDelay
WanderDelayCount
etc.

Maybe an option to make the NPCs attack-move instead of just move.

Instead of doing a perfect "Equal to" when you check if the wander duration has expired, do an equal to or greater than. This way you also don't have to do weird stuff like converting real to integer.

Move this out of the if-block to shorten the code: Unit - Order Wander_Unit to Move To Wander_Point[2]

This looks conceptually good. The other systems seem to want to add 6,000 features in addition to wandering. I like just strictly wandering as a standalone system.
 

Wrda

Spell Reviewer
Level 25
Joined
Nov 18, 2012
Messages
1,870
Anyway, why create a point and then get the coordinates of that point? Use either lol
Agreed. this is pointless:
  • Custom script: set udg_WanderPoint[1] = Location(udg_WanderLocX[udg_WanderIndex], udg_WanderLocY[udg_WanderIndex])
Just use locations.

  • Custom script: call MoveRectTo(udg_WanderPathRect, x[1], y[1])
What is this? I never see you using it anywhere else on the triggers, only once...


Correct me If I'm wrong, but you will leak if the udg_WanderPathCheck is false
  • Custom script: loop
  • Set WanderPoint[2] = (WanderPoint[1] offset by (Random real number between WanderMinDist[WanderIndex] and WanderMaxDist[WanderIndex]) towards (Random angle) degrees)
  • Custom script: set x[1] = GetLocationX(udg_WanderPoint[2])
  • Custom script: set y[1] = GetLocationY(udg_WanderPoint[2])
  • Custom script: call MoveRectTo(udg_WanderPathRect, x[1], y[1])
  • Custom script: call SetItemPosition(udg_WanderPathChecker, x[1], y[1])
  • Custom script: set x[2] = GetItemX(udg_WanderPathChecker)
  • Custom script: set y[2] = GetItemY(udg_WanderPathChecker)
  • Item - Hide WanderPathChecker
  • Custom script: set udg_WanderPathCheck = ((x[2]-x[1])*(x[2]-x[1]) + (y[2]-y[1])*(y[2]-y[1]) <= 100) and (not IsTerrainPathable(x[1], y[1], PATHING_TYPE_WALKABILITY))
  • Custom script: exitwhen udg_WanderPathCheck == true
  • Custom script: endloop
 
Level 5
Joined
May 2, 2015
Messages
109
For some reason the code feels super long..

Anyway, why create a point and then get the coordinates of that point? Use either lol

yes it is long because of its features. if you can see in the description, this system will make unit wander if the unit is out of combat and if the terrain is pathable. btw i will try to make it short later and thanks for telling, i forgot to change that :p

Agreed. this is pointless:
  • Custom script: set udg_WanderPoint[1] = Location(udg_WanderLocX[udg_WanderIndex], udg_WanderLocY[udg_WanderIndex])
Just use locations.

  • Custom script: call MoveRectTo(udg_WanderPathRect, x[1], y[1])
What is this? I never see you using it anywhere else on the triggers, only once...


Correct me If I'm wrong, but you will leak if the udg_WanderPathCheck is false
  • Custom script: loop
  • Set WanderPoint[2] = (WanderPoint[1] offset by (Random real number between WanderMinDist[WanderIndex] and WanderMaxDist[WanderIndex]) towards (Random angle) degrees)
  • Custom script: set x[1] = GetLocationX(udg_WanderPoint[2])
  • Custom script: set y[1] = GetLocationY(udg_WanderPoint[2])
  • Custom script: call MoveRectTo(udg_WanderPathRect, x[1], y[1])
  • Custom script: call SetItemPosition(udg_WanderPathChecker, x[1], y[1])
  • Custom script: set x[2] = GetItemX(udg_WanderPathChecker)
  • Custom script: set y[2] = GetItemY(udg_WanderPathChecker)
  • Item - Hide WanderPathChecker
  • Custom script: set udg_WanderPathCheck = ((x[2]-x[1])*(x[2]-x[1]) + (y[2]-y[1])*(y[2]-y[1]) <= 100) and (not IsTerrainPathable(x[1], y[1], PATHING_TYPE_WALKABILITY))
  • Custom script: exitwhen udg_WanderPathCheck == true
  • Custom script: endloop


Oh, my mistake. i just copy the copy from my rpg map, i'll remove that and thanks again, thats leak. i'll try to remake some of the code.
 
Top