Index: src/bzflag/LocalPlayer.cxx
===================================================================
RCS file: /cvsroot/bzflag/bzflag/src/bzflag/LocalPlayer.cxx,v
retrieving revision 2.53
diff -u -r2.53 LocalPlayer.cxx
--- src/bzflag/LocalPlayer.cxx	10 Oct 2006 22:42:32 -0000	2.53
+++ src/bzflag/LocalPlayer.cxx	13 Oct 2006 19:34:05 -0000
@@ -44,6 +44,8 @@
   antidoteFlag(NULL),
   desiredSpeed(0.0f),
   desiredAngVel(0.0f),
+  desiredAccelX(0.0f),
+  desiredAccelY(0.0f),
   lastSpeed(0.0f),
   anyShotActive(false),
   target(NULL),
@@ -298,20 +300,47 @@
       newAngVel = 0.0f;	// or oldAngVel to spin while exploding
     } else if ((location == OnGround) || (location == OnBuilding) ||
 	       (location == InBuilding && oldPosition[2] == groundLimit)) {
-      // full control
-      float speed = desiredSpeed;
+      if (!BZDB.isTrue("hoverbot") || !canMove()) {
+	// full control
+	float speed = desiredSpeed;
 
-      // angular velocity
-      newAngVel = getNewAngVel(oldAngVel, desiredAngVel);
+	// angular velocity
+	newAngVel = getNewAngVel(oldAngVel, desiredAngVel);
 
-      // limit acceleration
-      doMomentum(dt, speed, newAngVel);
+	// limit acceleration
+	doMomentum(dt, speed, newAngVel);
 
-      // compute velocity so far
-      const float angle = oldAzimuth + 0.5f * dt * newAngVel;
-      newVelocity[0] = speed * cosf(angle);
-      newVelocity[1] = speed * sinf(angle);
-      newVelocity[2] = 0.0f;
+	// save speed for next update
+	lastSpeed = speed;
+
+	// compute velocity so far
+	const float angle = oldAzimuth + 0.5f * dt * newAngVel;
+	newVelocity[0] = speed * cosf(angle);
+	newVelocity[1] = speed * sinf(angle);
+	newVelocity[2] = 0.0f;
+      } else {
+	// get maximum linear acceleration
+	float linearAcc = (getFlag() == Flags::Momentum)
+	  ? BZDB.eval(StateDatabase::BZDB_MOMENTUMLINACC)
+	  : BZDB.eval(StateDatabase::BZDB_INERTIALINEAR);
+	// the magic 20.0f is from doMomentum()
+	newVelocity[0] = oldVelocity[0] + dt * 20.0f * linearAcc * desiredAccelX;
+	newVelocity[1] = oldVelocity[1] + dt * 20.0f * linearAcc * desiredAccelY;
+
+	float newSpeed = sqrt(newVelocity[0] * newVelocity[0]
+	      + newVelocity[1] * newVelocity[1]);
+
+	if (newSpeed > BZDBCache::tankSpeed) {
+	  newVelocity[0] *= BZDBCache::tankSpeed / newSpeed;
+	  newVelocity[1] *= BZDBCache::tankSpeed / newSpeed;
+	}
+
+	// angular velocity
+	newAngVel = getNewAngVel(oldAngVel, desiredAngVel);
+	// limit angular acceleration
+	float dummy = 0.0;
+	doMomentum(dt, dummy, newAngVel);
+      }
 
       // now friction, if any
       doFriction(dt, oldVelocity, newVelocity);
@@ -324,9 +353,6 @@
 	newVelocity[2] += 4 * BZDBCache::gravity * dt;
       else if (oldPosition[2] > groundLimit)
 	newVelocity[2] += BZDBCache::gravity * dt;
-
-      // save speed for next update
-      lastSpeed = speed;
     } else {
       // can't control motion in air unless have wings
       if (getFlag() == Flags::Wings) {
@@ -1153,6 +1179,34 @@
 }
 
 
+void			LocalPlayer::setDesiredAccelX(float fracOfMaxAccel)
+{
+  // If we aren't allowed to move, then the desired acceleration is 0.
+  if (!canMove()) {
+    fracOfMaxAccel = 0.0;
+  }
+
+  if (fracOfMaxAccel > 1.0f) fracOfMaxAccel = 1.0f;
+  else if (fracOfMaxAccel < -1.0f) fracOfMaxAccel = -1.0f;
+
+  desiredAccelX = fracOfMaxAccel;
+}
+
+
+void			LocalPlayer::setDesiredAccelY(float fracOfMaxAccel)
+{
+  // If we aren't allowed to move, then the desired acceleration is 0.
+  if (!canMove()) {
+    fracOfMaxAccel = 0.0;
+  }
+
+  if (fracOfMaxAccel > 1.0f) fracOfMaxAccel = 1.0f;
+  else if (fracOfMaxAccel < -1.0f) fracOfMaxAccel = -1.0f;
+
+  desiredAccelY = fracOfMaxAccel;
+}
+
+
 void			LocalPlayer::setPause(bool pause)
 {
   if (isAlive()) {
Index: src/bzflag/LocalPlayer.h
===================================================================
RCS file: /cvsroot/bzflag/bzflag/src/bzflag/LocalPlayer.h,v
retrieving revision 2.15
diff -u -r2.15 LocalPlayer.h
--- src/bzflag/LocalPlayer.h	10 Oct 2006 22:42:32 -0000	2.15
+++ src/bzflag/LocalPlayer.h	13 Oct 2006 19:34:05 -0000
@@ -69,6 +69,8 @@
   void		setTeam(TeamColor);
   void		setDesiredSpeed(float fracOfMaxSpeed);
   void		setDesiredAngVel(float fracOfMaxAngVel);
+  void		setDesiredAccelX(float fracOfMaxAccel);
+  void		setDesiredAccelY(float fracOfMaxAccel);
   void		setPause(bool = true);
   void		activateAutoPilot(bool = true);
   bool		fireShot();
@@ -145,6 +147,8 @@
   FlagSceneNode*	antidoteFlag;
   float		desiredSpeed;
   float		desiredAngVel;
+  float		desiredAccelX;
+  float		desiredAccelY;
   float		lastSpeed;
   float		crossingPlane[4];
   bool		anyShotActive;
Index: src/bzflag/defaultBZDB.cxx
===================================================================
RCS file: /cvsroot/bzflag/bzflag/src/bzflag/defaultBZDB.cxx,v
retrieving revision 2.34
diff -u -r2.34 defaultBZDB.cxx
--- src/bzflag/defaultBZDB.cxx	5 Aug 2006 20:03:50 -0000	2.34
+++ src/bzflag/defaultBZDB.cxx	13 Oct 2006 19:34:05 -0000
@@ -184,7 +184,13 @@
   { "3rdPersonFarTargetDistance",	"180.0",			true,	StateDatabase::ReadWrite,	NULL },
 
   // last screenshot
-  { "lastScreenshot",		"0",			true,	StateDatabase::ReadWrite,	NULL }
+  { "lastScreenshot",		"0",			true,	StateDatabase::ReadWrite,	NULL },
+
+  // Robots
+  { "hoverbot",			"0",			false,	StateDatabase::ReadWrite,	NULL },
+  { "bzrcPosNoise",		"0.0",			false,	StateDatabase::ReadWrite,	NULL },
+  { "bzrcAngNoise",		"0.0",			false,	StateDatabase::ReadWrite,	NULL },
+  { "bzrcVelNoise",		"0.0",			false,	StateDatabase::ReadWrite,	NULL },
 };
 
 
Index: src/bzrobots/RCLink.cxx
===================================================================
RCS file: /cvsroot/bzflag/bzflag/src/bzrobots/RCLink.cxx,v
retrieving revision 1.2
diff -u -r1.2 RCLink.cxx
--- src/bzrobots/RCLink.cxx	13 Oct 2006 19:26:23 -0000	1.2
+++ src/bzrobots/RCLink.cxx	13 Oct 2006 19:34:05 -0000
@@ -457,6 +457,48 @@
     } else if (angularvel_level < -1.0) {
       angularvel_level = -1.0;
     }
+  } else if (strcasecmp(argv[0], "accelx") == 0 && argc == 3) {
+    request_type = AccelX;
+
+    index = strtol(argv[1], &endptr, 0);
+    if (endptr == argv[1]) {
+      index = -1;
+      fail = true;
+      failstr = "Invalid parameter for tank.";
+    }
+    set_robotindex(index);
+
+    accelx_level = strtof(argv[2], &endptr);
+    if (endptr == argv[2]) {
+      fail = true;
+      failstr = "Invalid parameter for angular velocity.";
+    }
+    if (accelx_level > 1.0) {
+      accelx_level = 1.0;
+    } else if (accelx_level < -1.0) {
+      accelx_level = -1.0;
+    }
+  } else if (strcasecmp(argv[0], "accely") == 0 && argc == 3) {
+    request_type = AccelY;
+
+    index = strtol(argv[1], &endptr, 0);
+    if (endptr == argv[1]) {
+      index = -1;
+      fail = true;
+      failstr = "Invalid parameter for tank.";
+    }
+    set_robotindex(index);
+
+    accely_level = strtof(argv[2], &endptr);
+    if (endptr == argv[2]) {
+      fail = true;
+      failstr = "Invalid parameter for angular velocity.";
+    }
+    if (accely_level > 1.0) {
+      accely_level = 1.0;
+    } else if (accely_level < -1.0) {
+      accely_level = -1.0;
+    }
   } else if (strcasecmp(argv[0], "shoot") == 0 && argc == 2) {
     request_type = Shoot;
 
@@ -500,6 +542,12 @@
     case AngularVel:
       link->respondf("ack %f angvel %d %f\n", elapsed, get_robotindex(), angularvel_level);
       break;
+    case AccelX:
+      link->respondf("ack %f accelx %d %f\n", elapsed, get_robotindex(), accelx_level);
+      break;
+    case AccelY:
+      link->respondf("ack %f accely %d %f\n", elapsed, get_robotindex(), accely_level);
+      break;
     case Shoot:
       link->respondf("ack %f shoot %d\n", elapsed, get_robotindex());
       break;
Index: src/bzrobots/RCLink.h
===================================================================
RCS file: /cvsroot/bzflag/bzflag/src/bzrobots/RCLink.h,v
retrieving revision 1.2
diff -u -r1.2 RCLink.h
--- src/bzrobots/RCLink.h	13 Oct 2006 19:26:24 -0000	1.2
+++ src/bzrobots/RCLink.h	13 Oct 2006 19:34:05 -0000
@@ -36,6 +36,8 @@
 		    HelloRequest,
 		    Speed,
 		    AngularVel,
+		    AccelX,
+		    AccelY,
 		    Shoot,
 		    TeamListRequest,
 		    BasesListRequest,
@@ -62,6 +64,7 @@
 			void sendfail(RCLink *link);
 
 			float speed_level, angularvel_level;
+			float accelx_level, accely_level;
 			bool fail;
 			char *failstr;
 
Index: src/bzrobots/RCRobotPlayer.cxx
===================================================================
RCS file: /cvsroot/bzflag/bzflag/src/bzrobots/RCRobotPlayer.cxx,v
retrieving revision 1.3
diff -u -r1.3 RCRobotPlayer.cxx
--- src/bzrobots/RCRobotPlayer.cxx	13 Oct 2006 19:26:24 -0000	1.3
+++ src/bzrobots/RCRobotPlayer.cxx	13 Oct 2006 19:34:05 -0000
@@ -32,6 +32,8 @@
 				agent(_agent),
 				speed(0.0),
 				angularvel(0.0),
+				accelx(0.0),
+				accely(0.0),
 				shoot(false)
 {
 }
@@ -45,7 +47,12 @@
 void			RCRobotPlayer::doUpdateMotion(float dt)
 {
   if (isAlive()) {
-    setDesiredSpeed(speed);
+    if (!BZDB.isTrue("hoverbot")) {
+      setDesiredSpeed(speed);
+    } else {
+      setDesiredAccelX(accelx);
+      setDesiredAccelY(accely);
+    }
     setDesiredAngVel(angularvel);
   }
   LocalPlayer::doUpdateMotion(dt);
@@ -66,8 +73,12 @@
 {
   switch (req->get_request_type()) {
     case Speed:
-      speed = req->speed_level;
-      link->respond("ok\n");
+      if (!BZDB.isTrue("hoverbot")) {
+	speed = req->speed_level;
+	link->respond("ok\n");
+      } else {
+	link->respond("fail speed not allowed (hoverbot-only)\n");
+      }
       break;
 
     case AngularVel:
@@ -75,6 +86,24 @@
       link->respond("ok\n");
       break;
 
+    case AccelX:
+      if (BZDB.isTrue("hoverbot")) {
+	accelx = req->accelx_level;
+	link->respond("ok\n");
+      } else {
+	link->respond("fail accelx not allowed (not a hoverbot)\n");
+      }
+      break;
+
+    case AccelY:
+      if (BZDB.isTrue("hoverbot")) {
+	accely = req->accely_level;
+	link->respond("ok\n");
+      } else {
+	link->respond("fail accely not allowed (not a hoverbot)\n");
+      }
+      break;
+
     case Shoot:
       shoot = true;
       if (fireShot()) {
Index: src/bzrobots/RCRobotPlayer.h
===================================================================
RCS file: /cvsroot/bzflag/bzflag/src/bzrobots/RCRobotPlayer.h,v
retrieving revision 1.2
diff -u -r1.2 RCRobotPlayer.h
--- src/bzrobots/RCRobotPlayer.h	13 Oct 2006 19:26:24 -0000	1.2
+++ src/bzrobots/RCRobotPlayer.h	13 Oct 2006 19:34:05 -0000
@@ -48,6 +48,7 @@
     void		doUpdateMotion(float dt);
     RCLink*		agent;
     float		speed, angularvel;
+    float		accelx, accely;
     bool		shoot;
 };
 
Index: src/bzrobots/botplaying.cxx
===================================================================
RCS file: /cvsroot/bzflag/bzflag/src/bzrobots/botplaying.cxx,v
retrieving revision 1.2
diff -u -r1.2 botplaying.cxx
--- src/bzrobots/botplaying.cxx	13 Oct 2006 19:26:24 -0000	1.2
+++ src/bzrobots/botplaying.cxx	13 Oct 2006 19:34:05 -0000
@@ -2595,7 +2595,7 @@
 
   rcLink->respondf("constant team %s\n", Team::getShortName(startupInfo.team));
   rcLink->respondf("constant worldsize %f\n", BZDBCache::worldSize);
-  rcLink->respond("constant hoverbot 0\n");
+  rcLink->respondf("constant hoverbot %s\n", BZDB.get("hoverbot").c_str());
 
   rcLink->respond("end\n");
 }
@@ -2616,6 +2616,8 @@
     switch (req->get_request_type()) {
       case Speed:
       case AngularVel:
+      case AccelX:
+      case AccelY:
       case Shoot:
 	tankindex = req->get_robotindex();
 	if (tankindex == -1) {
Index: src/bzrobots/bzrobots.cxx
===================================================================
RCS file: /cvsroot/bzflag/bzflag/src/bzrobots/bzrobots.cxx,v
retrieving revision 1.2
diff -u -r1.2 bzrobots.cxx
--- src/bzrobots/bzrobots.cxx	13 Oct 2006 19:26:24 -0000	1.2
+++ src/bzrobots/bzrobots.cxx	13 Oct 2006 19:34:05 -0000
@@ -226,6 +226,8 @@
 	printFatalError("Invalid argument for %s.", argv[i-1]);
 	usage();
       }
+    } else if (strcmp(argv[i], "-hoverbot") == 0) {
+      BZDB.set("hoverbot", "1");
     } else if (strcmp(argv[i], "-posnoise") == 0) {
       checkArgc(i, argc, argv[i]);
       BZDB.set("bzrcPosNoise", argv[i]);
