Tremulous Forum
Mods => Mod Releases => Gameplay Changing => Topic started 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.
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.
-
Ehhh sounds nice!
-
Interesting feature, it would definitely make the defcomp more useful if the implementation is good :)
-
I hope Norfenstein hears about this.
-
Kickass.
-
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.
-
Too Smart Turrets... :-)
-
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.
-
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,
***************
*** 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,
***************
*** 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.
-
(Thorn, I hate when you are being right)
Did you try to patch revision 90? (it can be seen from the patch itself).
-
Nope...woops, I patched rev 895, I tried to get 90 though, it wouldn't download.
-
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/