Game Development Community

dev|Pro Game Development Curriculum

Turret & AITurret classes, Version 1.20

by Brian Howard · 03/14/2004 (9:33 am) · 131 comments

Download Code File

Included in this archive are the original files and the files modified to work with 1.20 version. Most files did not have to be modified. Files that were modified were saved as a new file in an originalname_1_20.ext format. For example, trigger.cc had to be modified and the 1.20 code was saved as trigger_1_20.cc

I've maintained the same commenting format Paul used.

I've included the original turret_readme.txt file and an updated turret_readme_1_20.txt in the archive. The new readme file contains references for other fixes I found along the way. Please let me know if I missed a reference.

***I have not tested this on moving vehicles!

Hope the changes are helpful. I'll check back in, and do what I can to help out. This is my first posting, so let me know if there is a better way to communicate code updates.

About the author

Recent Blogs

#101
11/08/2008 (8:42 am)
I am trying to get the AITurrets to shoot at a new class of vehicle I made, but it doesnt for some reason. Where are the set ObjectTypes for the turrets to shoot at? My vehicle class is using the PlayerObjectType, so does anyone have any idea why its not working?
#102
03/02/2009 (12:50 am)
Tracking changes I made to port to TGEA 1.8.1

1. Any .cc file was changed to .cpp

2. Any console call removed number as second parameter...

void AITurret::throwCallback( const char *name )
{
   Con::executef(getDataBlock(), 2, name, scriptThis());
}
for example now becomes...
void AITurret::throwCallback( const char *name )
{
   Con::executef(getDataBlock(),name, scriptThis()); /// <--- no 2
}

in missionAreaEditor.cpp (just phdana code)
// draw all the objects
   Vector<SceneObject*> objects;
   // phdana turrets ->
   U32 mask = InteriorObjectType | PlayerObjectType | VehicleObjectType | StaticShapeObjectType | WaterObjectType | TriggerObjectType | TurretObjectType;
   // <- phdana turrets
   gServerContainer.findObjects(mask, findObjectsCallback, &objects);

3.In aiturret.h change writepacketstream to void rather than bool...
void	writePacketData(GameConnection *, BitStream *stream);

and in aiturret.cpp...

void AITurret::writePacketData(GameConnection *con, BitStream *stream)
{
  Parent::writePacketData(con, stream);

  return;
}

4. Added TurretObjectType as BIT(27) since BIT(21) (as in earlier code) was taken... in T3D/objectTypes.h

