AI Guard Unit
by Mark Holcomb · 11/27/2004 (5:18 pm) · 335 comments
Download Code File
This is my second attempt at making an AI controlled character. The first was an
AIPlayer that would follow paths. This character is a guard unit. The guard will
wait at it's post (spawn point) until it sees a target. It will then attack that
target while trying to close with it.
If the target is lost the bot will wait at the last place it saw the character and
look around for a little bit, and then it will try to return to it's post.
There is a chance the bot will get stuck trying to return, but there is a simple
routine that has the bot try to move in random directions to try and clear itself
of any obstacles between it and it's post. It's not perfect.
The thinking routine is a simple state machine - which can be expanded on to give the bot more responses and actions.
As with my first ai character, I am using a simple system that allows the designer to drop
markers in the game map that will mark where the bots will start out. When the mission is loaded, the markers are detected and bots are spawned at the marker locations. The markers are then hidden from view. (The markers can be left visible to help in map editing.)
The markers for the guards can be given a dynamic variable called respawn. (Assigned to the marker during map editing.) 'Respawn' will determine whether a bot respawns or not upon death.
The bots have an attention setting. How often they scan is determined by their attention level. The bots get more sluggish (freeing up processor time) when targets are too far away. Conversely, the bot becomes incrementally more attentive as targets come within range, and further aware as targets come into sight.
When a target is found in range and in sight the bot will shoot at the target. The firing sequence is a step of scheduled calls that call for a firing cycle, a trigger down cycle, and a firing delay to control bot rate of fire.
When a bot is attacked it will attempt to sideatep and it's field of vision is temporarily increased to a 360deg field of vision - to emulate looking around to see what happened. The bot's attention level is also set to make it think at it's fastest rate when attacked.
To use the AIGuard...the following changes need to be made.
1. Back up your original game.cs, player.cs, and your current build of Torque. To install AIGuard will require a recompile, since I have created a new class cloned by copying AIPlayer.cc and AIPlayer.h and renaming all references to AIPlayer to AIGuard.
(I did this because I wanted to be able to run both my AIPatroller and AIGuards in the same maps and did not want to have any confusion between them.)
2. Add the files AIGuard.cc and AIGuard.h to your Torque project. (In my instance I saved them to my c:\Torque\engine\game directory and then added them into my project.)
3. Recompile your project and copy your new executable to the appropriate directory for your app.
4. Copy the file AIGuard.cs into your server/scripts directory.
5. Modify game.cs to add the line
to the function onServerCreated().
6. Also in game.cs: The section for function StartGame needs to modified the following ways:
Below the lines that read:
add this:
(If you followed my previous resource you may not have any reference to AImanager. Don't fret... just look for the place in game.cs where you have
and put in
right underneath it.
7. In player.cs in the code for Armor::Damage modify the lines
to read:
*** If you followed my previous resource there should be no need to change this code.
8. Load your map - Stronghold as an example.
9. Go into the map editor. (F11) Then go into the Editor Creator (F4)
10. Under Shapes there should be a drop down called AIMarker, under that a new item called AIGuard.
11. Create a new AIGuard marker.
12. Select your marker, position it where you like and hit (F3) to modify the marker.
13. If you want to override the default respawn value - create a dynamic variable called respawn and set it's value to true or false.
14. Update your item by clicking 'APPLY'- very important and easy to miss step.
15. Save your mission and reload it.
A bot called Guard1 should appear at the spot of your marker.
If you come within range of the guard he should shoot at you and try to hunt you down.
If you get away, or when you die, he should return to his post.
I hope the resource helps other people get up and running with some AI code in their game.
And again, I'd like to thank the other members of this website whose code has been used in several places in the scripting to make this all work.
Mark H.
P.S. I've also included my AIPatrol class files with this - to install it follow the same instructions as for AIGuard, just substitute AIPatrol where AIGuard appears in the instructions. They can both be run at the same times with no problems.
P.S.S. 11/28/04 - I modified the AIPatrol.cs file to correct for a couple of typos.
P.S.S.S 12/3/04 - Added ammo and health seeking capabilities and fixed some errors. (Read posts below - or file in .zip for full details.)
This is my second attempt at making an AI controlled character. The first was an
AIPlayer that would follow paths. This character is a guard unit. The guard will
wait at it's post (spawn point) until it sees a target. It will then attack that
target while trying to close with it.
If the target is lost the bot will wait at the last place it saw the character and
look around for a little bit, and then it will try to return to it's post.
There is a chance the bot will get stuck trying to return, but there is a simple
routine that has the bot try to move in random directions to try and clear itself
of any obstacles between it and it's post. It's not perfect.
The thinking routine is a simple state machine - which can be expanded on to give the bot more responses and actions.
As with my first ai character, I am using a simple system that allows the designer to drop
markers in the game map that will mark where the bots will start out. When the mission is loaded, the markers are detected and bots are spawned at the marker locations. The markers are then hidden from view. (The markers can be left visible to help in map editing.)
The markers for the guards can be given a dynamic variable called respawn. (Assigned to the marker during map editing.) 'Respawn' will determine whether a bot respawns or not upon death.
The bots have an attention setting. How often they scan is determined by their attention level. The bots get more sluggish (freeing up processor time) when targets are too far away. Conversely, the bot becomes incrementally more attentive as targets come within range, and further aware as targets come into sight.
When a target is found in range and in sight the bot will shoot at the target. The firing sequence is a step of scheduled calls that call for a firing cycle, a trigger down cycle, and a firing delay to control bot rate of fire.
When a bot is attacked it will attempt to sideatep and it's field of vision is temporarily increased to a 360deg field of vision - to emulate looking around to see what happened. The bot's attention level is also set to make it think at it's fastest rate when attacked.
To use the AIGuard...the following changes need to be made.
1. Back up your original game.cs, player.cs, and your current build of Torque. To install AIGuard will require a recompile, since I have created a new class cloned by copying AIPlayer.cc and AIPlayer.h and renaming all references to AIPlayer to AIGuard.
(I did this because I wanted to be able to run both my AIPatroller and AIGuards in the same maps and did not want to have any confusion between them.)
2. Add the files AIGuard.cc and AIGuard.h to your Torque project. (In my instance I saved them to my c:\Torque\engine\game directory and then added them into my project.)
3. Recompile your project and copy your new executable to the appropriate directory for your app.
4. Copy the file AIGuard.cs into your server/scripts directory.
5. Modify game.cs to add the line
exec("./aiGuard.cs"); to the function onServerCreated().
6. Also in game.cs: The section for function StartGame needs to modified the following ways:
Below the lines that read:
// Start the AIManager
new ScriptObject(AIManager) {};
MissionCleanup.add(AIManager);
AIManager.think();add this:
AIGuard::LoadEntities();
(If you followed my previous resource you may not have any reference to AImanager. Don't fret... just look for the place in game.cs where you have
AIPlayer::LoadEntities
and put in
AIGuard::LoadEntities();
right underneath it.
7. In player.cs in the code for Armor::Damage modify the lines
// Deal with client callbacks here because we don't have this
// information in the onDamage or onDisable methods
%client = %obj.client;
%sourceClient = %sourceObject ? %sourceObject.client : 0;
if (%obj.getState() $= "Dead")
%client.onDeath(%sourceObject, %sourceClient, %damageType, %location);to read:
// Deal with client callbacks here because we don't have this
// information in the onDamage or onDisable methods
%client = %obj.client;
%sourceClient = %sourceObject ? %sourceObject.client : 0; if (%obj.isbot == true)
{
%obj.attentionlevel=1;
%obj.enhancefov(%obj);
}
if (%obj.getState() $= "Dead")
{
if (%obj.isbot == true)
{
if (%obj.respawn == true)
{
%obj.delaybeforerespawn(%obj.botname, %obj.markerpos, %obj.marker);
%this.player=0;
}
}
else
{
%client.onDeath(%sourceObject, %sourceClient, %damageType, %location);
}
}*** If you followed my previous resource there should be no need to change this code.
8. Load your map - Stronghold as an example.
9. Go into the map editor. (F11) Then go into the Editor Creator (F4)
10. Under Shapes there should be a drop down called AIMarker, under that a new item called AIGuard.
11. Create a new AIGuard marker.
12. Select your marker, position it where you like and hit (F3) to modify the marker.
13. If you want to override the default respawn value - create a dynamic variable called respawn and set it's value to true or false.
14. Update your item by clicking 'APPLY'- very important and easy to miss step.
15. Save your mission and reload it.
A bot called Guard1 should appear at the spot of your marker.
If you come within range of the guard he should shoot at you and try to hunt you down.
If you get away, or when you die, he should return to his post.
I hope the resource helps other people get up and running with some AI code in their game.
And again, I'd like to thank the other members of this website whose code has been used in several places in the scripting to make this all work.
Mark H.
P.S. I've also included my AIPatrol class files with this - to install it follow the same instructions as for AIGuard, just substitute AIPatrol where AIGuard appears in the instructions. They can both be run at the same times with no problems.
P.S.S. 11/28/04 - I modified the AIPatrol.cs file to correct for a couple of typos.
P.S.S.S 12/3/04 - Added ammo and health seeking capabilities and fixed some errors. (Read posts below - or file in .zip for full details.)
#202
This happens whether I compile the AiGuard cc and h files or if I just try and run AiGuard on a fresh install, without the compile, as another user above says worked for him. In both cases I followed the directions step-by-step.
Any thoughts as to what would cause the crash?
12/15/2006 (12:00 am)
I get a crash on TGE 1.5 as well - it will not load. The console log indicates that the last thing being attempted was to load up AiGuard.cs. This happens whether I compile the AiGuard cc and h files or if I just try and run AiGuard on a fresh install, without the compile, as another user above says worked for him. In both cases I followed the directions step-by-step.
Any thoughts as to what would cause the crash?
#203
12/16/2006 (2:16 pm)
The only issue I have had with this in 1.5 is that even after a relight of the mission via the misison editor and a save it seems to want to relight the whole over again. I dont think that the relight has to do with the code its just really weird.
#204
Works Great!! Just What I Was Looking For.
Thanks A Ton For This.
12/25/2006 (7:03 pm)
Added To 1.5 - Took around 10 - 20 minutes (looked through the script files)Works Great!! Just What I Was Looking For.
Thanks A Ton For This.
#205
01/01/2007 (1:07 am)
hmmm crashes on 1.5 for me as well
#206
I experienced crash too on TGE 1.5.
My problem was I have exec aiguard.cs before exec player.cs in game.cs,
putting the exec of aiguard.cs just after player.cs seems to solve the crash.
Hope this help.
01/03/2007 (7:25 am)
@Brad Strong:I experienced crash too on TGE 1.5.
My problem was I have exec aiguard.cs before exec player.cs in game.cs,
putting the exec of aiguard.cs just after player.cs seems to solve the crash.
Hope this help.
#208
Then I setup the markers and had 5 bots chasing me around in no time. Works great!
Thanks Mark, this is an excellent example to play with.
01/23/2007 (6:35 pm)
I got the scripts setup and compiled in about an hour with no issues. I'm using TGE 1.5Then I setup the markers and had 5 bots chasing me around in no time. Works great!
Thanks Mark, this is an excellent example to play with.
#210
Using Mark's code I make a friend AI unit character ( don't try to shoot player but other AI).
this was done using a simset (called EvilAIgroup).
Tinkering with AI guard scripts I just replace clientgroup with EvilAIGroup and all the variables assignemnts such as %client.player.getposition with %client.getposition (that's is ripping off the player call).
Everything runs fine, so a little doubt arise: considering %client variable is passed via a groupcount why in Mark code there is %client.player.somemethod instead just %client.somemethod ? Maybe a multiplayer issue ?
I don't have 2 pc so I can test it please someone can tell if I done it right ?
I asked this because I'm trying to develop a little AI editor called AISCE (AI simple character editor)
with an AI friend character.
The editor is free and a downloadable beta is posted here: http://www.garagegames.com/blogs/70406/12171
I will be happy to have some comments, suggestions, critics posted.
02/03/2007 (4:29 am)
Hi to all, I have a little question:Using Mark's code I make a friend AI unit character ( don't try to shoot player but other AI).
this was done using a simset (called EvilAIgroup).
Tinkering with AI guard scripts I just replace clientgroup with EvilAIGroup and all the variables assignemnts such as %client.player.getposition with %client.getposition (that's is ripping off the player call).
Everything runs fine, so a little doubt arise: considering %client variable is passed via a groupcount why in Mark code there is %client.player.somemethod instead just %client.somemethod ? Maybe a multiplayer issue ?
I don't have 2 pc so I can test it please someone can tell if I done it right ?
I asked this because I'm trying to develop a little AI editor called AISCE (AI simple character editor)
with an AI friend character.
The editor is free and a downloadable beta is posted here: http://www.garagegames.com/blogs/70406/12171
I will be happy to have some comments, suggestions, critics posted.
#211
Compiling starter.fps/server/scripts/player.cs...
Loading compiled script starter.fps/server/scripts/player.cs.
Compiling starter.fps/data/shapes/player/player.cs...
Loading compiled script starter.fps/data/shapes/player/player.cs.
Validation required for shape: starter.fps/data/shapes/player/player.dts
starter.fps/server/scripts/player.cs (831): Unable to find object: '' attempting to call function 'getState'
Compiling starter.fps/server/scripts/aiGuard.cs...
Loading compiled script starter.fps/server/scripts/aiGuard.cs.
Validation required for shape: starter.fps/data/shapes/player/player.dts
Compiling starter.fps/server/scripts/chimneyfire.cs...
Loading compiled script starter.fps/server/scripts/chimneyfire.cs.
Compiling starter.fps/server/scripts/sgExamples.cs...
Loading compiled script starter.fps/server/scripts/sgExamples.cs.
ParticleEmitterData(RealFireBigEmitter) thetaMax > 180.0
*** LOADING MISSION: starter.fps/data/missions/stronghold.mis
*** Stage 1 load
*** Stage 2 load
Executing starter.fps/data/missions/stronghold.mis.
*** Mission loaded
starter.fps/server/scripts/game.cs (122): Unknown command think.
Object AIManager(1679) AIManager -> ScriptObject -> SimObject
Loading Guard entities...
starter.fps/server/scripts/aiGuard.cs (350): Unable to instantiate non-conobject class AIGuard.
Set::add: Object "0" doesn't exist
starter.fps/server/scripts/aiGuard.cs (366): Unable to find object: '0' attempting to call function 'EquipBot'
starter.fps/server/scripts/aiGuard.cs (368): Unable to find object: '0' attempting to call function 'setShapeName'
starter.fps/server/scripts/aiGuard.cs (370): Unable to find object: '0' attempting to call function 'setTransform'
starter.fps/server/scripts/aiGuard.cs (372): Unable to find object: '0' attempting to call function 'schedule'
Hiding Guard markers...
Connect request from: IP:0.0.0.0:0
Connection established 1680
CADD: 1681 local
02/15/2007 (1:23 pm)
This is what I am seeing whne I try to use this code. I was unable to get torque to load because it would crash and then i read where you needed to have the exec aiguard after the player.cs. The it loaded fine. I was getting the error where the AIGuard enabled was set to false and I also changed the weapon to crossbow. Now I am getting this error and I'm not sure where to go from here. I am using TGE1.5 Thanks.Compiling starter.fps/server/scripts/player.cs...
Loading compiled script starter.fps/server/scripts/player.cs.
Compiling starter.fps/data/shapes/player/player.cs...
Loading compiled script starter.fps/data/shapes/player/player.cs.
Validation required for shape: starter.fps/data/shapes/player/player.dts
starter.fps/server/scripts/player.cs (831): Unable to find object: '' attempting to call function 'getState'
Compiling starter.fps/server/scripts/aiGuard.cs...
Loading compiled script starter.fps/server/scripts/aiGuard.cs.
Validation required for shape: starter.fps/data/shapes/player/player.dts
Compiling starter.fps/server/scripts/chimneyfire.cs...
Loading compiled script starter.fps/server/scripts/chimneyfire.cs.
Compiling starter.fps/server/scripts/sgExamples.cs...
Loading compiled script starter.fps/server/scripts/sgExamples.cs.
ParticleEmitterData(RealFireBigEmitter) thetaMax > 180.0
*** LOADING MISSION: starter.fps/data/missions/stronghold.mis
*** Stage 1 load
*** Stage 2 load
Executing starter.fps/data/missions/stronghold.mis.
*** Mission loaded
starter.fps/server/scripts/game.cs (122): Unknown command think.
Object AIManager(1679) AIManager -> ScriptObject -> SimObject
Loading Guard entities...
starter.fps/server/scripts/aiGuard.cs (350): Unable to instantiate non-conobject class AIGuard.
Set::add: Object "0" doesn't exist
starter.fps/server/scripts/aiGuard.cs (366): Unable to find object: '0' attempting to call function 'EquipBot'
starter.fps/server/scripts/aiGuard.cs (368): Unable to find object: '0' attempting to call function 'setShapeName'
starter.fps/server/scripts/aiGuard.cs (370): Unable to find object: '0' attempting to call function 'setTransform'
starter.fps/server/scripts/aiGuard.cs (372): Unable to find object: '0' attempting to call function 'schedule'
Hiding Guard markers...
Connect request from: IP:0.0.0.0:0
Connection established 1680
CADD: 1681 local
#212
Have you compiled AIguard in the engine ? I ask because of:
starter.fps/server/scripts/aiGuard.cs (350): Unable to instantiate non-conobject class AIGuard.
AIGuard class must conobject.
02/16/2007 (1:27 am)
@DavidHave you compiled AIguard in the engine ? I ask because of:
starter.fps/server/scripts/aiGuard.cs (350): Unable to instantiate non-conobject class AIGuard.
AIGuard class must conobject.
#213
02/16/2007 (5:51 am)
I put it in the same directory as mentioned above and then added it to the project in vs2005. I then did a clean build and then a recompile of Torque. I got zero failed. I'll try it again though.
#214
Performing Custom Build Step
Performing Custom Build Step
Performing Custom Build Step
Performing Custom Build Step
Performing Custom Build Step
Performing Custom Build Step
Compiling...
aiPatrol.cc <-----
aiGuard.cc <-----
--other stock things that compiled--
Torque Demo - 0 error(s), 0 warning(s)
So, I know it compiled correctly.
02/16/2007 (7:30 am)
Here is the build log - Performing Custom Build Step
Performing Custom Build Step
Performing Custom Build Step
Performing Custom Build Step
Performing Custom Build Step
Performing Custom Build Step
Compiling...
aiPatrol.cc <-----
aiGuard.cc <-----
--other stock things that compiled--
Torque Demo - 0 error(s), 0 warning(s)
So, I know it compiled correctly.
#215
I was able to replicate your error building torque without aiguard code, so I think the issue is in compiling aiguard.cc, but your build log seems OK so I can just give some suggestions:
1) OK probably a very stupid suggestion, so excuse if I tell you:
Perphas your torque demo build is not in example directory, so your are still using the old. Check file time creation.
2) Try to compile only AIGuard without AIpatrol for now.
3) Use a new aiguard.cs without mods
4) Is seems also there is an aiplayer.cs issue (due to the aimanger error) try to comment out aimanager calls.
02/16/2007 (8:39 am)
@David I was able to replicate your error building torque without aiguard code, so I think the issue is in compiling aiguard.cc, but your build log seems OK so I can just give some suggestions:
1) OK probably a very stupid suggestion, so excuse if I tell you:
Perphas your torque demo build is not in example directory, so your are still using the old. Check file time creation.
2) Try to compile only AIGuard without AIpatrol for now.
3) Use a new aiguard.cs without mods
4) Is seems also there is an aiplayer.cs issue (due to the aimanger error) try to comment out aimanager calls.
#216
02/16/2007 (12:54 pm)
Ok, you were right! It was the first problem I believe. I have torquedem.exe and torquedemo_DEBUG.exe. The debug.exe is the one that works but I checked the dates like you suggested and that tipped me off. Thanks.
#217
02/16/2007 (1:31 pm)
The guard is unable to cause damage and I am unable to cause damage to it. Also, the mission now lags with the ai present. I only spawned one guard so if I have more than one it will for sure crash torque. Doy ou think this is because I am running the debug.exe?
#219
Damage thing was fixed. Still not able to port with AFX.
02/19/2007 (7:03 pm)
I am going to ask this again because no one answered me before. Has anyone tried to port this with the afx combo pack? I am still unable to recieve or give damage.Damage thing was fixed. Still not able to port with AFX.
#220
Here are the code changes I made in aiguard.cs so far.
Thats all I did, so let me know if you have any problems getting these changes to work.
Remember to clean (delete) your DSO's before testing this in game!
PS: No C++ changes have been made.
02/25/2007 (10:23 am)
Well, I have been tweaking this script to make the bots more human like. I also think I resolved the premature firing issue as well. But I need to do a little more testing to confirm this.Here are the code changes I made in aiguard.cs so far.
Add code in [b]bold[/b] here. $AI_GUARD_RESPAWN_DELAY = 20000; $AI_GUARD_ENHANCEFOV_CHANCE = 5; $AI_GUARD_SEEK_HEALTH_LVL = 60; [b] // This determines how close a bot will come to a player. $AI_GUARD_MINIMUM_CLOSING_DISTANCE = 20; [/b]
I added the following blocks of code in [b]bold[/b] to the Think function.
function AIGuard::Think(%this, %obj)
{
... ...
case "Guarding":
if(%obj.gettransform() != %obj.marker.gettransform())
%obj.settransform(%obj.marker.gettransform());
//The bot will enhance it's FOV if it picks a 1 from
//a range of 1 to $AI_GUARD_ENHANCEFOV_CHANCE
%chance = getRandom(($AI_GUARD_ENHANCEFOV_CHANCE-1)) +1;
if (%chance == 1 )
%this.enhancefov(%obj);
//The bot checks for the nearest valid target if any.
%tgtid = %this.GetClosestHumanInSightandRange(%obj);
//If %tgtid >0 then a target is in sight and range.
if(%tgtid >= 0)
{
//Set the bots action to 'Attacking' and set it to attack quickly.
%obj.action = "Attacking";
[b]
//Get the current player object from the client value set in %tgtid
%tgt = ClientGroup.getobject(%tgtid);
//get the targets position and sets the bots destination
%dest = %tgt.player.getTransform();
%botpos = %obj.getTransform();
//control the distance from the bot to the targets position.
%tempdist = vectorDist(%dest, %botpos);
if(%tempdist < $AI_GUARD_MINIMUM_CLOSING_DISTANCE)
{
%obj.setmovedestination(%botpos);
}
else
{
%obj.setmovedestination(%dest);
}
//Set the bot to aim at the target.
%obj.setAimLocation(VectorAdd(%tgt.player.getTransform(),"0 0 2.0"));
[/b]
//This is one instance where the bots thinking is sped up to enable the bot
//to react more quickly.
%this.schedule(100,"Think", %obj);
}
else
... ...
case "Attacking":
//Maintain a low attention value to keep the bot thinking quickly while attacking.
%obj.attentionlevel = 1;
//Get the id of the nearest valid target
%tgtid = %this.GetClosestHumanInSightandRange(%obj);
//If %tgtid>0 then there is a valid target
if(%tgtid >= 0)
{
//Make sure that we keep ourself in attack mode since we have a target in sight.
%obj.action = "Attacking";
//Get the current player object from the client value set in %tgtid
%tgt = ClientGroup.getobject(%tgtid);
[b]
//get the targets position and sets the bots destination
%dest = %tgt.player.getTransform();
%botpos = %obj.getTransform();
//control the distance from the bot to the targets position.
%tempdist = vectorDist(%dest, %botpos);
if(%tempdist < $AI_GUARD_MINIMUM_CLOSING_DISTANCE)
{
%obj.setmovedestination(%botpos);
}
else
{
%obj.setmovedestination(%dest);
}
// Moved the setAimLocation function down too here.
//Set the bot to aim at the target.
%obj.setAimLocation(VectorAdd(%tgt.player.getTransform(),"0 0 2.0"));
[/b]
//Tells the bot to start shooting the target.
%obj.openfire(%obj, %tgt);
//Tells the scheduler to have us think again
//%this.schedule($AI_GUARD_SCANTIME * %obj.attentionlevel,"Think", %obj);
// just playing around with this atm....
%this.schedule(200 * %obj.attentionlevel,"Think", %obj);
}
else
... ...
case "Holding":
//Enhance the bot's FOV
%this.enhancefov(%obj);
//Checks for targets - (See the above code for full details of this section of code)
%tgtid = %this.GetClosestHumanInSightandRange(%obj);
if(%tgtid >= 0)
{
%obj.holdcnt=0;
%obj.action = "Attacking";
[b]
//** added this to fix premature firing bug **
//Get the current player object from the client value set in %tgtid
%tgt = ClientGroup.getobject(%tgtid);
//get the targets position and sets the bots destination
%dest = %tgt.player.getTransform();
%botpos = %obj.getTransform();
//control the distance from the bot to the targets position.
%tempdist = vectorDist(%dest, %botpos);
if(%tempdist < $AI_GUARD_MINIMUM_CLOSING_DISTANCE)
{
%obj.setmovedestination(%botpos);
}
else
{
%obj.setmovedestination(%dest);
}
//Set the bot to aim at the target.
%obj.setAimLocation(VectorAdd(%tgt.player.getTransform(),"0 0 2.0"));
[/b]
%this.schedule(100,"Think" , %obj);
}
else
... ...Thats all I did, so let me know if you have any problems getting these changes to work.
Remember to clean (delete) your DSO's before testing this in game!
PS: No C++ changes have been made.

Torque 3D Owner Graham Evans
Console or compiler error messages would be useful to see what the problem may be
Regards
Graham