Tremulous Forum

Mods => Mod Releases => Gameplay Changing => Topic started by: ==Troy== on August 29, 2008, 07:29:07 pm

Title: Smart Turrets
Post by: ==Troy== on August 29, 2008, 07:29:07 pm
Another little gadged from me. If humans built DefComp, the turrets start to record where the aliens are coming from, and turn to that direction if they are idle. A little bit of mess with the turret yaw/pitch code, since otherwise it went crazy. Again, diff from latest Lakitu.

Code: [Select]
Index: src/game/g_buildable.c
===================================================================
--- src/game/g_buildable.c (revision 90)
+++ src/game/g_buildable.c (working copy)
@@ -2121,9 +2121,232 @@
   return qtrue;
 }
 
+float turret_trunc( float val )
+{
+if (val >= 0)
+  return (float)((int)(val));
+else
+  return (float)((int)(val - 1));
+}
+void TurretVectorCorrect( vec3_t vec )
+{
+vec[ YAW ] -= (float)(turret_trunc(vec[ YAW ]/360.0f)*360);
+vec[ PITCH ] -= (float)((turret_trunc(vec[ PITCH ]/360.0f))*360 + 360);
+}
 
 /*
 ================
+HMGTurret_StoreIncomingDirection
+
+Used by HMGTurret_Think to store the direction from which the target came from
+after the target is destroyed/OOR  the turret will turn back there
+================
+*/
+
+qboolean HMGTurret_StoreIncomingDirection ( gentity_t *self, gentity_t *target )  //mainly the code is copied from the turret aiming function but instead we store the initial angle
+{
+  vec3_t  dirToTarget, dttAdjusted, angleToTarget, angularDiff, xNormal;
+  vec3_t  refNormal = { 0.0f, 0.0f, 1.0f };
+  float   rotAngle;
+  int i;

+  if (!target) return qfalse;
+
+  VectorSubtract( target->s.pos.trBase, self->s.pos.trBase, dirToTarget );
+
+  VectorNormalize( dirToTarget );
+
+  CrossProduct( self->s.origin2, refNormal, xNormal );
+  VectorNormalize( xNormal );
+  rotAngle = RAD2DEG( acos( DotProduct( self->s.origin2, refNormal ) ) );
+  RotatePointAroundVector( dttAdjusted, xNormal, dirToTarget, rotAngle );
+
+  vectoangles( dttAdjusted, angleToTarget );

+

+   if ( self->totalAngles == -1)
+   {
+        self->totalAngles++;
+    VectorCopy( angleToTarget, self->angleMem[self->totalAngles] );
+    TurretVectorCorrect(self->angleMem[self->totalAngles]);
+    self->angleFrequency[self->totalAngles] += 100;
+    //trap_SendServerCommand( -1, va( "print \"Initialised\n\""));
+    return qtrue;
+   }
+  
+   for (i = 0; i <= self->totalAngles; i++)
+   {
+     angularDiff[ PITCH ] = AngleSubtract( self->angleMem[i][ PITCH ], angleToTarget[ PITCH ] );
+     angularDiff[ YAW ] = AngleSubtract( self->angleMem[i][ YAW ], angleToTarget[ YAW ] );
+     if (fabs(angularDiff[ YAW ]) < MAX_ANGLE_TOLERANCE && fabs(angularDiff[ PITCH ]) < MAX_ANGLE_TOLERANCE) // add-on the value, averaging out the direction
+     {
+   int j;
+      self->angleMem[i][ YAW ] -= angularDiff[ YAW ]/2.0f;
+ self->angleMem[i][ PITCH ] -= angularDiff[ PITCH ]/2.0f;
+ TurretVectorCorrect(self->angleMem[i]);
+ self->angleFrequency[i] += 100;
+   for (j = 0; j <= self->totalAngles; j++) // scale down the latter frequencies
+   {
+ if (j == i) continue;
+     self->angleFrequency[j] *= 0.8;
+   }
+   //trap_SendServerCommand( -1, va( "print \"Value added\n\""));
+   return qtrue;
+     }
+    }
+
+
+      if (self->totalAngles == MAX_ANGLE_MEM - 1)
+   {
+    int j, k = 0;
+    for(j = 0; j < MAX_ANGLE_MEM - 1; j++) // find the least frequent stored direction and overwrite it
+    {
+      if (self->angleFrequency[k] > self->angleFrequency[j]) k = j;
+    }
+    
+    VectorCopy( angleToTarget, self->angleMem[k] );
+    self->angleFrequency[k] += 100;
+    TurretVectorCorrect(self->angleMem[k]);
+    //trap_SendServerCommand( -1, va( "print \"Direction replaced\n\""));
+    return qtrue;
+   }
+   else // add a new direction
+   {
+    self->totalAngles++;
+    VectorCopy( angleToTarget, self->angleMem[self->totalAngles] );
+    self->angleFrequency[self->totalAngles] += 100;
+    TurretVectorCorrect(self->angleMem[self->totalAngles]);
+    //trap_SendServerCommand( -1, va( "print \"Direction created\n\""));
+    return qtrue;
+   }
+

+
+  return qfalse;
+}
+
+
+
+/*
+================
+HMGTurret_ReturnDirection
+
+Used by HMGTurret_Think to return the aiming directions to the recorded state
+================
+*/
+
+
+void HMGTurret_ReturnDirection( gentity_t *self )
+{
+  vec3_t  angleToTarget, angularDiff;
+  float   temp;
+  float   accuracyTolerance, angularSpeed;
+
+
+ if (self->totalAngles < 0) return;
+
+ if (self->returnedTo >= 0 || self->returning < 0)
+ {
+   int i, j = 0, m = 0;
+   float k;
+  
+   if ( self->totalAngles == 0 )
+   {
+     if ( self->returnedTo != 0 ) self->returning = 0;
+      }
+   else
+   {
+     int seed;
+ seed = trap_Milliseconds();
+ if (self->returnedTo >=0 && self->idleTimeStamp > level.time) return; // we didnt want to change direction this time
+     k = Q_random(&seed);
+     for (i = 0; i <= self->totalAngles; i++)
+     {
+       j += self->angleFrequency[i];
+     }
+ for (i = 0; i <= self->totalAngles; i++)
+     {
+   m += self->angleFrequency[i];
+       if( k <= (float)(m)/(float)(j) )
+   {
+ if ( i == self->returnedTo ) return;
+ //trap_SendServerCommand( -1, va( "print \"Chosen the new Direction, %i\n\"", i));
+     self->returning = i;
+ self->returnedTo = -1;
+ break;
+   }
+     }
+   }
+ }
+ else
+ {
+     if( self->lev1Grabbed )
+     {
+       //can't turn fast if grabbed
+       accuracyTolerance = MGTURRET_GRAB_ACCURACYTOLERANCE;
+       angularSpeed = MGTURRET_GRAB_ANGULARSPEED;
+     }
+     else if( self->dcced )
+     {
+       accuracyTolerance = MGTURRET_DCC_ACCURACYTOLERANCE;
+       angularSpeed = MGTURRET_DCC_ANGULARSPEED;
+     }
+     else
+     {
+       accuracyTolerance = MGTURRET_ACCURACYTOLERANCE;
+       angularSpeed = MGTURRET_ANGULARSPEED;
+     }
+   VectorCopy(self->angleMem[self->returning], angleToTarget);
+       angularDiff[ PITCH ] = AngleSubtract( self->s.angles2[ PITCH ], angleToTarget[ PITCH ] );
+          angularDiff[ YAW ] = AngleSubtract( self->s.angles2[ YAW ], angleToTarget[ YAW ] );
+  
+           //if not pointing at our target then move accordingly
+           if( angularDiff[ PITCH ] < (-accuracyTolerance) )
+             self->s.angles2[ PITCH ] += angularSpeed;
+           else if( angularDiff[ PITCH ] > accuracyTolerance )
+             self->s.angles2[ PITCH ] -= angularSpeed;
+           else
+             self->s.angles2[ PITCH ] = angleToTarget[ PITCH ];
+         
+           //disallow vertical movement past a certain limit
+           temp = fabs( self->s.angles2[ PITCH ] );
+           if( temp > 180 )
+             temp -= 360;
+
+           if( temp < -MGTURRET_VERTICALCAP )
+             self->s.angles2[ PITCH ] = (-360) + MGTURRET_VERTICALCAP;
+         
+           //if not pointing at our target then move accordingly
+           if( angularDiff[ YAW ] < (-accuracyTolerance) )
+             self->s.angles2[ YAW ] += angularSpeed;
+           else if( angularDiff[ YAW ] > accuracyTolerance )
+             self->s.angles2[ YAW ] -= angularSpeed;
+           else
+             self->s.angles2[ YAW ] = angleToTarget[ YAW ];
+
+   if ( self->s.angles2[ YAW ] == angleToTarget[ YAW ] && (self->s.angles2[ PITCH ] == angleToTarget[ PITCH ] || self->s.angles2[ PITCH ] == (-360) + MGTURRET_VERTICALCAP))
+   {
+     int seed;
+ seed = trap_Milliseconds();
+ //trap_SendServerCommand( -1, va( "print \"Reached direction, returnedTo : %i\n\"", self->returning));
+     self->returnedTo = self->returning;
+     self->returning = -1;
+ self->idleTimeStamp = level.time + MIN_IDLE_STAMP + (int)(3*MIN_IDLE_STAMP*Q_random(&seed));
+ return;
+   }
+  
+  
+ }
+
+
+}
+
+
+
+
+/*
+================
 HMGTurret_FindEnemy
 
 Used by HMGTurret_Think to locate enemy gentities
@@ -2135,7 +2358,7 @@
   vec3_t    range;
   vec3_t    mins, maxs;
   int       i, num;
-  gentity_t *target;
+  gentity_t *target, *mate;
 
   VectorSet( range, MGTURRET_RANGE, MGTURRET_RANGE, MGTURRET_RANGE );
   VectorAdd( self->s.origin, range, maxs );
@@ -2155,6 +2378,19 @@
 
       //we found a target
       self->enemy = target;
+   if (self->dcced && !target->recorded)
+   { 
+    int j;
+     target->recorded = HMGTurret_StoreIncomingDirection( self, target );
+ for (j = 0; j < num; j++)
+ {
+   mate = &g_entities[ entityList[ j ] ];
+   if ( mate != self && mate->s.eType == ET_BUILDABLE && mate->s.modelindex == BA_H_MGTURRET )
+   {
+     HMGTurret_StoreIncomingDirection( mate, target );
+   }  
+ }
+   }
       return;
     }
   }
@@ -2174,6 +2410,19 @@
 
         //we found a target
         self->enemy = target;
+     if (self->dcced && !target->recorded)
+     { 
+      int j;
+       target->recorded = HMGTurret_StoreIncomingDirection( self, target );
+     for (j = 0; j < num; j++)
+   {
+     mate = &g_entities[ entityList[ j ] ];
+     if ( mate != self && mate->s.eType == ET_BUILDABLE && mate->s.modelindex == BA_H_MGTURRET )
+     {
+       HMGTurret_StoreIncomingDirection( mate, target );
+     }  
+   }
+     }
         return;
       }
     }
@@ -2217,14 +2466,20 @@
     {
       if( self->enemy )
         self->enemy->targeted = NULL;
-
       HMGTurret_FindEnemy( self );
     }
 
     //if a new target cannot be found don't do anything
     if( !self->enemy )
-      return;
-
+ {
+   if( self->dcced ) HMGTurret_ReturnDirection( self );
+   return;
+    }
+ else
+ {
+   self->returnedTo = -1;
+ }
+
     self->enemy->targeted = self;
 
     //if we are pointing at our target and we can fire shoot it
@@ -2236,7 +2491,6 @@
       self->s.eFlags |= EF_FIRING;
       G_AddEvent( self, EV_FIRE_WEAPON, 0 );
       G_SetBuildableAnim( self, BANIM_ATTACK1, qfalse );
-
       self->count = level.time + firespeed;
     }
   }
@@ -3238,6 +3492,10 @@
   built->spawned = qfalse;
   built->buildTime = built->s.time = level.time;
   built->spawnBlockTime = 0;

+  built->totalAngles = -1;
+  built->returning = -1;
+  built->returnedTo = -1;
 
   // build instantly in cheat mode
   if( builder->client && g_cheats.integer )
@@ -3588,6 +3846,9 @@
 
   built->takedamage = qtrue;
   built->spawned = qtrue; //map entities are already spawned
+  built->totalAngles = -1;
+  built->returning = -1;
+  built->returnedTo = -1;
   built->health = BG_FindHealthForBuildable( buildable );
   built->s.generic1 |= B_SPAWNED_TOGGLEBIT;
 
@@ -3916,6 +4177,9 @@
 
   built->takedamage = qtrue;
   built->spawned = qtrue; //map entities are already spawned
+  built->totalAngles = -1;
+  built->returning = -1;
+  built->returnedTo = -1;
   built->health = BG_FindHealthForBuildable( buildable );
   built->s.generic1 |= B_SPAWNED_TOGGLEBIT;
 
Index: src/game/g_client.c
===================================================================
--- src/game/g_client.c (revision 90)
+++ src/game/g_client.c (working copy)
@@ -1596,7 +1596,7 @@
   ent->waterlevel = 0;
   ent->watertype = 0;
   ent->flags = 0;
-
+  ent->recorded = qfalse;
   //TA: calculate each client's acceleration
   ent->evaluateAcceleration = qtrue;
 
Index: src/game/g_local.h
===================================================================
--- src/game/g_local.h (revision 90)
+++ src/game/g_local.h (working copy)
@@ -243,6 +243,17 @@
   int               lastDamageTime;
   
   int               bdnumb; // buildlog entry ID

+  #define MAX_ANGLE_MEM 16
+  #define MAX_ANGLE_TOLERANCE  45.0f
+  #define MIN_IDLE_STAMP  5000
+  vec3_t angleMem[ MAX_ANGLE_MEM];
+  int angleFrequency[ MAX_ANGLE_MEM ];
+  int totalAngles;
+  qboolean recorded;
+  int returning;
+  int returnedTo;
+  int idleTimeStamp;
 };
 
 typedef enum


Edit : forgot to say, in the case if the turret will find more than 2 distinct direction (from where the aliens are coming) it will "scan" both of them, turning one way or another at random time periods.
Title: Re: Smart Turrets
Post by: seeeker on August 29, 2008, 10:40:43 pm
Ehhh sounds nice!
Title: Re: Smart Turrets
Post by: TRaK on August 29, 2008, 10:50:39 pm
Interesting feature, it would definitely make the defcomp more useful if the implementation is good :)
Title: Re: Smart Turrets
Post by: techhead on September 01, 2008, 02:50:30 am
I hope Norfenstein hears about this.
Title: Re: Smart Turrets
Post by: Hendrich on September 04, 2008, 01:49:30 am
Kickass.
Title: Re: Smart Turrets
Post by: rotacak on September 04, 2008, 01:50:51 pm
I think this fixing that what should not be fixed. If turret will be allways looking at entrance, what dretch should do? Now is possible that another alien attack enemy base and turned turrets somewhere else. Then dretch can run in base too, because turrets looking somewhere else.
Or even dretch can make one attack and turn turrets to left side and die. Then make second attack and can run by right side into base before turrets turn to him.
But with this will be dretch allways dead whatever he do.
Title: Re: Smart Turrets
Post by: + OPTIMUS + on September 04, 2008, 01:56:59 pm
Too Smart Turrets... :-)
Title: Re: Smart Turrets
Post by: ==Troy== on September 04, 2008, 02:06:04 pm
rotacak. This was an interesting thing to code, thats all that matters. Its up to server admins to decide whether they want it or not. And in any way you are required to have DC for them to work.
Title: Re: Smart Turrets
Post by: Ghosthree3 on September 06, 2008, 04:21:15 am
I applied the patch, it failed for two hunks I got two files, "g_buildable.c.rej" and "g_local.h.rej". In "g_buildable.c.rej" I get,
Code: [Select]
***************
*** 3238,3243 ****
    built->spawned = qfalse;
    built->buildTime = built->s.time = level.time;
    built->spawnBlockTime = 0;
 
    // build instantly in cheat mode
    if( builder->client && g_cheats.integer )
--- 3492,3501 ----
    built->spawned = qfalse;
    built->buildTime = built->s.time = level.time;
    built->spawnBlockTime = 0;
+   
+   built->totalAngles = -1;
+   built->returning = -1;
+   built->returnedTo = -1;
 
    // build instantly in cheat mode
    if( builder->client && g_cheats.integer )
In "g_local.h.rej" I get,
Code: [Select]
***************
*** 243,248 ****
    int               lastDamageTime;
   
    int               bdnumb; // buildlog entry ID
  };
 
 
--- 243,259 ----
    int               lastDamageTime;
   
    int               bdnumb; // buildlog entry ID
+   
+   #define MAX_ANGLE_MEM 16
+   #define MAX_ANGLE_TOLERANCE  45.0f
+   #define MIN_IDLE_STAMP  5000
+   vec3_t angleMem[ MAX_ANGLE_MEM];
+   int angleFrequency[ MAX_ANGLE_MEM ];
+   int totalAngles;
+   qboolean recorded;
+   int returning;
+   int returnedTo;
+   int idleTimeStamp;
  };
 
 

I tried applying them manually, it still didn't seem to work, or maybe I'm not sure what I was meant to be looking for.
Title: Re: Smart Turrets
Post by: ==Troy== on September 06, 2008, 01:24:32 pm
(Thorn, I hate when you are being right)

Did you try to patch revision 90? (it can be seen from the patch itself).
Title: Re: Smart Turrets
Post by: Ghosthree3 on September 07, 2008, 12:25:07 am
Nope...woops, I patched rev 895, I tried to get 90 though, it wouldn't download.
Title: Re: Smart Turrets
Post by: ==Troy== on September 07, 2008, 12:33:28 am
Ah, well, you see, khm... I was making a diff from commonly used Lakitu qvm (its just easier for me to maintain and test). So you would want to use this svn : http://source.mercenariesguild.net/lakitu7-qvm/