Index: src/qcommon/q_shared.h
===================================================================
--- src/qcommon/q_shared.h	(revision 1044)
+++ src/qcommon/q_shared.h	(working copy)
@@ -935,6 +935,7 @@
 // if none of the catchers are active, bound key strings will be executed
 #define KEYCATCH_CONSOLE		0x0001
 #define	KEYCATCH_UI					0x0002
+#define	KEYCATCH_MESSAGE		0x0004
 #define	KEYCATCH_CGAME			0x0008
 
 
@@ -1084,9 +1085,8 @@
 
 	int			stats[MAX_STATS];
 	int			persistant[MAX_PERSISTANT];	// stats that aren't cleared on death
-	int			misc[MAX_MISC];	// misc data
-	int			ammo;			// ammo held
-	int			clips;			// clips held
+	int			misc[MAX_MISC];	// level.time that the powerup runs out
+	int			ammo[MAX_WEAPONS];
 
 	int			generic1;
 	int			loopSound;
@@ -1275,9 +1275,9 @@
 
 // server browser sources
 // AS_MPLAYER is no longer used
-#define AS_GLOBAL			0
+#define AS_GLOBAL			2
 #define AS_MPLAYER		1
-#define AS_LOCAL			2
+#define AS_LOCAL			0
 #define AS_FAVORITES	3
 
 
Index: src/qcommon/qcommon.h
===================================================================
--- src/qcommon/qcommon.h	(revision 1044)
+++ src/qcommon/qcommon.h	(working copy)
@@ -221,7 +221,7 @@
 ==============================================================
 */
 
-#define	PROTOCOL_VERSION	70
+#define	PROTOCOL_VERSION	69
 
 // maintain a list of compatible protocols for demo playing
 // NOTE: that stuff only works with two digits protocols
Index: src/qcommon/msg.c
===================================================================
--- src/qcommon/msg.c	(revision 1044)
+++ src/qcommon/msg.c	(working copy)
@@ -827,7 +827,7 @@
 { NETF(modelindex), 8 },
 { NETF(otherEntityNum2), GENTITYNUM_BITS },
 { NETF(loopSound), 8 },
-{ NETF(generic1), 16 },
+{ NETF(generic1), 8 },
 { NETF(origin2[2]), 0 },
 { NETF(origin2[0]), 0 },
 { NETF(origin2[1]), 0 },
@@ -1143,9 +1143,7 @@
 { PSF(damageYaw), 8 },
 { PSF(damagePitch), 8 },
 { PSF(damageCount), 8 },
-{ PSF(ammo), 12 },
-{ PSF(clips), 4 },
-{ PSF(generic1), 16 },
+{ PSF(generic1), 8 },
 { PSF(pm_type), 8 },					
 { PSF(delta_angles[0]), 16 },
 { PSF(delta_angles[2]), 16 },
@@ -1173,6 +1171,7 @@
 	playerState_t	dummy;
 	int				statsbits;
 	int				persistantbits;
+	int				ammobits;
 	int				miscbits;
 	int				numFields;
 	int				c;
@@ -1253,6 +1252,12 @@
 			persistantbits |= 1<<i;
 		}
 	}
+	ammobits = 0;
+	for (i=0 ; i<MAX_WEAPONS ; i++) {
+		if (to->ammo[i] != from->ammo[i]) {
+			ammobits |= 1<<i;
+		}
+	}
 	miscbits = 0;
 	for (i=0 ; i<MAX_MISC ; i++) {
 		if (to->misc[i] != from->misc[i]) {
@@ -1260,7 +1265,7 @@
 		}
 	}
 
-	if (!statsbits && !persistantbits && !miscbits) {
+	if (!statsbits && !persistantbits && !ammobits && !miscbits) {
 		MSG_WriteBits( msg, 0, 1 );	// no change
 		oldsize += 4;
 		return;
@@ -1289,6 +1294,17 @@
 	}
 
 
+	if ( ammobits ) {
+		MSG_WriteBits( msg, 1, 1 );	// changed
+		MSG_WriteBits( msg, ammobits, MAX_WEAPONS );
+		for (i=0 ; i<MAX_WEAPONS ; i++)
+			if (ammobits & (1<<i) )
+				MSG_WriteShort (msg, to->ammo[i]);
+	} else {
+		MSG_WriteBits( msg, 0, 1 );	// no change
+	}
+
+
 	if ( miscbits ) {
 		MSG_WriteBits( msg, 1, 1 );	// changed
 		MSG_WriteBits( msg, miscbits, MAX_MISC );
@@ -1408,8 +1424,19 @@
 			}
 		}
 
-		// parse misc data
+		// parse ammo
 		if ( MSG_ReadBits( msg, 1 ) ) {
+			LOG("PS_AMMO");
+			bits = MSG_ReadBits (msg, MAX_WEAPONS);
+			for (i=0 ; i<MAX_WEAPONS ; i++) {
+				if (bits & (1<<i) ) {
+					to->ammo[i] = MSG_ReadShort(msg);
+				}
+			}
+		}
+
+		// parse misc
+		if ( MSG_ReadBits( msg, 1 ) ) {
 			LOG("PS_MISC");
 			bits = MSG_ReadBits (msg, MAX_MISC);
 			for (i=0 ; i<MAX_MISC ; i++) {
Index: src/qcommon/common.c
===================================================================
--- src/qcommon/common.c	(revision 1044)
+++ src/qcommon/common.c	(working copy)
@@ -33,7 +33,7 @@
 #endif
 
 int demo_protocols[] =
-{ PROTOCOL_VERSION, 0 };
+{ 66, 67, 68, 69, 0 };
 
 #define MAX_NUM_ARGVS	50
 
Index: src/game/g_syscalls.asm
===================================================================
--- src/game/g_syscalls.asm	(revision 1044)
+++ src/game/g_syscalls.asm	(working copy)
@@ -34,24 +34,21 @@
 equ trap_UnlinkEntity               -32
 equ trap_EntitiesInBox              -33
 equ trap_EntityContact              -34
-equ trap_GetUsercmd                 -35
-equ trap_GetEntityToken             -36
-equ trap_FS_GetFileList             -37
-equ trap_RealTime                   -38
-equ trap_SnapVector                 -39
-equ trap_TraceCapsule               -40
-equ trap_EntityContactCapsule       -41
-equ trap_FS_Seek                    -42
+equ trap_BotAllocateClient          -35
+equ trap_BotFreeClient              -36
+equ trap_GetUsercmd                 -37
+equ trap_GetEntityToken             -38
+equ trap_FS_GetFileList             -39
+equ trap_DebugPolygonCreate         -40
+equ trap_DebugPolygonDelete         -41
+equ trap_RealTime                   -42
+equ trap_SnapVector                 -43
+equ trap_TraceCapsule               -44
+equ trap_EntityContactCapsule       -45
+equ trap_FS_Seek                    -46
+equ trap_SendGameStat               -47
 
-equ trap_Parse_AddGlobalDefine      -43
-equ trap_Parse_LoadSource           -44
-equ trap_Parse_FreeSource           -45
-equ trap_Parse_ReadToken            -46
-equ trap_Parse_SourceFileAndLine    -47
 
-equ trap_SendGameStat               -48
-
-
 equ memset                          -101
 equ memcpy                          -102
 equ strncpy                         -103
Index: src/game/bg_misc.c
===================================================================
--- src/game/bg_misc.c	(revision 1044)
+++ src/game/bg_misc.c	(working copy)
@@ -5126,16 +5126,62 @@
 
 /*
 ========================
+BG_UnpackAmmoArray
+
+Extract the ammo quantity from the array
+========================
+*/
+void BG_UnpackAmmoArray( int weapon, int psAmmo[ ], int psAmmo2[ ], int *ammo, int *clips )
+{
+  int   ammoarray[ 32 ];
+  int   i;
+
+  for( i = 0; i <= 15; i++ )
+    ammoarray[ i ] = psAmmo[ i ];
+
+  for( i = 16; i <= 31; i++ )
+    ammoarray[ i ] = psAmmo2[ i - 16 ];
+
+  if( ammo != NULL )
+    *ammo = ammoarray[ weapon ] & 0x0FFF;
+
+  if( clips != NULL )
+    *clips = ( ammoarray[ weapon ] >> 12 ) & 0x0F;
+}
+
+/*
+========================
+BG_PackAmmoArray
+
+Pack the ammo quantity into the array
+========================
+*/
+void BG_PackAmmoArray( int weapon, int psAmmo[ ], int psAmmo2[ ], int ammo, int clips )
+{
+  int   weaponvalue;
+
+  weaponvalue = ammo | ( clips << 12 );
+
+  if( weapon <= 15 )
+    psAmmo[ weapon ] = weaponvalue;
+  else if( weapon >= 16 )
+    psAmmo2[ weapon - 16 ] = weaponvalue;
+}
+
+/*
+========================
 BG_WeaponIsFull
 
 Check if a weapon has full ammo
 ========================
 */
-qboolean BG_WeaponIsFull( weapon_t weapon, int stats[ ], int ammo, int clips )
+qboolean BG_WeaponIsFull( weapon_t weapon, int stats[ ], int psAmmo[ ], int psAmmo2[ ] )
 {
   int maxAmmo, maxClips;
+  int ammo, clips;
 
   BG_FindAmmoForWeapon( weapon, &maxAmmo, &maxClips );
+  BG_UnpackAmmoArray( weapon, psAmmo, psAmmo2, &ammo, &clips );
 
   if( BG_InventoryContainsUpgrade( UP_BATTPACK, stats ) )
     maxAmmo = (int)( (float)maxAmmo * BATTPACK_MODIFIER );
Index: src/game/g_active.c
===================================================================
--- src/game/g_active.c	(revision 1044)
+++ src/game/g_active.c	(working copy)
@@ -516,7 +516,6 @@
   qboolean  walking = qfalse, stopped = qfalse,
             crouched = qfalse, jumping = qfalse,
             strafing = qfalse;
-  int       i;
 
   ucmd = &ent->client->pers.cmd;
 
@@ -665,14 +664,18 @@
     //client is charging up an lcannon
     if( client->ps.weapon == WP_LUCIFER_CANNON )
     {
+      int ammo;
+
+      BG_UnpackAmmoArray( WP_LUCIFER_CANNON, client->ps.ammo, client->ps.misc, &ammo, NULL );
+
       if( client->ps.stats[ STAT_MISC ] < LCANNON_TOTAL_CHARGE && ucmd->buttons & BUTTON_ATTACK )
         client->ps.stats[ STAT_MISC ] += ( 100.0f / LCANNON_CHARGE_TIME ) * LCANNON_TOTAL_CHARGE;
 
       if( client->ps.stats[ STAT_MISC ] > LCANNON_TOTAL_CHARGE )
         client->ps.stats[ STAT_MISC ] = LCANNON_TOTAL_CHARGE;
 
-      if( client->ps.stats[ STAT_MISC ] > ( client->ps.ammo * LCANNON_TOTAL_CHARGE ) / 10 )
-        client->ps.stats[ STAT_MISC ] = client->ps.ammo * LCANNON_TOTAL_CHARGE / 10;
+      if( client->ps.stats[ STAT_MISC ] > ( ammo * LCANNON_TOTAL_CHARGE ) / 10 )
+        client->ps.stats[ STAT_MISC ] = ammo * LCANNON_TOTAL_CHARGE / 10;
     }
 
     switch( client->ps.weapon )
@@ -692,21 +695,7 @@
             client->ps.stats[ STAT_BUILDABLE ] |= SB_VALID_TOGGLEBIT;
           else
             client->ps.stats[ STAT_BUILDABLE ] &= ~SB_VALID_TOGGLEBIT;
-
-          // Let the client know which buildables will be removed by building
-          for( i = 0; i < MAX_MISC; i++ )
-          {
-            if( i < level.numBuildablesForRemoval )
-              client->ps.misc[ i ] = level.markedBuildables[ i ]->s.number;
-            else
-              client->ps.misc[ i ] = 0;
-          }
         }
-        else
-        {
-          for( i = 0; i < MAX_MISC; i++ )
-            client->ps.misc[ i ] = 0;
-        }
 
         //update build timer
         if( client->ps.stats[ STAT_MISC ] > 0 )
@@ -851,12 +840,16 @@
 
     if( client->ps.weapon == WP_ALEVEL3_UPG )
     {
-      int maxAmmo;
+      int ammo, maxAmmo;
 
       BG_FindAmmoForWeapon( WP_ALEVEL3_UPG, &maxAmmo, NULL );
+      BG_UnpackAmmoArray( WP_ALEVEL3_UPG, client->ps.ammo, client->ps.misc, &ammo, NULL );
 
-      if( client->ps.ammo < maxAmmo )
-        client->ps.ammo++;
+      if( ammo < maxAmmo )
+      {
+        ammo++;
+        BG_PackAmmoArray( WP_ALEVEL3_UPG, client->ps.ammo, client->ps.misc, ammo, 0 );
+      }
     }
   }
 }
