Tremulous Forum

Mods => Mod Releases => Gameplay Changing => Topic started by: ==Troy== on August 18, 2008, 09:00:43 pm

Title: Hive's swarm following around the corners.
Post by: ==Troy== on August 18, 2008, 09:00:43 pm
A small patch (diff from latest Lakitu) which allows swarms to follow players around the corners. Its not the most optimal way to do it, but it works nicely and it is quite hard to get rid of the swarm, only doors or complicated brushwork will help.


Code: [Select]
Index: src/game/g_local.h
===================================================================
--- src/game/g_local.h (revision 87)
+++ src/game/g_local.h (working copy)
@@ -242,6 +242,10 @@
   int               lastDamageTime;
   
   int               bdnumb; // buildlog entry ID

+    #define MAX_WPA 31
+  vec3_t WPA[ MAX_WPA + 1 ];
+  int TotalWP;
 };
 
 typedef enum
Index: src/game/g_missile.c
===================================================================
--- src/game/g_missile.c (revision 87)
+++ src/game/g_missile.c (working copy)
@@ -582,34 +582,127 @@
 */
 void AHive_SearchAndDestroy( gentity_t *self )
 {
+
   vec3_t dir;
-  trace_t tr;
-
+  trace_t tr, tr2, tr3;
+  vec3_t Torigin;
+  gentity_t *traceEnt;

+ if (self->TotalWP == 0 )
+ {
+ self->TotalWP++;
+ VectorCopy(self->target_ent->r.currentOrigin, self->WPA[ 0 ]);
+ VectorCopy(self->target_ent->r.currentOrigin, self->WPA[ self->TotalWP ]);
+ }
   trap_Trace( &tr, self->r.currentOrigin, self->r.mins, self->r.maxs,
               self->target_ent->r.currentOrigin, self->r.ownerNum, self->clipmask );
+  traceEnt = &g_entities[ tr.entityNum ];
 
   //if there is no LOS or the parent hive is too far away or the target is dead or notargeting, return
-  if( tr.entityNum == ENTITYNUM_WORLD ||
-      Distance( self->r.currentOrigin, self->parent->r.currentOrigin ) > ( HIVE_RANGE * 5 ) ||
+  if( Distance( self->r.currentOrigin, self->parent->r.currentOrigin ) > ( HIVE_RANGE * 30 ) ||
       self->target_ent->health <= 0 || self->target_ent->flags & FL_NOTARGET )
   {
     self->r.ownerNum = ENTITYNUM_WORLD;
 
     self->think = AHive_ReturnToHive;
     self->nextthink = level.time + FRAMETIME;
+ return;
   }
   else
   {
-    VectorSubtract( self->target_ent->r.currentOrigin, self->r.currentOrigin, dir );
+ if ( tr.entityNum == ENTITYNUM_WORLD || traceEnt->s.eType == ET_BUILDABLE)
+ {
+ trap_Trace( &tr2, self->WPA[ self->TotalWP - 1 ], self->r.mins, self->r.maxs,
+ self->target_ent->r.currentOrigin, self->r.ownerNum, self->clipmask );
+     traceEnt = &g_entities[ tr2.entityNum ];
+ if ( tr2.entityNum == ENTITYNUM_WORLD || traceEnt->s.eType == ET_BUILDABLE )
+ {
+ trap_Trace( &tr3, self->WPA[ self->TotalWP ], self->r.mins, self->r.maxs,
+ self->target_ent->r.currentOrigin, self->r.ownerNum, self->clipmask ); // if the player turned around another corner while we were thinking, drop the target.
+   traceEnt = &g_entities[ tr3.entityNum ];
+ if ( tr3.entityNum == ENTITYNUM_WORLD || traceEnt->s.eType == ET_BUILDABLE )
+ {
+ self->r.ownerNum = ENTITYNUM_WORLD;
+
+ self->think = AHive_ReturnToHive;
+ self->nextthink = level.time + FRAMETIME;
+ //trap_SendServerCommand( -1, va( "print \"Lost Target\n\""));
+ return; // lost the track, get back home
+ }
+ else
+ {
+ if (self->TotalWP < MAX_WPA)
+ {
+ self->TotalWP++;
+ //trap_SendServerCommand( -1, va( "print \"New Waypoint, %i\n\"", self->TotalWP - 1));
+ VectorCopy(self->target_ent->r.currentOrigin, self->WPA[ self->TotalWP ]);
+ }
+ else
+ {
+ self->r.ownerNum = ENTITYNUM_WORLD;
+
+ self->think = AHive_ReturnToHive;
+ self->nextthink = level.time + FRAMETIME;
+ //trap_SendServerCommand( -1, va( "print \"Out Of memory\n\""));
+ return; // out of memory, get back home
+ }
+ }
+ }
+ else
+ {
+ VectorCopy(self->target_ent->r.currentOrigin, self->WPA[ self->TotalWP ]); //update latest waypoint without creating a new one, if there is a LOS from the old one
+ }
+ }
+ else
+ {
+ int i;
+ if (self->TotalWP > 1)
+ {
+ self->TotalWP = 1;
+ //trap_SendServerCommand( -1, va( "print \"Direct Line of Sight\n\""));
+ }
+ VectorCopy(self->target_ent->r.currentOrigin, self->WPA[ 0 ]);
+ VectorCopy(self->target_ent->r.currentOrigin, self->WPA[ self->TotalWP ]);
+
+
+ }
+
+ if (Distance( self->r.currentOrigin, self->WPA[ 0 ]) < 64 && self->TotalWP > 1) // snap the swarm to the waypoint if it is close enough.
+ {
+ int i;
+ VectorCopy(self->WPA[ 0 ], self->r.currentOrigin);
+ for (i = 0; i <= MAX_WPA; i++)
+ {
+ VectorCopy(self->WPA[i+1], self->WPA[i]);
+ }
+ self->TotalWP--;
+ if (self->TotalWP < 1) self->TotalWP = 1;
+ VectorCopy(self->target_ent->r.currentOrigin, self->WPA[ self->TotalWP ]);
+ //trap_SendServerCommand( -1, va( "print \"Waypoint Reached\n\""));
+ }
+
+ trap_Trace( &tr, self->r.currentOrigin, self->r.mins, self->r.maxs,
+        self->WPA[ 0 ], self->r.ownerNum, self->clipmask );
+   traceEnt = &g_entities[ tr.entityNum ];
+ if ( tr.entityNum == ENTITYNUM_WORLD || traceEnt->s.eType == ET_BUILDABLE )  // check for doors closing
+ {
+
+     self->r.ownerNum = ENTITYNUM_WORLD;
+
+ self->think = AHive_ReturnToHive;
+ self->nextthink = level.time + FRAMETIME;
+ //trap_SendServerCommand( -1, va( "print \"Invalid Waypoint\n\""));
+ return;
+ }
+
+ VectorSubtract( self->WPA[ 0 ], self->r.currentOrigin, dir );
     VectorNormalize( dir );
-
     //change direction towards the player
     VectorScale( dir, HIVE_SPEED, self->s.pos.trDelta );
     SnapVector( self->s.pos.trDelta );      // save net bandwidth
     VectorCopy( self->r.currentOrigin, self->s.pos.trBase );
     self->s.pos.trTime = level.time;
-
-    self->nextthink = level.time + HIVE_DIR_CHANGE_PERIOD;
+    self->nextthink = level.time + HIVE_DIR_CHANGE_PERIOD/2;
   }
 }
 
@@ -641,7 +734,8 @@
   bolt->methodOfDeath = MOD_SWARM;
   bolt->clipmask = MASK_SHOT;
   bolt->target_ent = self->target_ent;
-
+  bolt->TotalWP = 0;

   bolt->s.pos.trType = TR_LINEAR;
   bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME;   // move a bit on the very first frame
   VectorCopy( start, bolt->s.pos.trBase );

Title: Re: Hive's swarm following around the corners.
Post by: mooseberry on August 18, 2008, 09:08:16 pm
Yay, even more annoying hives!  :P

But good work!
Title: Re: Hive's swarm following around the corners.
Post by: Lakitu7 on August 18, 2008, 09:47:34 pm
Hmm, nice idea and nice work. I'm going to poke Norf and see what he thinks about trying a change like this on mgdev...
Title: Re: Hive's swarm following around the corners.
Post by: Norfenstein on August 18, 2008, 10:23:40 pm
I'm not sure how often people actually try to run away from the swarms (I usually just dance around in the alien base until I die) but they do still need something, and this sounds like something good to try.
Title: Re: Hive's swarm following around the corners.
Post by: ==Troy== on August 18, 2008, 11:05:32 pm
Updated the code a little, added a WORKING check for doors now. :)
Title: Re: Hive's swarm following around the corners.
Post by: Bissig on August 18, 2008, 11:28:28 pm
I'd like to see swarms being more efficient ;-) Nice work!
Title: Re: Hive's swarm following around the corners.
Post by: techhead on August 19, 2008, 03:39:26 am
I honestly think that they should either move slightly faster or slightly slower. With them moving at the same speed as a non-sprinting human, one can run in circles for a while until the swarm gets bored and runs back to the hive. Between non-sprint and sprint would be best, in my honest opinion.
Also, they should be unable to travel through water, even though water is seldom used in Tremulous maps.
Title: Re: Hive's swarm following around the corners.
Post by: ==Troy== on August 25, 2008, 09:38:48 pm
fixed a memory leak, the top post is updated.
Title: Re: Hive's swarm following around the corners.
Post by: Paradox on August 26, 2008, 02:33:32 am
Added to the P-G-Qvm porting list.