enum SimObjectTypes
{
....
   StaticRenderedObjectType =    BIT(26),
   // phdana turrets ->
   TurretObjectType =            BIT(27),
   // <- phdana turrets

5. In aiTurret.cpp change include as I put my turret files under T3D/turrets...

#include "../trigger.h"

#103
03/02/2009 (12:56 am)
TGEA 1.8.1 changes continue....

6. In aiTurret.cpp changed includes to suit current location "T3D/turrets...

#include "aiTurret.h"                          // <---- here
#include "console/consoleInternal.h"
#include "math/mMatrix.h"
#include "math/mathUtils.h"
#include "console/console.h"
#include "console/consoleTypes.h"
#include "console/consoleInternal.h"
#include "../gameConnection.h"                 // <-----here  
#include "../../core/stream/bitStream.h"       // <-----here
#include "math/mMathFn.h" 
#include "../moveManager.h"                    // <-----here
#104
03/02/2009 (1:03 am)
7. in turret.cpp changed includes...

#include "Turret.h"                             //<-- here
#include "console/console.h"
#include "console/consoleTypes.h"
#include "console/consoleInternal.h"
#include "../gameConnection.h"                  //<-- here
#include "../../core/stream/bitStream.h"        //<-- here
#include "ts/tsShapeInstance.h"
#include "../moveManager.h"                     //<-- here
#include "../../core/resourceManager.h"         //<-- here

...and change the forward declaration of ::preload (changed StringHandle to NetStringHandle)
bool mountImage(ShapeBaseImageData* imageData,U32 imageSlot,bool loaded,NetStringHandle &skinNameHandle);
8. Change writePacketData to match override of parent class (bool to void)...
void	writePacketData(GameConnection *, BitStream *stream);

9. In turret.cpp changed code to match forward declaration...
void Turret::writePacketData(GameConnection *con, BitStream *stream)
{
  Parent::writePacketData(con, stream);

  stream->write(mRot.x); 
  stream->write(mRot.z);
  stream->writeFlag(isActive);
    
  return;
}

10. Changes the interface for the mountImage method... (StringHandle to NetStringHandle)
bool Turret::mountImage(ShapeBaseImageData* imageData,U32 imageSlot,bool loaded,NetStringHandle &skinNameHandle)
{
...

12. Change the ::preload overriden method, to handle the new way of using the ResourceManager
bool TurretData::preload(bool server, String &errorBuffer)
{
   if (!Parent::preload(server, errorBuffer))
      return false;
   if (shapeName && shapeName[0])
   {
      // Resolve shapename
      shapeResource = ResourceManager::get().load(shapeName);
      if (!bool(shapeResource))
      {
		 //dSprintf(buffer, sizeOf(buffer), "TankData: Couldn't load shape "%s"",shapeName);
		 errorBuffer = String::ToString("TankData: Couldn't load shape "%s"",shapeName);
         return false;
      }
      if(!server && !shapeResource->preloadMaterialList(shapeResource.getPath()) && NetConnection::filesWereDownloaded())
         return false;
   }
...

***MORE TO COME
#105
03/05/2009 (4:31 am)
As far as I can tell this doesn't go in vehicle.cpp

static U32 sDirtySetMask = PlayerObjectType     |
                           // phdana turrets ->
                           TurretObjectType |
                           // <- phdana turrets
                           VehicleObjectType;

Added mask to flyingVehicle.cpp

const static U32 sCollisionMoveMask = (TerrainObjectType        | InteriorObjectType   |
                                       WaterObjectType          | PlayerObjectType     |
									   // phdana turrets ->
										TurretObjectType         |
										// <- phdana turrets
                                       StaticShapeObjectType    | VehicleObjectType    |
                                       VehicleBlockerObjectType | StaticTSObjectType   |
                                       AtlasObjectType);

Added mask to hoverVehicle.cpp

const U32 sCollisionMoveMask = (TerrainObjectType        | InteriorObjectType   |
                                PlayerObjectType         | StaticTSObjectType   |
								// phdana turrets ->
                                TurretObjectType         |
                                // <- phdana turrets
                                StaticShapeObjectType    | VehicleObjectType    |
                                VehicleBlockerObjectType | AtlasObjectType);

Added mask to wheeledVehicle.cpp

static U32 sClientCollisionMask =
      TerrainObjectType    | InteriorObjectType       |
      PlayerObjectType     | StaticShapeObjectType    |
	  // phdana turrets
      TurretObjectType     |
      // <- phdana turrets
      VehicleObjectType    | VehicleBlockerObjectType |
      StaticTSObjectType   | AtlasObjectType;
#106
03/05/2009 (4:35 am)
Added this to GameBase.cpp

// phdana turrets ->
void GameBase::potentialEnterObject(GameBase*)
{
   // do nothing...derived classes do something with this
}
// <- phdana turrets

Added this to GameBase.h (in public:)

// phdana turrets ->
   virtual void potentialEnterObject(GameBase*);
   // <- phdana turrets

#107
03/05/2009 (4:40 am)
Added mask to item.cpp

const U32 sClientCollisionMask = (AtlasObjectType       |  TerrainObjectType     |
                                  InteriorObjectType    |  StaticShapeObjectType |
								  // phdana turrets ->
                                  TurretObjectType      |
                                  // <- phdana turrets
                                  VehicleObjectType     |  PlayerObjectType      | 
                                  StaticTSObjectType);

Added to gameFunctions.cpp (instead of Main.cc)

// phdana turrets ->
   Con::setIntVariable("$TypeMasks::TurretObjectType",         TurretObjectType);
// <- phdana turrets
#108
03/05/2009 (4:42 am)
Added to player.cpp (just do the phdana commented changes)

In class...
// Air control
   airControl = 0.0f;

   jumpTowardsNormal = true;

   // phdana aiobject ->
   activatesTriggers = true;
   // <- phdana aiobject

   dMemset( actionList, 0, sizeof(actionList) );
}

at top...
//
static U32 sCollisionMoveMask = (AtlasObjectType        | TerrainObjectType    |
                                 InteriorObjectType     |
                                 WaterObjectType        | PlayerObjectType     |
								 // phdana turrets ->
                                 TurretObjectType       | 
                                 // <- phdana turrets
                                 StaticShapeObjectType  | VehicleObjectType    |
                                 PhysicalZoneObjectType | StaticTSObjectType);

static U32 sServerCollisionContactMask = (sCollisionMoveMask |
                                          (ItemObjectType    |
                                           TriggerObjectType |
                                           CorpseObjectType));

static U32 sClientCollisionContactMask = sCollisionMoveMask | PhysicalZoneObjectType;

// phdana turrets ->
static U32 sDirtySetMask = (PlayerObjectType | TurretObjectType | VehicleObjectType);
// <- phdana turrets
#109
03/05/2009 (4:43 am)
In player.h (just the phdana changes)

bool renderFirstPerson;    ///< Render the player shape in first person

   // phdana aiobject ->
   bool activatesTriggers;
   // <- phdana aiobject

#110
03/05/2009 (4:52 am)
In projectile.cpp

const U32 Projectile::csmDynamicCollisionMask = PlayerObjectType        |
                                                VehicleObjectType       |
												// phdana turrets ->
                                                TurretObjectType        |
                                                // <- phdana turrets
                                                DamagableItemObjectType;
#111
03/05/2009 (4:55 am)
In triggers.cpp

Add to Trigger datablock
// phdana turrets ->
   mOwner = NULL;
   // <- phdana turrets

Just add phdana code...
void Trigger::potentialEnterObject(GameBase* enter)
{
   AssertFatal(isServerObject(), "Error, should never be called on the client!");

   // phdana turrets ->
   // if we have an owner then we just call their potential enter
   // instead and let them do the rest of the processing
   if (mOwner != NULL)
   {
      mOwner->potentialEnterObject(enter);
      return;
   }
   // <- phdana turrets

Add at bottom
// phdana turrets ->
void Trigger::setOwner(GameBase *owner)
{
  mOwner = owner;
}
// <- phdana turrets

// phdana turrets ->
void cTriggerSetOwner(SimObject* obj, S32 argc, const char** argv )
{
   AssertFatal(dynamic_cast<Trigger*>(obj) != NULL, "Error, how did a non-trigger get here?");
   Trigger* trigger = static_cast<Trigger*>(obj);

   if (argc > 2)
   {
      GameBase* owner = NULL;
      if (Sim::findObject(argv[2], owner) == false)
         return;

      trigger->setOwner(owner);
   }

}
// <- phdana turrets

and after that...

Added whole method (not sure about this...)
void Trigger::consoleInit()
{
   // phdana aiobject ->
   Con::addCommand("Trigger", "setOwner",      cTriggerSetOwner,     "[TriggerObject].setOwner(obj)", 3, 3);
   // <- phdana aiobject
}
#112
03/05/2009 (4:57 am)
Added to trigger.h

Just add phdana code...
TriggerData*      mDataBlock;

   U32               mLastThink;
   U32               mCurrTick;

   // phdana turrets ->
   GameBase         *mOwner;
   // <- phdana turrets

Added to public: (just add phdana code)
public:
   void setTransform(const MatrixF &mat);

   // phdana aiobject ->
   void setOwner(GameBase *owner);
   // <- phdana aiobject

and further down (just phdana code)
... more code...

   static void initPersistFields();
   // phdana aiobject ->
   static void consoleInit();
   // <- phdana aiobject
#113
03/05/2009 (5:13 am)
All compiled and ran well - will add objects from ph tomorrow.
#114
03/05/2009 (12:07 pm)
Andy Hawkins, thanks for ur work! Wery usefull!
#115
03/06/2009 (6:50 am)
Testing the mod...

1. Copied these files from...
4116.turrets_pauldana\\torque\\example\\fps\\server\\scripts

over to...
GameExamples\\<your game>\\game\\scriptsAndAssets\\server\\scripts

aiTurret.cs
anotherAITurret.cs
genericAITurret.cs
genericTurret.cs
turret.cs

2. opened game.cs in ...
GameExamples\\<your game>\\game\\scriptsAndAssets\\server\\scripts

and added...(just add phdana code)

// phdana turrets ->
   exec("./turret.cs");
   exec("./aiTurret.cs");
   exec("./genericTurret.cs");
   exec("./genericAITurret.cs");
   // <- phdana turrets

   // Keep track of when the game started
   $Game::StartTime = $Sim::Time;
#116
03/06/2009 (6:51 am)
3. in player.cs (same folder) in Armor::doDismount(..)
(just add phdana code)
for (%i = 0; %i < %numAttempts; %i++) {
      %pos = VectorAdd(%oldPos, VectorScale(%vec[%i], 3));
      if (%obj.checkDismountPoint(%oldPos, %pos)) {
         %success = %i;
         %impulseVec = %vec[%i];
         break;
      }
   }
   if (%forced && %success == -1)
      %pos = %oldPos;

   // phdana turrets ->
      if(%obj.mVehicle)
      {
         %data = %obj.mVehicle.getDataBlock();
         if (%data.className $= TurretData)
            %data.playerDismounted(%obj.mVehicle, %obj);

         %obj.mVehicle.mountable = true;
        %client = %obj.client;
        if(%obj.mVehicle.mountedTurret.currentDriver == %client)
         %obj.mVehicle.mountedTurret.currentDriver = "";
      }

      %obj.mountVehicle = false;
      %obj.schedule(4000, "setMountVehicle", true);
      %obj.schedule(4000, "mountVehicles", true);

      // Mount last weapon used, unmount from node, and give player control.
      %obj.unMount();
      %this.onUnMount(%obj);
      %obj.setControlObject(%obj);

   // <- phdana turrets

4. still in player.cs in method Armor::onCollision(...)
(ad phdana code but it replaces this...)
// Mount vehicles
   %this = %col.getDataBlock();
   if ((%this.className $= WheeledVehicleData) && %obj.mountVehicle &&
         %obj.getState() $= "Move" && %col.mountable) {

      // Only mount drivers for now.
      %node = 0;
      %col.mountObject(%obj,%node);
      %obj.mVehicle = %col;
   }
with this...
// phdana turrets ->
   %obj.mountedTurret = "";

   // Mount vehicles or turrets
   %this = %col.getDataBlock();
   if ((%this.className $= WheeledVehicleData ||
       %this.className $= TurretData) && %obj.mountVehicle &&
         %obj.getState() $= "Move" && %col.mountable) {

         %node = findEmptySeat(%col, %this);
         if(%col.mountedTurret.currentDriver $= "" && %node > 0)
         {
            error("FOUND MOUNTED TURRET ON vehicle! %node =" SPC %node);
            %col.mountedTurret.mountObject(%obj, 0);
            %col.mountedTurret.currentDriver = %client;
            %turretMounted = true;
         }

         %col.mountable=true;// Set Vehicle mountable for other passengers

         if(!%turretMounted)
         {
            %col.mountObject(%obj,%node);
 		 	%player = %client.player;
 		 	%col.currentDriver = %client;
 		 	%client.currentMountedVehicle = %col;
 		 }
 		 %obj.mVehicle = %col;

        if(%this.className $= TurretData)
        {
          echo("Mounted a Turret, not a vehicle");
          %this.playerMounted(%col,%obj, %node);
        }
   }
   // <- phdana turrets

5. still in player.cs scroll down to bottom and add all this...
// phdana turrets ->
// if you dont already have this for vehicles
// you need it for turrets
function findEmptySeat(%vehicle, %vehicleblock)
{
  for (%i = 0; %i <  %vehicleblock.numMountPoints; %i++)
  {
    %node = %vehicle.getMountNodeObject(%i);
    if (%node == 0)
    {
         return %i;
    }
  }
  return -1;
}
// <- phdana turrets
#117
03/06/2009 (6:53 am)
6. in shapebase.cs scroll to bottom and add this code...
// phdana turrets ->

//-----------------------------------------------------------------------------
// ShapeBaseImage datablock
//-----------------------------------------------------------------------------

// any shape base image does this on fire
function ShapeBaseImageData::onFire(%data, %obj, %slot)
{
   echo("ShapeBaseImageData::onFire()");

	%projectile = %data.projectile;

	%muzzleVector = %obj.getMuzzleVector(%slot);
   %objectVelocity = %obj.getVelocity();

   %muzzleVelocity = VectorAdd(
      VectorScale(%muzzleVector, %projectile.muzzleVelocity),
      VectorScale(%objectVelocity, %projectile.velInheritFactor));

       %p = new (%data.projectileType)() {
         dataBlock        = %data.projectile;
         initialVelocity  = %muzzleVelocity;
         initialDirection = %obj.getMuzzleVector(%slot);
         initialPosition  = %obj.getMuzzlePoint(%slot);
         sourceObject     = %obj;
         sourceSlot       = %slot;
      };

   if (isObject(%obj.lastProjectile) && %obj.deleteLastProjectile)
      %obj.lastProjectile.delete();

   %obj.lastProjectile = %p;
   %obj.deleteLastProjectile = %data.deleteLastProjectile;

   MissionCleanup.add(%p);

   return %p;
}

// <- phdana turrets
#118
03/06/2009 (6:54 am)
Second last step!!!

Copy this entire folder...
4116.turrets_pauldana\torque\example\fps\data\shapes\turrets

to
GameExamples\<your game>\game\scriptsAndAssets\data\shapes
#119
03/06/2009 (6:57 am)
Last step

Run game, press F11, press F4, drill down to Shapes\Turrets,
and add Generic Turret and place - is starts below the terrain so drag it up. (this is for the player)

Then add GenericAI Turret, place it, and run around. It will track and fire at you.

NOTE: Did not fire projectile, and I couldn't mount player turret.
#120
03/06/2009 (7:47 am)
Yeah played around a bit and I still can't mount the turret or get the aiturret to fire a projectile.

mounting a turret I get these errors
scriptsAndAssets/server/scripts/player.cs (761): Unable to find function findEmptySeat
FOUND MOUNTED TURRET ON vehicle! %node = 2276
scriptsAndAssets/server/scripts/player.cs (765): Unable to find object: '' attempting to call function 'mountObject'
Mounted a Turret, not a vehicle
TurretData::playerMounted()

and the aiturret I tried adding this to the datablock...
projectile = RifleProjectile;


but it doesn't fire :( I go over to the Aiturret and the projectile is stuck on the turret pointing down, there is glow on the floor but the projectile doesn't move. Seems to have no angle or velocity.