Index: src/game/g_public.h
===================================================================
--- src/game/g_public.h	(revision 1044)
+++ src/game/g_public.h	(working copy)
@@ -23,7 +23,7 @@
 
 // g_public.h -- game module information visible to server
 
-#define GAME_API_VERSION  9
+#define GAME_API_VERSION  8
 
 // entity->svFlags
 // the server does not know how to interpret most of the values
@@ -197,7 +197,7 @@
   G_ENTITY_CONTACT, // ( const vec3_t mins, const vec3_t maxs, const gentity_t *ent );
   // perform an exact check against inline brush models of non-square shape
 
-  G_GET_USERCMD,  // ( int clientNum, usercmd_t *cmd )
+  G_GET_USERCMD=36,  // ( int clientNum, usercmd_t *cmd )
 
   G_GET_ENTITY_TOKEN, // qboolean ( char *buffer, int bufferSize )
   // Retrieves the next string token from the entity spawn text, returning
@@ -205,7 +205,7 @@
   // This should only be done at GAME_INIT time.
 
   G_FS_GETFILELIST,
-  G_REAL_TIME,
+  G_REAL_TIME=41,
   G_SNAPVECTOR,
 
   G_TRACECAPSULE, // ( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask );
@@ -214,13 +214,13 @@
   // 1.32
   G_FS_SEEK,
 
+  G_SEND_GAMESTAT,
+
   G_PARSE_ADD_GLOBAL_DEFINE,
   G_PARSE_LOAD_SOURCE,
   G_PARSE_FREE_SOURCE,
   G_PARSE_READ_TOKEN,
-  G_PARSE_SOURCE_FILE_AND_LINE,
-
-  G_SEND_GAMESTAT
+  G_PARSE_SOURCE_FILE_AND_LINE
 } gameImport_t;
 
 
Index: src/game/bg_pmove.c
===================================================================
--- src/game/bg_pmove.c	(revision 1044)
+++ src/game/bg_pmove.c	(working copy)
@@ -2659,7 +2659,7 @@
 static void PM_Weapon( void )
 {
   int           addTime = 200; //default addTime - should never be used
-  int           maxClips;
+  int           ammo, clips, maxClips;
   qboolean      attack1 = qfalse;
   qboolean      attack2 = qfalse;
   qboolean      attack3 = qfalse;
@@ -2757,10 +2757,11 @@
 
   // start the animation even if out of ammo
 
+  BG_UnpackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->misc, &ammo, &clips );
   BG_FindAmmoForWeapon( pm->ps->weapon, NULL, &maxClips );
 
   // check for out of ammo
-  if( !pm->ps->ammo && !pm->ps->clips && !BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) )
+  if( !ammo && !clips && !BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) )
   {
     PM_AddEvent( EV_NOAMMO );
     pm->ps->weaponTime += 200;
@@ -2776,14 +2777,16 @@
   {
     if( maxClips > 0 )
     {
-      pm->ps->clips--;
-      BG_FindAmmoForWeapon( pm->ps->weapon, &pm->ps->ammo, NULL );
+      clips--;
+      BG_FindAmmoForWeapon( pm->ps->weapon, &ammo, NULL );
     }
 
     if( BG_FindUsesEnergyForWeapon( pm->ps->weapon ) &&
         BG_InventoryContainsUpgrade( UP_BATTPACK, pm->ps->stats ) )
-      pm->ps->ammo = (int)( (float)pm->ps->ammo * BATTPACK_MODIFIER );
+      ammo = (int)( (float)ammo * BATTPACK_MODIFIER );
 
+    BG_PackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->misc, ammo, clips );
+
     //allow some time for the weapon to be raised
     pm->ps->weaponstate = WEAPON_RAISING;
     PM_StartTorsoAnim( TORSO_RAISE );
@@ -2792,7 +2795,7 @@
   }
 
   // check for end of clip
-  if( ( !pm->ps->ammo || pm->ps->pm_flags & PMF_WEAPON_RELOAD ) && pm->ps->clips )
+  if( ( !ammo || pm->ps->pm_flags & PMF_WEAPON_RELOAD ) && clips )
   {
     pm->ps->pm_flags &= ~PMF_WEAPON_RELOAD;
 
@@ -2911,7 +2914,7 @@
     if( BG_WeaponHasThirdMode( pm->ps->weapon ) )
     {
       //hacky special case for slowblob
-      if( pm->ps->weapon == WP_ALEVEL3_UPG && !pm->ps->ammo )
+      if( pm->ps->weapon == WP_ALEVEL3_UPG && !ammo )
       {
         PM_AddEvent( EV_NOAMMO );
         pm->ps->weaponTime += 200;
@@ -3030,22 +3033,25 @@
   // take an ammo away if not infinite
   if( !BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) )
   {
-    //special case for lcannon
+    //special case for lCanon
     if( pm->ps->weapon == WP_LUCIFER_CANNON && attack1 && !attack2 )
     {
-      pm->ps->ammo -= (int)( ceil( ( (float)pm->ps->stats[ STAT_MISC ] / (float)LCANNON_TOTAL_CHARGE ) * 10.0f ) );
+      ammo -= (int)( ceil( ( (float)pm->ps->stats[ STAT_MISC ] / (float)LCANNON_TOTAL_CHARGE ) * 10.0f ) );
 
       //stay on the safe side
-      if( pm->ps->ammo < 0 )
-        pm->ps->ammo = 0;
+      if( ammo < 0 )
+        ammo = 0;
     }
     else
-      pm->ps->ammo--;
+      ammo--;
+
+    BG_PackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->misc, ammo, clips );
   }
   else if( pm->ps->weapon == WP_ALEVEL3_UPG && attack3 )
   {
     //special case for slowblob
-    pm->ps->ammo--;
+    ammo--;
+    BG_PackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->misc, ammo, clips );
   }
 
   //FIXME: predicted angles miss a problem??