Soon ill have patched up and released a new version.
Title: Re: Hive's swarm following around the corners.
Post by: professor on August 26, 2008, 06:19:28 am
 i like this idea
hows this though... u get a trapper :trapper: and mix it wit a hive :hive: then when the hummys come the swarm carrys the trapper juice and chases the hummy :human:
and its stuck till a friendly tyrant :tyrant: or granger :granger: wit :grenade: comes along!
Title: Re: Hive's swarm following around the corners.
Post by: Bomb on August 26, 2008, 02:20:29 pm
i like this idea
hows this though... u get a trapper :trapper: and mix it wit a hive :hive: then when the hummys come the swarm carrys the trapper juice and chases the hummy :human:
and its stuck till a friendly tyrant :tyrant: or granger :granger: wit :grenade: comes along!

(http://lizrevision.com/wp-content/uploads/royal-fail.jpg)
Title: Re: Hive's swarm following around the corners.
Post by: Lava Croft on August 26, 2008, 04:50:17 pm
I'm starting to get visions of System Shock 2's bees. Good work!
Title: Re: Hive's swarm following around the corners.
Post by: professor on August 26, 2008, 05:42:24 pm
http://i148.photobucket.com/albums/s16/r3v3r3nd_album/fail1.jpg
 http://forum.alsacreations.com/upload/2043-fail-camera.jpg

and u thought i was bad

Title: Re: Hive's swarm following around the corners.
Post by: ==Troy== on September 01, 2008, 02:31:29 pm
Hives can now shoot around corners (or rather, learn to shoot around corners). I am posting this separately, even though it uses the same principle as the above patch, but is not a realy improvement, just a different feature.

In this patch the hives learn to shoot around buildables/corners and the swarm itself follows the player around the corners/buildables, Yet again diff from Lakitu.

Code: [Select]
Index: src/game/g_buildable.c
===================================================================
--- src/game/g_buildable.c (revision 87)
+++ src/game/g_buildable.c (working copy)
@@ -1106,8 +1106,24 @@
 //==================================================================================
 
 
+qboolean Hive_CheckWP( vec3_t org1, vec3_t org2, gentity_t *ent )
+{
+  trace_t tr;
+  gentity_t *traceEnt;
 
+  trap_Trace( &tr, org1, NULL, NULL, org2, ent->s.number, MASK_SHOT );
+  traceEnt = &g_entities[ tr.entityNum ];

+  if( tr.entityNum == ENTITYNUM_WORLD || traceEnt->s.eType == ET_BUILDABLE )
+    return qfalse;
 
+  return qtrue;
+}
+
+
+
+
+
 /*
 ================
 AHive_Think
@@ -1120,10 +1136,14 @@
   int       entityList[ MAX_GENTITIES ];
   vec3_t    range = { ACIDTUBE_RANGE, ACIDTUBE_RANGE, ACIDTUBE_RANGE };
   vec3_t    mins, maxs;
-  int       i, num;
+  int       i, num, j, k;
   gentity_t *enemy;
   vec3_t    dirToTarget;
-
+  qboolean  visible, fvisible;
+  int TWP = -1, freeTWP = -1, createTWP = -1;
+  qboolean  WP1, WP2;


   self->powered = G_IsOvermindBuilt( );
 
   self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex );
@@ -1140,31 +1160,141 @@
 
   if( self->timestamp < level.time )
     self->active = qfalse; //nothing has returned in HIVE_REPEAT seconds, forget about it
-
+
+  if( self->RecheckTime < level.time)
+  {
+    self->RecheckTime = level.time + HIVE_RECHECK;
+ ;//trap_SendServerCommand( -1, va( "print \"Rechecking Hive, number of waypoints : %i\n\"", self->TotalWP));
+ for(j = 1; j <= self->TotalWP; j++)
+ {
+     while ( j <= self->TotalWP && (!Hive_CheckWP(self->r.currentOrigin, self->WPA[j-1], self) || (!Hive_CheckWP(self->WPA[j-1], self->WPA2[j-1], self) && self->inUse[j-1])))
+ {
+   for(k = j; k <= self->TotalWP; k++)
+   {
+     VectorCopy(self->WPA[k], self->WPA[k-1]);
+ VectorCopy(self->WPA2[k], self->WPA2[k-1]);
+ self->inUse[k-1] = self->inUse[k];
+   }
+   self->TotalWP--;
+   ;//trap_SendServerCommand( -1, va( "print \"Removed invalid waypoint\n\""));
+ }
+ }
+  }


   if( self->spawned && !self->active && G_FindOvermind( self ) )
   {
     //do some damage
     num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
+ self->targWP = -1;
     for( i = 0; i < num; i++ )
     {
       enemy = &g_entities[ entityList[ i ] ];
 
       if( enemy->flags & FL_NOTARGET )
- continue;
+     continue;
 
-      if( enemy->health <= 0 )
+      if( enemy->health <= 0 || !enemy->client || enemy->client->ps.stats[ STAT_PTEAM ] != PTE_HUMANS)
         continue;
+
+   ;//trap_SendServerCommand( -1, va( "print \"Target Detected\n\""));
+      if( !Hive_CheckWP( self->r.currentOrigin, enemy->r.currentOrigin, self ) )
+   {
+     ;//trap_SendServerCommand( -1, va( "print \"no LOS, checking waypoints\n\""));
+ TWP = freeTWP = createTWP = -1;
+     for (j = 1; j <= self->TotalWP; j++)
+ {
+   WP1 = Hive_CheckWP( self->WPA[j-1], enemy->r.currentOrigin, self );
+   if( self->inUse[j-1] )
+     WP2 = Hive_CheckWP( self->WPA2[j-1], enemy->r.currentOrigin, self );
+   else
+     WP2 = qfalse;
+
+   if (!WP1 && WP2) { TWP = -2 - (j-1); break; }  
+   if (WP1 && WP2) { TWP = j-1; break; }
+   if (WP1 && !WP2 && self->inUse[j-1] ) createTWP = j-1;
+   if (WP1 && !self->inUse[j-1] ) freeTWP = j-1;
+ }
+
+ if (TWP == -1)
+ {
+   if (freeTWP == -1)
+   {
+     if (createTWP != -1 && self->TotalWP <= MAX_WPA)
+ {
+   VectorCopy( self->WPA[createTWP], self->WPA[self->TotalWP]);
+   VectorCopy( enemy->r.currentOrigin, self->WPA2[self->TotalWP]);
+       self->inUse[self->TotalWP] = qtrue;
+       self->TotalWP++;
+   self->targWP = createTWP;
+       ;//trap_SendServerCommand( -1, va( "print \"Waypoint cloned\n\""));
+ }
+   }
+   else
+   {
+     VectorCopy( enemy->r.currentOrigin, self->WPA2[freeTWP]);
+     self->inUse[freeTWP] = qtrue;
+ self->targWP = freeTWP;
+ ;//trap_SendServerCommand( -1, va( "print \"Secondary Assigned\n\""));
+   }  
+ }
+ else
+ {
+   self->targWP = TWP;
+   ;//trap_SendServerCommand( -1, va( "print \"Firing normally\n\""));
+ }
+
+
+ if (self->targWP == -1)
+   continue;
+ else
+   ;//trap_SendServerCommand( -1, va( "print \"Found Waypoint, here it goes!\n\""));
+  
+   }
+   else
+   {
+     ;//trap_SendServerCommand( -1, va( "print \"We have LOS, record waypoint\n\""));
+ if (self->TotalWP <= MAX_WPA)
+ {
+     visible = qfalse;
+ fvisible = qfalse;
+     for (j = 1; j <= self->TotalWP; j++)
+ {
+   if ( (self->inUse[j-1] && (visible = Hive_CheckWP(self->WPA2[j-1], enemy->r.currentOrigin, self))) || 
+        (!self->inUse[j-1] && (fvisible = Hive_CheckWP(self->WPA[j-1], enemy->r.currentOrigin, self)))) break;
+ }
+ if (!visible)
+ {
+   if (fvisible)
+   {
+ VectorCopy( enemy->r.currentOrigin, self->WPA[j-1]);
+ ;//trap_SendServerCommand( -1, va( "print \"Waypoint Replaced\n\""));
+   }
+   else
+   {
+   VectorCopy( enemy->r.currentOrigin, self->WPA[self->TotalWP]);
+   self->inUse[self->TotalWP] = qfalse;
+   self->TotalWP++;
+   ;//trap_SendServerCommand( -1, va( "print \"Waypoint Stored\n\""));
+   }
+ }
+ else
+   ;//trap_SendServerCommand( -1, va( "print \"Unnessesary Waypoint, ignored\n\""));
+ }
+ else
+   ;//trap_SendServerCommand( -1, va( "print \"Out of Memory, ignored\n\""));
+   }
+     
+ ;//trap_SendServerCommand( -1, va( "print \"Launching the swarm!\n\""));
 
-      if( !G_Visible( self, enemy ) )
-        continue;
-
-      if( enemy->client && enemy->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
-      {
         self->active = qtrue;
         self->target_ent = enemy;
         self->timestamp = level.time + HIVE_REPEAT;
-
-        VectorSubtract( enemy->s.pos.trBase, self->s.pos.trBase, dirToTarget );
+ if (self->targWP == -1)
+   VectorSubtract( enemy->s.pos.trBase, self->s.pos.trBase, dirToTarget );
+ else
+   VectorSubtract( self->WPA[self->targWP], self->s.pos.trBase, dirToTarget );
+
         VectorNormalize( dirToTarget );
         vectoangles( dirToTarget, self->turretAim );
 
@@ -1172,7 +1302,7 @@
         FireWeapon( self );
         G_SetBuildableAnim( self, BANIM_ATTACK1, qfalse );
         return;
-      }
+     
     }
   }
 
Index: src/game/g_local.h
===================================================================
--- src/game/g_local.h (revision 87)
+++ src/game/g_local.h (working copy)
@@ -242,6 +242,15 @@
   int               lastDamageTime;
   
   int               bdnumb; // buildlog entry ID

+    #define MAX_WPA 31
+ #define HIVE_RECHECK 30000
+  vec3_t WPA[ MAX_WPA + 1 ];
+  vec3_t WPA2[ MAX_WPA + 1 ];
+  qboolean inUse[ MAX_WPA + 1];
+  int TotalWP;
+  int targWP;
+  int RecheckTime;
 };
 
 typedef enum
Index: src/game/g_missile.c
===================================================================
--- src/game/g_missile.c (revision 87)
+++ src/game/g_missile.c (working copy)
@@ -582,34 +582,127 @@
 */
 void AHive_SearchAndDestroy( gentity_t *self )
 {
+
   vec3_t dir;
-  trace_t tr;
-
+  trace_t tr, tr2, tr3;
+  vec3_t Torigin;
+  gentity_t *traceEnt;

+ if (self->TotalWP == 0 )
+ {
+ self->TotalWP++;
+ VectorCopy(self->target_ent->r.currentOrigin, self->WPA[ 0 ]);
+ VectorCopy(self->target_ent->r.currentOrigin, self->WPA[ self->TotalWP ]);
+ }
   trap_Trace( &tr, self->r.currentOrigin, self->r.mins, self->r.maxs,
               self->target_ent->r.currentOrigin, self->r.ownerNum, self->clipmask );
+  traceEnt = &g_entities[ tr.entityNum ];
 
   //if there is no LOS or the parent hive is too far away or the target is dead or notargeting, return
-  if( tr.entityNum == ENTITYNUM_WORLD ||
-      Distance( self->r.currentOrigin, self->parent->r.currentOrigin ) > ( HIVE_RANGE * 5 ) ||
+  if( Distance( self->r.currentOrigin, self->parent->r.currentOrigin ) > ( HIVE_RANGE * 30 ) ||
       self->target_ent->health <= 0 || self->target_ent->flags & FL_NOTARGET )
   {
     self->r.ownerNum = ENTITYNUM_WORLD;
 
     self->think = AHive_ReturnToHive;
     self->nextthink = level.time + FRAMETIME;
+ return;
   }
   else
   {
-    VectorSubtract( self->target_ent->r.currentOrigin, self->r.currentOrigin, dir );
+ if ( tr.entityNum == ENTITYNUM_WORLD || traceEnt->s.eType == ET_BUILDABLE)
+ {
+ trap_Trace( &tr2, self->WPA[ self->TotalWP - 1 ], self->r.mins, self->r.maxs,
+ self->target_ent->r.currentOrigin, self->r.ownerNum, self->clipmask );
+     traceEnt = &g_entities[ tr2.entityNum ];
+ if ( tr2.entityNum == ENTITYNUM_WORLD || traceEnt->s.eType == ET_BUILDABLE )
+ {
+ trap_Trace( &tr3, self->WPA[ self->TotalWP ], self->r.mins, self->r.maxs,
+ self->target_ent->r.currentOrigin, self->r.ownerNum, self->clipmask ); // if the player turned around another corner while we were thinking, drop the target.
+   traceEnt = &g_entities[ tr3.entityNum ];
+ if ( tr3.entityNum == ENTITYNUM_WORLD || traceEnt->s.eType == ET_BUILDABLE )
+ {
+ self->r.ownerNum = ENTITYNUM_WORLD;
+
+ self->think = AHive_ReturnToHive;
+ self->nextthink = level.time + FRAMETIME;
+ //;//trap_SendServerCommand( -1, va( "print \"Lost Target\n\""));
+ return; // lost the track, get back home
+ }
+ else
+ {
+ if (self->TotalWP < MAX_WPA)
+ {
+ self->TotalWP++;
+ //;//trap_SendServerCommand( -1, va( "print \"New Waypoint, %i\n\"", self->TotalWP - 1));
+ VectorCopy(self->target_ent->r.currentOrigin, self->WPA[ self->TotalWP ]);
+ }
+ else
+ {
+ self->r.ownerNum = ENTITYNUM_WORLD;
+
+ self->think = AHive_ReturnToHive;
+ self->nextthink = level.time + FRAMETIME;
+ //;//trap_SendServerCommand( -1, va( "print \"Out Of memory\n\""));
+ return; // out of memory, get back home
+ }
+ }
+ }
+ else
+ {
+ VectorCopy(self->target_ent->r.currentOrigin, self->WPA[ self->TotalWP ]); //update latest waypoint without creating a new one, if there is a LOS from the old one
+ }
+ }
+ else
+ {
+ int i;
+ if (self->TotalWP > 1)
+ {
+ self->TotalWP = 1;
+ //;//trap_SendServerCommand( -1, va( "print \"Direct Line of Sight\n\""));
+ }
+ VectorCopy(self->target_ent->r.currentOrigin, self->WPA[ 0 ]);
+ VectorCopy(self->target_ent->r.currentOrigin, self->WPA[ self->TotalWP ]);
+
+
+ }
+
+ if (Distance( self->r.currentOrigin, self->WPA[ 0 ]) < 64 && self->TotalWP > 1) // snap the swarm to the waypoint if it is close enough.
+ {
+ int i;
+ VectorCopy(self->WPA[ 0 ], self->r.currentOrigin);
+ for (i = 0; i <= MAX_WPA; i++)
+ {
+ VectorCopy(self->WPA[i+1], self->WPA[i]);
+ }
+ self->TotalWP--;
+ if (self->TotalWP < 1) self->TotalWP = 1;
+ VectorCopy(self->target_ent->r.currentOrigin, self->WPA[ self->TotalWP ]);
+ //;//trap_SendServerCommand( -1, va( "print \"Waypoint Reached\n\""));
+ }
+
+ trap_Trace( &tr, self->r.currentOrigin, self->r.mins, self->r.maxs,
+        self->WPA[ 0 ], self->r.ownerNum, self->clipmask );
+   traceEnt = &g_entities[ tr.entityNum ];
+ if ( tr.entityNum == ENTITYNUM_WORLD || traceEnt->s.eType == ET_BUILDABLE )  // check for doors closing
+ {
+
+     self->r.ownerNum = ENTITYNUM_WORLD;
+
+ self->think = AHive_ReturnToHive;
+ self->nextthink = level.time + FRAMETIME;
+ //;//trap_SendServerCommand( -1, va( "print \"Invalid Waypoint\n\""));
+ return;
+ }
+
+ VectorSubtract( self->WPA[ 0 ], self->r.currentOrigin, dir );
     VectorNormalize( dir );
-
     //change direction towards the player
     VectorScale( dir, HIVE_SPEED, self->s.pos.trDelta );
     SnapVector( self->s.pos.trDelta );      // save net bandwidth
     VectorCopy( self->r.currentOrigin, self->s.pos.trBase );
     self->s.pos.trTime = level.time;
-
-    self->nextthink = level.time + HIVE_DIR_CHANGE_PERIOD;
+    self->nextthink = level.time + HIVE_DIR_CHANGE_PERIOD/2;
   }
 }
 
@@ -641,7 +734,29 @@
   bolt->methodOfDeath = MOD_SWARM;
   bolt->clipmask = MASK_SHOT;
   bolt->target_ent = self->target_ent;
-
+  bolt->TotalWP = 0;

+  if(self->targWP != -1)
+  {
+    if(self->targWP >= 0)
+    {
+ bolt->TotalWP++;
+ VectorCopy(self->WPA[self->targWP], bolt->WPA[ 0 ]);
+ VectorCopy(self->WPA[self->targWP], bolt->WPA[ bolt->TotalWP ]);
+     ;//trap_SendServerCommand( -1, va( "print \"Swarm : Waypoint Received, proceeding to target\n\""));
+ }
+ else
+ {
+ int TW;
+ TW = abs(self->targWP) - 2;
+ bolt->TotalWP += 2;
+ VectorCopy(self->WPA[TW], bolt->WPA[ 0 ]);
+ VectorCopy(self->WPA2[TW], bolt->WPA[ 1 ]);
+ VectorCopy(self->WPA2[TW], bolt->WPA[ bolt->TotalWP ]);
+     ;//trap_SendServerCommand( -1, va( "print \"Swarm : 2 Waypoints received, proceeding to target\n\""));
+ }
+  }

   bolt->s.pos.trType = TR_LINEAR;
   bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME;   // move a bit on the very first frame
   VectorCopy( start, bolt->s.pos.trBase );




Edit : pwef! added even more complicated algorythm, since the first one did not solve the problem for all cases that could happen. Not the best way to implement, but it is quite effective.