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.
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.