@@ -3247,8 +3253,12 @@
 
 void PmoveSingle( pmove_t *pmove )
 {
+  int ammo, clips;
+
   pm = pmove;
 
+  BG_UnpackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->misc, &ammo, &clips );
+
   // this counter lets us debug movement problems with a journal
   // by setting a conditional breakpoint fot the previous frame
   c_pmove++;
@@ -3275,7 +3285,7 @@
   // set the firing flag for continuous beam weapons
   if( !(pm->ps->pm_flags & PMF_RESPAWNED) && pm->ps->pm_type != PM_INTERMISSION &&
       ( pm->cmd.buttons & BUTTON_ATTACK ) &&
-      ( ( pm->ps->ammo > 0 || pm->ps->clips > 0 ) || BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) ) )
+      ( ( ammo > 0 || clips > 0 ) || BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) ) )
     pm->ps->eFlags |= EF_FIRING;
   else
     pm->ps->eFlags &= ~EF_FIRING;
@@ -3283,7 +3293,7 @@
   // set the firing flag for continuous beam weapons
   if( !(pm->ps->pm_flags & PMF_RESPAWNED) && pm->ps->pm_type != PM_INTERMISSION &&
       ( pm->cmd.buttons & BUTTON_ATTACK2 ) &&
-      ( ( pm->ps->ammo > 0 || pm->ps->clips > 0 ) || BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) ) )
+      ( ( ammo > 0 || clips > 0 ) || BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) ) )
     pm->ps->eFlags |= EF_FIRING2;
   else
     pm->ps->eFlags &= ~EF_FIRING2;
@@ -3291,7 +3301,7 @@
   // set the firing flag for continuous beam weapons
   if( !(pm->ps->pm_flags & PMF_RESPAWNED) && pm->ps->pm_type != PM_INTERMISSION &&
       ( pm->cmd.buttons & BUTTON_USE_HOLDABLE ) &&
-      ( ( pm->ps->ammo > 0 || pm->ps->clips > 0 ) || BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) ) )
+      ( ( ammo > 0 || clips > 0 ) || BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) ) )
     pm->ps->eFlags |= EF_FIRING3;
   else
     pm->ps->eFlags &= ~EF_FIRING3;
Index: src/game/g_weapon.c
===================================================================
--- src/game/g_weapon.c	(revision 1044)
+++ src/game/g_weapon.c	(working copy)
@@ -93,7 +93,7 @@
     if( BG_InventoryContainsWeapon( i, ent->client->ps.stats ) &&
         weaponType && !BG_FindInfinteAmmoForWeapon( i ) &&
         !BG_WeaponIsFull( i, ent->client->ps.stats,
-          ent->client->ps.ammo, ent->client->ps.clips ) )
+          ent->client->ps.ammo, ent->client->ps.misc ) )
     {
       BG_FindAmmoForWeapon( i, &maxAmmo, &maxClips );
 
@@ -105,8 +105,8 @@
           maxAmmo = (int)( (float)maxAmmo * BATTPACK_MODIFIER );
       }
 
-      ent->client->ps.ammo = maxAmmo;
-      ent->client->ps.clips = maxClips;
+      BG_PackAmmoArray( i, ent->client->ps.ammo, ent->client->ps.misc,
+                        maxAmmo, maxClips );
 
       restoredAmmo = qtrue;
     }
Index: src/game/g_trigger.c
===================================================================
--- src/game/g_trigger.c	(revision 1044)
+++ src/game/g_trigger.c	(working copy)
@@ -1073,7 +1073,7 @@
 */
 void trigger_ammo_touch( gentity_t *self, gentity_t *other, trace_t *trace )
 {
-  int maxClips, maxAmmo;
+  int ammo, clips, maxClips, maxAmmo;
 
   if( !other->client )
     return;
@@ -1099,19 +1099,24 @@
     self->timestamp = level.time + FRAMETIME;
 
   BG_FindAmmoForWeapon( other->client->ps.weapon, &maxAmmo, &maxClips );
+  BG_UnpackAmmoArray( other->client->ps.weapon, other->client->ps.ammo, other->client->ps.misc,
+                      &ammo, &clips );
 
-  if( ( other->client->ps.ammo + self->damage ) > maxAmmo )
+  if( ( ammo + self->damage ) > maxAmmo )
   {
-    if( other->client->ps.clips < maxClips )
+    if( clips < maxClips )
     {
-      other->client->ps.clips++;
-      other->client->ps.ammo = 1;
+      clips++;
+      ammo = 1;
     }
     else
-      other->client->ps.ammo = maxAmmo;
+      ammo = maxAmmo;
   }
   else
-    other->client->ps.ammo += self->damage;
+    ammo += self->damage;
+
+  BG_PackAmmoArray( other->client->ps.weapon, other->client->ps.ammo, other->client->ps.misc,
+                    ammo, clips );
 }
 
 /*
Index: src/game/g_client.c
===================================================================
--- src/game/g_client.c	(revision 1044)
+++ src/game/g_client.c	(working copy)
@@ -1478,8 +1478,7 @@
 
   BG_FindAmmoForWeapon( weapon, &maxAmmo, &maxClips );
   BG_AddWeaponToInventory( weapon, client->ps.stats );
-  client->ps.ammo = maxAmmo;
-  client->ps.clips = maxClips;
+  BG_PackAmmoArray( weapon, client->ps.ammo, client->ps.misc, maxAmmo, maxClips );
 
   ent->client->ps.stats[ STAT_PCLASS ] = ent->client->pers.classSelection;
   ent->client->ps.stats[ STAT_PTEAM ] = ent->client->pers.teamSelection;
Index: src/game/bg_public.h
===================================================================
--- src/game/bg_public.h	(revision 1044)
+++ src/game/bg_public.h	(working copy)
@@ -216,6 +216,7 @@
   STAT_STATE,     // client states e.g. wall climbing
   STAT_MISC,      // for uh...misc stuff
   STAT_BUILDABLE, // which ghost model to display for building
+  STAT_BOOSTTIME, //TA: time left for boost (alien only)
   STAT_FALLDIST,  // the distance the player fell
   STAT_VIEWLOCK   // direction to lock the view in
 } statIndex_t;
@@ -433,15 +434,15 @@
   BIT_NUM_TEAMS
 } buildableTeam_t;
 
-#define B_HEALTH_BITS       12
+
+#define B_HEALTH_BITS       5
 #define B_HEALTH_MASK       ((1<<B_HEALTH_BITS)-1)
 
-#define B_MARKED_TOGGLEBIT  0x00001000
-#define B_SPAWNED_TOGGLEBIT 0x00002000
-#define B_POWERED_TOGGLEBIT 0x00004000
-#define B_DCCED_TOGGLEBIT   0x00008000
+#define B_DCCED_TOGGLEBIT    0x00000000
+#define B_SPAWNED_TOGGLEBIT  0x00000020
+#define B_POWERED_TOGGLEBIT  0x00000040
+#define B_MARKED_TOGGLEBIT   0x00000080
 
-
 // reward sounds (stored in ps->persistant[PERS_PLAYEREVENTS])
 #define PLAYEREVENT_DENIEDREWARD      0x0001
 #define PLAYEREVENT_GAUNTLETREWARD    0x0002
@@ -564,8 +565,6 @@
   MN_TEAM,
   MN_A_TEAMFULL,
   MN_H_TEAMFULL,
-  MN_A_TEAMCHANGEBUILDTIMER,
-  MN_H_TEAMCHANGEBUILDTIMER,
 
   //alien stuff
   MN_A_CLASS,
@@ -576,7 +575,6 @@
   MN_A_NOEROOM,
   MN_A_TOOCLOSE,
   MN_A_NOOVMND_EVOLVE,
-  MN_A_EVOLVEBUILDTIMER,
 
   //alien build
   MN_A_SPWNWARN,
@@ -596,11 +594,6 @@
   MN_H_NOSLOTS,
   MN_H_NOFUNDS,
   MN_H_ITEMHELD,
-  MN_H_NOENERGYAMMOHERE,
-  MN_H_NOARMOURYHERE,
-  MN_H_NOROOMBSUITON,
-  MN_H_NOROOMBSUITOFF,
-  MN_H_ARMOURYBUILDTIMER,
 
   //human build
   MN_H_REPEATER,
@@ -1083,7 +1076,9 @@
   WUTeam_t  team;
 } upgradeAttributes_t;
 
-qboolean  BG_WeaponIsFull( weapon_t weapon, int stats[ ], int ammo, int clips );
+void      BG_UnpackAmmoArray( int weapon, int psAmmo[ ], int psAmmo2[ ], int *ammo, int *clips );
+void      BG_PackAmmoArray( int weapon, int psAmmo[ ], int psAmmo2[ ], int ammo, int clips );
+qboolean  BG_WeaponIsFull( weapon_t weapon, int stats[ ], int psAmmo[ ], int psAmmo2[ ] );
 void      BG_AddWeaponToInventory( int weapon, int stats[ ] );
 void      BG_RemoveWeaponFromInventory( int weapon, int stats[ ] );
 qboolean  BG_InventoryContainsWeapon( int weapon, int stats[ ] );
Index: src/game/g_cmds.c
===================================================================
--- src/game/g_cmds.c	(revision 1044)
+++ src/game/g_cmds.c	(working copy)
@@ -381,8 +381,7 @@
         BG_InventoryContainsUpgrade( UP_BATTPACK, client->ps.stats ) )
       maxAmmo = (int)( (float)maxAmmo * BATTPACK_MODIFIER );
 
-    client->ps.ammo = maxAmmo;
-    client->ps.clips = maxClips;
+    BG_PackAmmoArray( client->ps.weapon, client->ps.ammo, client->ps.misc, maxAmmo, maxClips );
   }
 }
 
@@ -748,10 +747,8 @@
        BG_InventoryContainsWeapon( WP_HBUILD2, ent->client->ps.stats ) ) &&
       ent->client->ps.stats[ STAT_MISC ] > 0 )
   {
-    if( ent->client->pers.teamSelection == PTE_ALIENS )
-      G_TriggerMenu( ent->client->ps.clientNum, MN_A_TEAMCHANGEBUILDTIMER );
-    else
-      G_TriggerMenu( ent->client->ps.clientNum, MN_H_TEAMCHANGEBUILDTIMER );
+    trap_SendServerCommand( ent-g_entities,
+        va( "print \"You cannot change teams until build timer expires\n\"" ) );
     return;
   }
 
@@ -1551,12 +1548,17 @@
   char      s[ MAX_TOKEN_CHARS ];
   int       clientNum;
   int       i;
+  trace_t   tr, tr2;
   vec3_t    infestOrigin;
   int       allowedClasses[ PCL_NUM_CLASSES ];
   int       numClasses = 0;
   pClass_t  currentClass = ent->client->ps.stats[ STAT_PCLASS ];
   pClass_t  newClass;
+
   int       numLevels;
+  vec3_t    fromMins, fromMaxs, toMins, toMaxs;
+  vec3_t    temp;
+
   int       entityList[ MAX_GENTITIES ];
   vec3_t    range = { AS_OVER_RT3, AS_OVER_RT3, AS_OVER_RT3 };
   vec3_t    mins, maxs;
@@ -1628,7 +1630,8 @@
             currentClass == PCL_ALIEN_BUILDER0_UPG ) &&
           ent->client->ps.stats[ STAT_MISC ] > 0 )
       {
-        G_TriggerMenu( ent->client->ps.clientNum, MN_A_EVOLVEBUILDTIMER );
+        trap_SendServerCommand( ent-g_entities,
+            va( "print \"You cannot evolve until build timer expires\n\"" ) );
         return;
       }
 
@@ -1636,7 +1639,31 @@
                                            newClass,
                                            (short)ent->client->ps.persistant[ PERS_CREDIT ], 0 );
 
-      if( G_RoomForClassChange( ent, newClass, infestOrigin ) )
+      BG_FindBBoxForClass( currentClass,
+                           fromMins, fromMaxs, NULL, NULL, NULL );
+      BG_FindBBoxForClass( newClass,
+                           toMins, toMaxs, NULL, NULL, NULL );
+
+      VectorCopy( ent->s.pos.trBase, infestOrigin );
+
+      infestOrigin[ 2 ] += ( fabs( toMins[ 2 ] ) - fabs( fromMins[ 2 ] ) ) + 1.0f;
+      VectorCopy( infestOrigin, temp );
+      /*`temp[ 2 ] += EVOLVE_TRACE_HEIGHT;`*/
+
+      //compute a place up in the air to start the real trace
+      trap_Trace( &tr, infestOrigin, toMins, toMaxs, temp, ent->s.number, MASK_SHOT );
+      VectorCopy( infestOrigin, temp );
+      /*`temp[ 2 ] += ( EVOLVE_TRACE_HEIGHT * tr.fraction ) - 1.0f;`*/
+
+      //trace down to the ground so that we can evolve on slopes
+      trap_Trace( &tr, temp, toMins, toMaxs, infestOrigin, ent->s.number, MASK_SHOT );
+      VectorCopy( tr.endpos, infestOrigin );
+
+      //make REALLY sure
+      trap_Trace( &tr2, ent->s.pos.trBase, NULL, NULL, infestOrigin, ent->s.number, MASK_SHOT );
+
+      //check there is room to evolve
+      if( !tr.startsolid && tr2.fraction == 1.0f )
       {
         //...check we can evolve to that class
         if( numLevels >= 0 &&
@@ -1988,7 +2015,8 @@
         !G_BuildableRange( ent->client->ps.origin, 100, BA_H_REPEATER ) &&
         !G_BuildableRange( ent->client->ps.origin, 100, BA_H_ARMOURY ) )
     {
-      G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOENERGYAMMOHERE );
+      trap_SendServerCommand( ent-g_entities, va(
+        "print \"You must be near a reactor, repeater or armoury\n\"" ) );
       return;
     }
   }
@@ -1997,7 +2025,7 @@
     //no armoury nearby
     if( !G_BuildableRange( ent->client->ps.origin, 100, BA_H_ARMOURY ) )
     {
-      G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOARMOURYHERE );
+      trap_SendServerCommand( ent-g_entities, va( "print \"You must be near a powered armoury\n\"" ) );
       return;
     }
   }
@@ -2054,8 +2082,8 @@
         BG_InventoryContainsUpgrade( UP_BATTPACK, ent->client->ps.stats ) )
       maxAmmo = (int)( (float)maxAmmo * BATTPACK_MODIFIER );
 
-    ent->client->ps.ammo = maxAmmo;
-    ent->client->ps.clips = maxClips;
+    BG_PackAmmoArray( weapon, ent->client->ps.ammo, ent->client->ps.misc,
+                      maxAmmo, maxClips );
 
     G_ForceWeaponChange( ent, weapon );
 
@@ -2117,11 +2145,11 @@
       {
         vec3_t newOrigin;
 
-        if( !G_RoomForClassChange( ent, PCL_HUMAN_BSUIT, newOrigin ) )
-        {
-          G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOROOMBSUITON );
-          return;
-        }
+        /*`if( !G_RoomForClassChange( ent, PCL_HUMAN_BSUIT, newOrigin ) )`*/
+        /*`{`*/
+          /*`G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOROOMBSUITON );`*/
+          /*`return;`*/
+        /*`}`*/
         VectorCopy( newOrigin, ent->s.pos.trBase );
         ent->client->ps.stats[ STAT_PCLASS ] = PCL_HUMAN_BSUIT;
         ent->client->ps.eFlags ^= EF_TELEPORT_BIT;
@@ -2163,7 +2191,7 @@
   //no armoury nearby
   if( !G_BuildableRange( ent->client->ps.origin, 100, BA_H_ARMOURY ) )
   {
-    G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOARMOURYHERE );
+    trap_SendServerCommand( ent-g_entities, va( "print \"You must be near a powered armoury\n\"" ) );
     return;
   }
 
@@ -2186,7 +2214,7 @@
       if( ( weapon == WP_HBUILD || weapon == WP_HBUILD2 ) &&
           ent->client->ps.stats[ STAT_MISC ] > 0 )
       {
-        G_TriggerMenu( ent->client->ps.clientNum, MN_H_ARMOURYBUILDTIMER );
+        trap_SendServerCommand( ent-g_entities, va( "print \"Cannot sell until build timer expires\n\"" ) );
         return;
       }
 
@@ -2211,22 +2239,6 @@
     //remove upgrade if carried
     if( BG_InventoryContainsUpgrade( upgrade, ent->client->ps.stats ) )
     {
-      // shouldn't really need to test for this, but just to be safe
-      if( upgrade == UP_BATTLESUIT )
-      {
-        vec3_t newOrigin;
-
-        if( !G_RoomForClassChange( ent, PCL_HUMAN, newOrigin ) )
-        {
-          G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOROOMBSUITOFF );
-          return;
-        }
-        VectorCopy( newOrigin, ent->s.pos.trBase );
-        ent->client->ps.stats[ STAT_PCLASS ] = PCL_HUMAN;
-        ent->client->ps.eFlags ^= EF_TELEPORT_BIT;
-      }
-
-      //add to inventory
       BG_RemoveUpgradeFromInventory( upgrade, ent->client->ps.stats );
 
       if( upgrade == UP_BATTPACK )
@@ -2244,7 +2256,7 @@
       if( ( i == WP_HBUILD || i == WP_HBUILD2 ) &&
           ent->client->ps.stats[ STAT_MISC ] > 0 )
       {
-        G_TriggerMenu( ent->client->ps.clientNum, MN_H_ARMOURYBUILDTIMER );
+        trap_SendServerCommand( ent-g_entities, va( "print \"Cannot sell until build timer expires\n\"" ) );
         continue;
       }
 
@@ -2270,21 +2282,6 @@
       if( BG_InventoryContainsUpgrade( i, ent->client->ps.stats ) &&
           BG_FindPurchasableForUpgrade( i ) )
       {
-
-        // shouldn't really need to test for this, but just to be safe
-        if( i == UP_BATTLESUIT )
-        {
-          vec3_t newOrigin;
-
-          if( !G_RoomForClassChange( ent, PCL_HUMAN, newOrigin ) )
-          {
-            G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOROOMBSUITOFF );
-            continue;
-          }
-          VectorCopy( newOrigin, ent->s.pos.trBase );
-          ent->client->ps.stats[ STAT_PCLASS ] = PCL_HUMAN;
-        }
-
         BG_RemoveUpgradeFromInventory( i, ent->client->ps.stats );
 
         if( i == UP_BATTPACK )
@@ -2298,8 +2295,7 @@
                 BG_FindUsesEnergyForWeapon( j ) &&
                 !BG_FindInfinteAmmoForWeapon( j ) )
             {
-              ent->client->ps.ammo = 0;
-              ent->client->ps.clips = 0;
+              BG_PackAmmoArray( j, ent->client->ps.ammo, ent->client->ps.misc, 0, 0 );
             }
           }
         }
Index: src/cgame/cg_predict.c
===================================================================
--- src/cgame/cg_predict.c	(revision 1044)
+++ src/cgame/cg_predict.c	(working copy)
@@ -507,6 +507,12 @@
       return 16;
   }
 
+  for( i = 0; i < MAX_WEAPONS; i++ )
+  {
+    if( pps->ammo[ i ] != ps->ammo[ i ] )
+      return 18;
+  }
+
   if( pps->generic1 != ps->generic1 ||
     pps->loopSound != ps->loopSound )
   {
Index: src/cgame/cg_syscalls.asm
===================================================================
--- src/cgame/cg_syscalls.asm	(revision 1044)
+++ src/cgame/cg_syscalls.asm	(working copy)
@@ -64,43 +64,42 @@
 equ trap_Key_GetCatcher               -62
 equ trap_Key_SetCatcher               -63
 equ trap_Key_GetKey                   -64
-equ trap_S_StopBackgroundTrack        -65
-equ trap_RealTime                     -66
-equ trap_SnapVector                   -67
-equ trap_RemoveCommand                -68
-equ trap_R_LightForPoint              -69
-equ trap_CIN_PlayCinematic            -70
-equ trap_CIN_StopCinematic            -71
-equ trap_CIN_RunCinematic             -72
-equ trap_CIN_DrawCinematic            -73
-equ trap_CIN_SetExtents               -74
-equ trap_R_RemapShader                -75
-equ trap_S_AddRealLoopingSound        -76
-equ trap_S_StopLoopingSound           -77
-equ trap_CM_TempCapsuleModel          -78
-equ trap_CM_CapsuleTrace              -79
-equ trap_CM_TransformedCapsuleTrace   -80
-equ trap_R_AddAdditiveLightToScene    -81
-equ trap_GetEntityToken               -82
-equ trap_R_AddPolysToScene            -83
-equ trap_R_inPVS                      -84
-equ trap_FS_Seek                      -85
-equ trap_FS_GetFileList               -86
-equ trap_LiteralArgs                  -87
-equ trap_CM_BiSphereTrace             -88
-equ trap_CM_TransformedBiSphereTrace  -89
-equ trap_GetDemoState                 -90
-equ trap_GetDemoPos                   -91
-equ trap_GetDemoName                  -92
-equ trap_Key_KeynumToStringBuf        -93
-equ trap_Key_GetBindingBuf            -94
-equ trap_Key_SetBinding               -95
-
-equ trap_Parse_AddGlobalDefine        -96
-equ trap_Parse_LoadSource             -97
-equ trap_Parse_FreeSource             -98
-equ trap_Parse_ReadToken              -99
-equ trap_Parse_SourceFileAndLine      -100
+equ trap_Parse_AddGlobalDefine        -65
+equ trap_Parse_LoadSource             -66
+equ trap_Parse_FreeSource             -67
+equ trap_Parse_ReadToken              -68
+equ trap_Parse_SourceFileAndLine      -69
+equ trap_S_StopBackgroundTrack        -70
+equ trap_RealTime                     -71
+equ trap_SnapVector                   -72
+equ trap_RemoveCommand                -73
+equ trap_R_LightForPoint              -74
+equ trap_CIN_PlayCinematic            -75
+equ trap_CIN_StopCinematic            -76
+equ trap_CIN_RunCinematic             -77
+equ trap_CIN_DrawCinematic            -78
+equ trap_CIN_SetExtents               -79
+equ trap_R_RemapShader                -80
+equ trap_S_AddRealLoopingSound        -81
+equ trap_S_StopLoopingSound           -82
+equ trap_CM_TempCapsuleModel          -83
+equ trap_CM_CapsuleTrace              -84
+equ trap_CM_TransformedCapsuleTrace   -85
+equ trap_R_AddAdditiveLightToScene    -86
+equ trap_GetEntityToken               -87
+equ trap_R_AddPolysToScene            -88
+equ trap_R_inPVS                      -89
+equ trap_FS_Seek                      -90
+equ trap_FS_GetFileList               -91
+equ trap_LiteralArgs                  -92
+equ trap_CM_BiSphereTrace             -93
+equ trap_CM_TransformedBiSphereTrace  -94
+equ trap_GetDemoState                 -95
+equ trap_GetDemoPos                   -96
+equ trap_GetDemoName                  -97
+equ trap_Key_KeynumToStringBuf        -98
+equ trap_Key_GetBindingBuf            -99
+equ trap_Key_SetBinding               -100
 equ trap_Key_SetOverstrikeMode        -101
 equ trap_Key_GetOverstrikeMode        -102
 
Index: src/cgame/cg_draw.c
===================================================================
--- src/cgame/cg_draw.c	(revision 1044)
+++ src/cgame/cg_draw.c	(working copy)
@@ -627,7 +627,7 @@
   qboolean      vertical;
   int           iconsize, numBarbs, i;
 
-  numBarbs = ps->ammo;
+  BG_UnpackAmmoArray( ps->weapon, ps->ammo, ps->misc, &numBarbs, NULL );
 
   if( height > width )
   {
@@ -702,7 +702,7 @@
         break;
 
       default:
-        value = ps->ammo;
+        BG_UnpackAmmoArray( cent->currentState.weapon, ps->ammo, ps->misc, &value, NULL );
         break;
     }
 
@@ -861,7 +861,7 @@
         break;
 
       default:
-        value = ps->clips;
+        BG_UnpackAmmoArray( cent->currentState.weapon, ps->ammo, ps->misc, NULL, &value );
 
         if( value > -1 )
         {
@@ -1106,11 +1106,25 @@
   {
     case CG_PLAYER_AMMO_VALUE:
       if( cent->currentState.weapon )
-        return ps->ammo;
+      {
+        int value;
+
+        BG_UnpackAmmoArray( cent->currentState.weapon, ps->ammo, ps->misc,
+           &value, NULL );
+
+        return value;
+      }
       break;
     case CG_PLAYER_CLIPS_VALUE:
       if( cent->currentState.weapon )
-        return ps->clips;
+      {
+        int value;
+
+        BG_UnpackAmmoArray( cent->currentState.weapon, ps->ammo, ps->misc,
+           NULL, &value );
+
+        return value;
+      }
       break;
     case CG_PLAYER_HEALTH:
       return ps->stats[ STAT_HEALTH ];
@@ -1901,13 +1915,14 @@
 */
 void CG_DrawWeaponIcon( rectDef_t *rect, vec4_t color )
 {
-  int           maxAmmo;
+  int           ammo, clips, maxAmmo;
   centity_t     *cent;
   playerState_t *ps;
 
   cent = &cg_entities[ cg.snap->ps.clientNum ];
   ps = &cg.snap->ps;
 
+  BG_UnpackAmmoArray( cent->currentState.weapon, ps->ammo, ps->misc, &ammo, &clips );
   BG_FindAmmoForWeapon( cent->currentState.weapon, &maxAmmo, NULL );
 
   // don't display if dead
@@ -1919,9 +1934,9 @@
 
   CG_RegisterWeapon( cent->currentState.weapon );
 
-  if( ps->clips == 0 && !BG_FindInfinteAmmoForWeapon( cent->currentState.weapon ) )
+  if( clips == 0 && !BG_FindInfinteAmmoForWeapon( cent->currentState.weapon ) )
   {
-    float ammoPercent = (float)ps->ammo / (float)maxAmmo;
+    float ammoPercent = (float)ammo / (float)maxAmmo;
 
     if( ammoPercent < 0.33f )
     {
Index: src/cgame/cg_local.h
===================================================================
--- src/cgame/cg_local.h	(revision 1044)
+++ src/cgame/cg_local.h	(working copy)
@@ -590,6 +590,16 @@
   qboolean  visible;       // Status is visble?
 } buildableStatus_t;
 
+typedef struct buildableCache_s
+{
+  vec3_t   cachedOrigin;   // If either the cached entity origin or the
+  vec3_t   cachedNormal;   // cached surfNormal change the cache is invalid
+  vec3_t   axis[ 3 ];
+  vec3_t   origin;
+} buildableCache_t;
+
+
+
 //=================================================
 
 // centity_t have a direct corespondence with gentity_t in the game, but
@@ -634,6 +644,7 @@
   buildableAnimNumber_t oldBuildableAnim; //to detect when new anims are set
   particleSystem_t      *buildablePS;
   buildableStatus_t     buildableStatus;
+  buildableCache_t      buildableCache;
   float                 lastBuildableHealthScale;
   int                   lastBuildableDamageSoundTime;
 
Index: src/cgame/cg_tutorial.c
===================================================================
--- src/cgame/cg_tutorial.c	(revision 1044)
+++ src/cgame/cg_tutorial.c	(working copy)
@@ -418,6 +418,7 @@
 static void CG_HumanText( char *text, playerState_t *ps )
 {
   char      *name;
+  int       ammo, clips;
   upgrade_t upgrade = UP_NONE;
 
   if( cg.weaponSelect <= 32 )
@@ -428,7 +429,9 @@
     upgrade = cg.weaponSelect - 32;
   }
 
-  if( !ps->ammo && !ps->clips && !BG_FindInfinteAmmoForWeapon( ps->weapon ) )
+  BG_UnpackAmmoArray( ps->weapon, ps->ammo, ps->misc, &ammo, &clips );
+
+  if( !ammo && !clips && !BG_FindInfinteAmmoForWeapon( ps->weapon ) )
   {
     //no ammo
     switch( ps->weapon )
Index: src/cgame/cg_weapons.c
===================================================================
--- src/cgame/cg_weapons.c	(revision 1044)
+++ src/cgame/cg_weapons.c	(working copy)
@@ -1196,12 +1196,19 @@
   {
     if( !BG_InventoryContainsWeapon( i, cg.snap->ps.stats ) )
       continue;
+      
+    {
+      int ammo, clips;
+  
+      BG_UnpackAmmoArray( i, cg.snap->ps.ammo, cg.snap->ps.misc, &ammo, &clips );
+  
+      if( !ammo && !clips && !BG_FindInfinteAmmoForWeapon( i ) )
+        colinfo[ numItems ] = 1;
+      else
+        colinfo[ numItems ] = 0;
+    	
+    }
 
-    if( !ps->ammo && !ps->clips && !BG_FindInfinteAmmoForWeapon( i ) )
-      colinfo[ numItems ] = 1;
-    else
-      colinfo[ numItems ] = 0;
-
     if( i == cg.weaponSelect )
       selectedItem = numItems;
 
Index: src/cgame/cg_servercmds.c
===================================================================
--- src/cgame/cg_servercmds.c	(revision 1044)
+++ src/cgame/cg_servercmds.c	(working copy)
@@ -500,20 +500,7 @@
       cmd       = "menu tremulous_human_dialog\n";
       break;
 
-    case MN_A_TEAMCHANGEBUILDTIMER:
-      longMsg   = "You cannot leave the Alien team until your build timer "
-                  "has expired.";
-      shortMsg  = "You cannot change teams until your build timer expires.\n";
-      cmd       = "menu tremulous_alien_dialog\n";
-      break;
 
-    case MN_H_TEAMCHANGEBUILDTIMER:
-      longMsg   = "You cannot leave the Human team until your build timer "
-                  "has expired.";
-      shortMsg  = "You cannot change teams until your build timer expires.\n";
-      cmd       = "menu tremulous_human_dialog\n";
-      break;
-
     //===============================
 
     case MN_H_NOROOM:
@@ -607,43 +594,7 @@
       cmd       = "menu tremulous_human_dialog\n";
       break;
 
-    case MN_H_NOARMOURYHERE:
-      longMsg   = "You must be near a powered Armoury in order to purchase "
-                  "weapons, upgrades or non-energy ammunition.";
-      shortMsg  = "You must be near a powered Armoury\n";
-      cmd       = "menu tremulous_human_dialog\n";
-      break;
 
-    case MN_H_NOENERGYAMMOHERE:
-      longMsg   = "You must be near an Armoury, Reactor or Repeater in order "
-                  "to purchase energy ammunition.";
-      shortMsg  = "You must be near an Armoury, Reactor or Repeater\n";
-      cmd       = "menu tremulous_human_dialog\n";
-      break;
-
-    case MN_H_NOROOMBSUITON:
-      longMsg   = "There is not enough room here to put on a Battle Suit. "
-                  "Make sure you have enough head room to climb in.";
-      shortMsg  = "Not enough room here to put on a Battle Suit\n";
-      cmd       = "menu tremulous_human_dialog\n";
-      break;
-
-    case MN_H_NOROOMBSUITOFF:
-      longMsg   = "There is not enough room here to take off your Battle Suit. "
-                  "Make sure you have enough head room to climb out.";
-      shortMsg  = "Not enough room here to take off your Battle Suit\n";
-      cmd       = "menu tremulous_human_dialog\n";
-      break;
-
-    case MN_H_ARMOURYBUILDTIMER:
-      longMsg   = "You are not allowed to buy or sell weapons until your "
-                  "build timer has expired.";
-      shortMsg  = "You can not buy or sell weapos until your build timer "
-                  "expires\n";
-      cmd       = "menu tremulous_human_dialog\n";
-      break;
-
-
     //===============================
 
     case MN_A_NOROOM:
@@ -725,12 +676,6 @@
       cmd       = "menu tremulous_alien_dialog\n";
       break;
 
-    case MN_A_EVOLVEBUILDTIMER:
-      longMsg   = "You cannot Evolve until your build timer has expired.";
-      shortMsg  = "You cannot Evolve until your build timer expires\n";
-      cmd       = "menu tremulous_alien_dialog\n";
-      break;
-
     case MN_A_HOVEL_OCCUPIED:
       longMsg   = "This Hovel is already occupied by another builder.";
       shortMsg  = "This Hovel is already occupied by another builder\n";
Index: src/cgame/cg_buildable.c
===================================================================
--- src/cgame/cg_buildable.c	(revision 1044)
+++ src/cgame/cg_buildable.c	(working copy)
@@ -622,12 +622,12 @@
 
   VectorMA( inOrigin, -TRACE_DEPTH, normal, end );
   VectorMA( inOrigin, 1.0f, normal, start );
-  CG_CapTrace( &tr, start, mins, maxs, end, skipNumber, MASK_PLAYERSOLID );
+  CG_CapTrace( &tr, start, mins, maxs, end, skipNumber, MASK_SOLID );
 
   if( tr.fraction == 1.0f )
   {
     //erm we missed completely - try again with a box trace
-    CG_Trace( &tr, start, mins, maxs, end, skipNumber, MASK_PLAYERSOLID );
+    CG_Trace( &tr, start, mins, maxs, end, skipNumber, MASK_SOLID );
   }
 
   VectorMA( inOrigin, tr.fraction * -TRACE_DEPTH, normal, outOrigin );
@@ -1280,9 +1280,33 @@
   BG_FindBBoxForBuildable( es->modelindex, mins, maxs );
 
   if( es->pos.trType == TR_STATIONARY )
-    CG_PositionAndOrientateBuildable( angles, ent.origin, surfNormal, es->number,
-                                      mins, maxs, ent.axis, ent.origin );
+  {
+    /*`CG_PositionAndOrientateBuildable( angles, ent.origin, surfNormal, es->number,`*/
+                                      /*`mins, maxs, ent.axis, ent.origin );`*/
 
+    // Positioning a buildable involves potentially up to two traces, and
+    // seeing as buildables rarely move, we cache the results and recalculate
+    // only if the buildable moves or changes orientation
+    if( VectorCompare( cent->buildableCache.cachedOrigin, cent->lerpOrigin ) &&
+        VectorCompare( cent->buildableCache.cachedNormal, surfNormal ) )
+    {
+      VectorCopy( cent->buildableCache.axis[ 0 ], ent.axis[ 0 ] );
+      VectorCopy( cent->buildableCache.axis[ 1 ], ent.axis[ 1 ] );
+      VectorCopy( cent->buildableCache.axis[ 2 ], ent.axis[ 2 ] );
+    }
+    else
+    {
+      CG_PositionAndOrientateBuildable( angles, ent.origin, surfNormal,
+                                        es->number, mins, maxs, ent.axis,
+                                        ent.origin );
+      VectorCopy( ent.axis[ 0 ], cent->buildableCache.axis[ 0 ] );
+      VectorCopy( ent.axis[ 1 ], cent->buildableCache.axis[ 1 ] );
+      VectorCopy( ent.axis[ 2 ], cent->buildableCache.axis[ 2 ] );
+      VectorCopy( cent->lerpOrigin, cent->buildableCache.cachedOrigin );
+      VectorCopy( surfNormal, cent->buildableCache.cachedNormal );
+    }
+  }
+
   //offset on the Z axis if required
   VectorMA( ent.origin, BG_FindZOffsetForBuildable( es->modelindex ), surfNormal, ent.origin );
 
Index: src/cgame/cg_public.h
===================================================================
--- src/cgame/cg_public.h	(revision 1044)
+++ src/cgame/cg_public.h	(working copy)
@@ -138,6 +138,11 @@
   CG_KEY_GETCATCHER,
   CG_KEY_SETCATCHER,
   CG_KEY_GETKEY,
+  CG_PARSE_ADD_GLOBAL_DEFINE,
+  CG_PARSE_LOAD_SOURCE,
+  CG_PARSE_FREE_SOURCE,
+  CG_PARSE_READ_TOKEN,
+  CG_PARSE_SOURCE_FILE_AND_LINE,
   CG_S_STOPBACKGROUNDTRACK,
   CG_REAL_TIME,
   CG_SNAPVECTOR,
@@ -172,12 +177,6 @@
   CG_KEY_GETBINDINGBUF,
   CG_KEY_SETBINDING,
 
-  CG_PARSE_ADD_GLOBAL_DEFINE,
-  CG_PARSE_LOAD_SOURCE,
-  CG_PARSE_FREE_SOURCE,
-  CG_PARSE_READ_TOKEN,
-  CG_PARSE_SOURCE_FILE_AND_LINE,
-
   CG_KEY_SETOVERSTRIKEMODE,
   CG_KEY_GETOVERSTRIKEMODE,
 
@@ -232,6 +231,12 @@
   // Generates and draws a game scene and status information at the given time.
   // If demoPlayback is set, local movement prediction will not be enabled
 
+  CG_CROSSHAIR_PLAYER,
+  // int (*CG_CrosshairPlayer)( void );
+
+  CG_LAST_ATTACKER,
+  // int (*CG_LastAttacker)( void );
+
   CG_KEY_EVENT,
   // void  (*CG_KeyEvent)( int key, qboolean down );
 
Index: src/cgame/cg_main.c
===================================================================
--- src/cgame/cg_main.c	(revision 1044)
+++ src/cgame/cg_main.c	(working copy)
@@ -68,6 +68,12 @@
       CG_DrawActiveFrame( arg0, arg1, arg2 );
       return 0;
 
+    case CG_CROSSHAIR_PLAYER: 	 
+      return CG_CrosshairPlayer( ); 	 
+ 	 
+    case CG_LAST_ATTACKER: 	 
+      return CG_LastAttacker( );
+
     case CG_KEY_EVENT:
       CG_KeyEvent( arg0, arg1 );
       return 0;
@@ -171,7 +177,7 @@
 vmCvar_t  cg_teamChatsOnly;
 vmCvar_t  cg_noVoiceChats;
 vmCvar_t  cg_noVoiceText;
-vmCvar_t  cg_hudFiles;
+vmCvar_t  cg_svnhudFiles;
 vmCvar_t  cg_scorePlum;
 vmCvar_t  cg_smoothClients;
 vmCvar_t  pmove_fixed;
@@ -320,7 +326,7 @@
   { &cg_disableWarningDialogs, "cg_disableWarningDialogs", "0", CVAR_ARCHIVE },
   { &cg_disableScannerPlane, "cg_disableScannerPlane", "0", CVAR_ARCHIVE },
   { &cg_tutorial, "cg_tutorial", "1", CVAR_ARCHIVE },
-  { &cg_hudFiles, "cg_hudFiles", "ui/hud.txt", CVAR_ARCHIVE},
+  { &cg_svnhudFiles, "cg_svnhudFiles", "ui/hud.txt", CVAR_ARCHIVE},
 
   { &cg_painBlendUpRate, "cg_painBlendUpRate", "10.0", 0 },
   { &cg_painBlendDownRate, "cg_painBlendDownRate", "0.5", 0 },
@@ -1701,7 +1707,7 @@
 
   Menu_Reset( );
 
-  trap_Cvar_VariableStringBuffer( "cg_hudFiles", buff, sizeof( buff ) );
+  trap_Cvar_VariableStringBuffer( "cg_svnhudFiles", buff, sizeof( buff ) );
   hudSet = buff;
 
   if( hudSet[ 0 ] == '\0' )
Index: src/ui/ui_public.h
===================================================================
--- src/ui/ui_public.h	(revision 1044)
+++ src/ui/ui_public.h	(working copy)
@@ -94,6 +94,11 @@
   UI_MEMORY_REMAINING,
   UI_R_REGISTERFONT,
   UI_R_MODELBOUNDS,
+  UI_PARSE_ADD_GLOBAL_DEFINE,
+  UI_PARSE_LOAD_SOURCE,
+  UI_PARSE_FREE_SOURCE,
+  UI_PARSE_READ_TOKEN,
+  UI_PARSE_SOURCE_FILE_AND_LINE,
   UI_S_STOPBACKGROUNDTRACK,
   UI_S_STARTBACKGROUNDTRACK,
   UI_REAL_TIME,
@@ -121,12 +126,6 @@
   UI_FS_SEEK,
   UI_SET_PBCLSTATUS,
 
-  UI_PARSE_ADD_GLOBAL_DEFINE,
-  UI_PARSE_LOAD_SOURCE,
-  UI_PARSE_FREE_SOURCE,
-  UI_PARSE_READ_TOKEN,
-  UI_PARSE_SOURCE_FILE_AND_LINE,
-
   UI_MEMSET = 100,
   UI_MEMCPY,
   UI_STRNCPY,
Index: src/ui/ui_main.c
===================================================================
--- src/ui/ui_main.c	(revision 1044)
+++ src/ui/ui_main.c	(working copy)
@@ -43,9 +43,9 @@
 
 static const char *netSources[ ] =
 {
+  "LAN",
+  "Mplayer",
   "Internet",
-  "Mplayer",
-  "LAN",
   "Favorites"
 };
 
Index: src/ui/ui_shared.c
===================================================================
--- src/ui/ui_shared.c	(revision 1044)
+++ src/ui/ui_shared.c	(working copy)
@@ -2041,6 +2041,8 @@
   float useScale;
   fontInfo_t *font = &DC->Assets.textFont;
 
+  memcpy( &newColor[0], &color[0], sizeof( vec4_t ) );
+
   if( scale <= DC->getCVarValue( "ui_smallFont" ) )
     font = &DC->Assets.smallFont;
   else if( scale >= DC->getCVarValue( "ui_bigFont" ) )
@@ -4366,9 +4368,9 @@
 
 static const char *Item_Text_Wrap( const char *text, float scale, float width )
 {
-  static char   out[ 8192 ];
+  static char   out[ 8192 ] = "";
   char          *paint = out;
-  char          c[ 3 ];
+  char          c[ 3 ] = "^7";
   const char    *p = text;
   const char    *eol;
   const char    *q = NULL, *qMinus1 = NULL;
@@ -4382,8 +4384,6 @@
 
   while( *p )
   {
-    Com_Memset( c, 0, sizeof( c ) );
-
     // Skip leading whitespace
 
     while( *p )
@@ -4403,20 +4403,21 @@
     if( !*p )
       break;
 
+    Q_strcat( paint, out + sizeof( out ) - paint, c );
+
     testLength = 1;
 
     eol = p;
 
-    q = p;
+    q = p + 1;
 
     while( Q_IsColorString( q ) )
+    {
+      c[ 0 ] = q[ 0 ];
+      c[ 1 ] = q[ 1 ];
       q += 2;
+    }
 
-    q++;
-
-    while( Q_IsColorString( q ) )
-      q += 2;
-
     while( UI_Text_Width( p, scale, testLength ) < width )
     {
       if( testLength >= strlen( p ) )
@@ -4434,6 +4435,8 @@
 
         while( Q_IsColorString( q ) )
         {
+          c[ 0 ] = q[ 0 ];
+          c[ 1 ] = q[ 1 ];
           q += 2;
           continue;
         }
@@ -4464,9 +4467,6 @@
     if( eol == p )
       eol = q;
 
-    // Add colour code (might be empty)
-    Q_strcat( out, sizeof( out ), c );
-
     paint = out + strlen( out );
 
     // Copy text
@@ -4476,7 +4476,12 @@
 
     // Add a \n if it's not there already
     if( out[ strlen( out ) - 1 ] != '\n' )
+    {
       Q_strcat( out, sizeof( out ), "\n" );
+      Q_strcat( out, sizeof( out ), c );
+    }
+    else
+      c[ 0 ] = '\0';
 
     paint = out + strlen( out );
 
Index: src/ui/ui_syscalls.asm
===================================================================
--- src/ui/ui_syscalls.asm	(revision 1044)
+++ src/ui/ui_syscalls.asm	(working copy)
@@ -55,37 +55,37 @@
 equ trap_MemoryRemaining              -53
 equ trap_R_RegisterFont               -54
 equ trap_R_ModelBounds                -55
-equ trap_S_StopBackgroundTrack        -56
-equ trap_S_StartBackgroundTrack       -57
-equ trap_RealTime                     -58
-equ trap_LAN_GetServerCount           -59
-equ trap_LAN_GetServerAddressString   -60
-equ trap_LAN_GetServerInfo            -61
-equ trap_LAN_MarkServerVisible        -62
-equ trap_LAN_UpdateVisiblePings       -63
-equ trap_LAN_ResetPings               -64
-equ trap_LAN_LoadCachedServers        -65
-equ trap_LAN_SaveCachedServers        -66
-equ trap_LAN_AddServer                -67
-equ trap_LAN_RemoveServer             -68
-equ trap_CIN_PlayCinematic            -69
-equ trap_CIN_StopCinematic            -70
-equ trap_CIN_RunCinematic             -71
-equ trap_CIN_DrawCinematic            -72
-equ trap_CIN_SetExtents               -73
-equ trap_R_RemapShader                -74
-equ trap_LAN_ServerStatus             -75
-equ trap_LAN_GetServerPing            -76
-equ trap_LAN_ServerIsVisible          -77
-equ trap_LAN_CompareServers           -78
-equ trap_FS_Seek                      -79
-equ trap_SetPbClStatus                -80
+equ trap_Parse_AddGlobalDefine        -56
+equ trap_Parse_LoadSource             -57
+equ trap_Parse_FreeSource             -58
+equ trap_Parse_ReadToken              -59
+equ trap_Parse_SourceFileAndLine      -60
+equ trap_S_StopBackgroundTrack        -61
+equ trap_S_StartBackgroundTrack       -62
+equ trap_RealTime                     -63
+equ trap_LAN_GetServerCount           -64
+equ trap_LAN_GetServerAddressString   -65
+equ trap_LAN_GetServerInfo            -66
+equ trap_LAN_MarkServerVisible        -67
+equ trap_LAN_UpdateVisiblePings       -68
+equ trap_LAN_ResetPings               -69
+equ trap_LAN_LoadCachedServers        -70
+equ trap_LAN_SaveCachedServers        -71
+equ trap_LAN_AddServer                -72
+equ trap_LAN_RemoveServer             -73
+equ trap_CIN_PlayCinematic            -74
+equ trap_CIN_StopCinematic            -75
+equ trap_CIN_RunCinematic             -76
+equ trap_CIN_DrawCinematic            -77
+equ trap_CIN_SetExtents               -78
+equ trap_R_RemapShader                -79
+equ trap_LAN_ServerStatus             -80
+equ trap_LAN_GetServerPing            -81
+equ trap_LAN_ServerIsVisible          -82
+equ trap_LAN_CompareServers           -83
+equ trap_FS_Seek                      -84
+equ trap_SetPbClStatus                -85
 
-equ trap_Parse_AddGlobalDefine        -81
-equ trap_Parse_LoadSource             -82
-equ trap_Parse_FreeSource             -83
-equ trap_Parse_ReadToken              -84
-equ trap_Parse_SourceFileAndLine      -85
 
 
 equ memset                            -101
Index: src/client/cl_console.c
===================================================================
--- src/client/cl_console.c	(revision 1044)
+++ src/client/cl_console.c	(working copy)
@@ -82,6 +82,67 @@
 
 /*
 ================
+Con_MessageMode_f
+================
+*/
+void Con_MessageMode_f (void) {
+	chat_playerNum = -1;
+	chat_team = qfalse;
+	Field_Clear( &chatField );
+	chatField.widthInChars = 30;
+
+	Key_SetCatcher( Key_GetCatcher( ) ^ KEYCATCH_MESSAGE );
+}
+
+/*
+================
+Con_MessageMode2_f
+================
+*/
+void Con_MessageMode2_f (void) {
+	chat_playerNum = -1;
+	chat_team = qtrue;
+	Field_Clear( &chatField );
+	chatField.widthInChars = 25;
+	Key_SetCatcher( Key_GetCatcher( ) ^ KEYCATCH_MESSAGE );
+}
+
+/*
+================
+Con_MessageMode3_f
+================
+*/
+void Con_MessageMode3_f (void) {
+	chat_playerNum = VM_Call( cgvm, CG_CROSSHAIR_PLAYER );
+	if ( chat_playerNum < 0 || chat_playerNum >= MAX_CLIENTS ) {
+		chat_playerNum = -1;
+		return;
+	}
+	chat_team = qfalse;
+	Field_Clear( &chatField );
+	chatField.widthInChars = 30;
+	Key_SetCatcher( Key_GetCatcher( ) ^ KEYCATCH_MESSAGE );
+}
+
+/*
+================
+Con_MessageMode4_f
+================
+*/
+void Con_MessageMode4_f (void) {
+	chat_playerNum = VM_Call( cgvm, CG_LAST_ATTACKER );
+	if ( chat_playerNum < 0 || chat_playerNum >= MAX_CLIENTS ) {
+		chat_playerNum = -1;
+		return;
+	}
+	chat_team = qfalse;
+	Field_Clear( &chatField );
+	chatField.widthInChars = 30;
+	Key_SetCatcher( Key_GetCatcher( ) ^ KEYCATCH_MESSAGE );
+}
+
+/*
+================
 Con_Clear_f
 ================
 */
@@ -253,6 +314,10 @@
 	CL_LoadConsoleHistory( );
 
 	Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
+	Cmd_AddCommand ("messagemode", Con_MessageMode_f);
+	Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
+	Cmd_AddCommand ("messagemode3", Con_MessageMode3_f);
+	Cmd_AddCommand ("messagemode4", Con_MessageMode4_f);
 	Cmd_AddCommand ("clear", Con_Clear_f);
 	Cmd_AddCommand ("condump", Con_Dump_f);
 }
@@ -541,6 +606,26 @@
 
 	if( Key_GetCatcher( ) & ( KEYCATCH_UI | KEYCATCH_CGAME ) )
 		return;
+
+	// draw the chat line
+	if( Key_GetCatcher( ) & KEYCATCH_MESSAGE )
+	{
+		int skip;
+
+		if( chat_team )
+		{
+			SCR_DrawBigString( 8, 232, "Team Say:", 1.0f, qfalse );
+			skip = 11;
+		}
+		else
+		{ 
+			SCR_DrawBigString( 8, 232, "Say:", 1.0f, qfalse );
+			skip = 5;
+		}
+
+		Field_BigDraw( &chatField, skip * BIGCHAR_WIDTH, 232,
+				SCREEN_WIDTH - ( skip + 1 ) * BIGCHAR_WIDTH, qtrue, qtrue );
+	}
 }
 
 //================================================================
Index: src/client/cl_keys.c
===================================================================
--- src/client/cl_keys.c	(revision 1044)
+++ src/client/cl_keys.c	(working copy)
@@ -35,8 +35,12 @@
 							// will be <= nextHistoryLine
 
 field_t		g_consoleField;
+field_t		chatField;
+qboolean	chat_team;
 
+int			chat_playerNum;
 
+
 qboolean	key_overstrikeMode;
 
 int				anykeydown;
@@ -701,7 +705,52 @@
 	Field_KeyDownEvent( &g_consoleField, key );
 }
 
+//============================================================================
 
+
+/*
+================
+Message_Key
+
+In game talk message
+================
+*/
+void Message_Key( int key ) {
+
+	char	buffer[MAX_STRING_CHARS];
+
+
+	if (key == K_ESCAPE) {
+		Key_SetCatcher( Key_GetCatcher( ) & ~KEYCATCH_MESSAGE );
+		Field_Clear( &chatField );
+		return;
+	}
+
+	if ( key == K_ENTER || key == K_KP_ENTER )
+	{
+		if ( chatField.buffer[0] && cls.state == CA_ACTIVE ) {
+			if (chat_playerNum != -1 )
+
+				Com_sprintf( buffer, sizeof( buffer ), "tell %i \"%s\"\n", chat_playerNum, chatField.buffer );
+
+			else if (chat_team)
+
+				Com_sprintf( buffer, sizeof( buffer ), "say_team \"%s\"\n", chatField.buffer );
+			else
+				Com_sprintf( buffer, sizeof( buffer ), "say \"%s\"\n", chatField.buffer );
+
+
+
+			CL_AddReliableCommand( buffer );
+		}
+		Key_SetCatcher( Key_GetCatcher( ) & ~KEYCATCH_MESSAGE );
+		Field_Clear( &chatField );
+		return;
+	}
+
+	Field_KeyDownEvent( &chatField, key );
+}
+
 //============================================================================
 
 
@@ -1149,6 +1198,12 @@
 
 	// escape is always handled special
 	if ( key == K_ESCAPE && down ) {
+		if ( Key_GetCatcher( ) & KEYCATCH_MESSAGE ) {
+			// clear message mode
+			Message_Key( key );
+			return;
+		}
+
 		// escape always gets out of CGAME stuff
 		if (Key_GetCatcher( ) & KEYCATCH_CGAME) {
 			Key_SetCatcher( Key_GetCatcher( ) & ~KEYCATCH_CGAME );
@@ -1206,6 +1261,8 @@
 		if ( cgvm ) {
 			VM_Call( cgvm, CG_KEY_EVENT, key, down );
 		} 
+	} else if ( Key_GetCatcher( ) & KEYCATCH_MESSAGE ) {
+		Message_Key( key );
 	} else if ( cls.state == CA_DISCONNECTED ) {
 		Console_Key( key );
 	} else {
@@ -1280,6 +1337,10 @@
 	{
 		VM_Call( uivm, UI_KEY_EVENT, key | K_CHAR_FLAG, qtrue );
 	}
+	else if ( Key_GetCatcher( ) & KEYCATCH_MESSAGE ) 
+	{
+		Field_CharEvent( &chatField, key );
+	}
 	else if ( cls.state == CA_DISCONNECTED )
 	{
 		Field_CharEvent( &g_consoleField, key );
Index: Makefile
===================================================================
--- Makefile	(revision 1044)
+++ Makefile	(working copy)
@@ -766,8 +766,8 @@
   ifneq ($(CROSS_COMPILING),1)
     TARGETS += \
       $(B)/base/vm/cgame.qvm \
-      $(B)/base/vm/game.qvm \
-      $(B)/base/vm/ui.qvm
+      $(B)/base/vm/ui.qvm 
+      #`$(B)/base/vm/game.qvm 
   endif
 endif
 
