Exemplo n.º 1
0
int setCourse(int crs_dir, int eng_type, int speed)
{
   return set_course(crs_dir, eng_type, speed);
}
Exemplo n.º 2
0
void rmove()
{
    register struct player *j;
    register int i;
    register int burst;
    register int numHits, tDir;
    int		avDir;
    extern struct Enemy *get_nearest();
    struct Enemy *enemy_buf;
    struct player *enemy = NULL;
    static int	roboclock = 0;
    static int	avoid[2] = { -32, 32 };
    int no_cloak;
    char towhom[MSG_LEN];
    int timer;
    static int lastTorpped = 0; /* when we last fired a torp 4/13/92 TC */

    roboclock++;

    /* keep ghostbuster away */
    me->p_ghostbuster = 0;

    /* Check that I'm alive */
    if (me->p_status == PEXPLODE) {
        if (debug) ERROR(1,("Robot: Augh! exploding.\n"));
	return;
    }
    else if (me->p_status == PDEAD) {
	if (me->p_ntorp > 0)
               return;
	if (debug) ERROR(1,("Robot: done exploding and torps are gone.\n"));
	exitRobot();
	return;
    }


    timer=0;
    for (i = 0, j = &players[i]; i < (MAXPLAYER - TESTERS); i++, j++) {
	if ((j->p_status != PFREE) && !(j->p_flags & PFROBOT))
	    timer=1;
    }
    if (!timer && !sticky) {
	exitRobot();
	return;
    }

    /* if I'm a Terminator, quit if he quits, and quit if he dies and */
    /* I'm not "sticky" (-s) */

    if (target >= 0) {
	if (players[target].p_status == PFREE) { /* he went away */
	    me->p_status = PEXPLODE;	    
	    return;
	}
	if ((!sticky) && (players[target].p_status != PALIVE)) { /* he died */
	    me->p_status = PEXPLODE;
	    return;
	}
    }

    /* If it's been BOREDOM_TIME updates since we fired a torp, become
       hostile to all races, if we aren't already, and if we're not
       a practice robot (intended for guardian bots). 4/13/92 TC */

    if ((roboclock - lastTorpped > BOREDOM_TIME) && (!practice) && (!hostile) &&
        (me->p_team != 0 && !quiet)) {
        messAll(me->p_no,roboname,"I'm bored.");
        hostile++;
        declare_war(ALLTEAM, 0);
    }

    /* Our first priority is to phaser plasma torps in nearby vicinity... */
    /* If we fire, we aren't allowed to cloak... */
    no_cloak = phaser_plasmas();

    /* Find an enemy */

    enemy_buf = get_nearest();

    if ((enemy_buf != NULL) && (enemy_buf != NOENEMY)) {	/* Someone to kill */
	enemy = &players[enemy_buf->e_info];
	if (((random() % messfuse) == 0) &&
	    (hypot((double) me->p_x-enemy->p_x, (double) me->p_y-enemy->p_y) < 20000.0)) {
	    /* change 5/10/21 TC ...neut robots don't message */
	    messfuse = MESSFUSEVAL;
	    if (me->p_team != 0 && !quiet) {
		sprintf(towhom, " %s->%s",
			players[me->p_no].p_mapchars,
			players[enemy->p_no].p_mapchars);
		pmessage2(enemy->p_no, MINDIV, towhom, me->p_no, "%s",
			robo_message(enemy));
	    }
	    else if (target >= 0 && !quiet) {
		messAll(me->p_no,roboname,"%s",termie_message(enemy));
	    }
	}
	else
	    if (--messfuse == 0)
		messfuse = 1;
	timer = 0;
/*	if (debug)
	    ERROR(1,( "%d) noticed %d\n", me->p_no, enemy_buf->e_info));*/
    }
    else if (enemy_buf == NOENEMY) { /* no more players. wait 1 minute. */
	if (do_repair()) {
	    return;
	}
	go_home(0);
/*	if (debug)
	    ERROR(1,( "%d) No players in game.\n", me->p_no));*/
	return;
    }
    else if (enemy_buf == 0) {	 /* no one hostile */
/*	if (debug)
	    ERROR(1,( "%d) No hostile players in game.\n", me->p_no));*/
	if (do_repair()) {
	    return;
	}
	go_home(0);
	timer = 0;
	return;
    }

/* Note a bug in this algorithm:
** Once someone dies, he is forgotten.  This makes robots particularly easy
**  to kill on a suicide run, where you aim to where you think he will turn 
**  as you die.  Once dead, the robot will ignore you and all of your 
**  active torpedoes!
**/

/* Algorithm:
** We have an enemy.
** First priority: shoot at target in range.
** Second: Dodge torps and plasma torps.
** Third: Get away if we are damaged.
** Fourth: repair.
** Fifth: attack.
*/

/*
** If we are a practice robot, we will do all but the second.  One
** will be modified to shoot poorly and not use phasers.
**/
    /* Fire weapons!!! */
    /*
    ** get_nearest() has already determined if torpedoes and phasers
    ** will hit.  It has also determined the courses which torps and
    ** phasers should be fired.  If so we will go ahead and shoot here.
    ** We will lose repair and cloaking for the rest of this interrupt.
    ** if we fire here.
    */

    if (practice) {
	no_cloak = 1;
	if (enemy_buf->e_flags & E_TSHOT) {
/*	    if (debug)
		ERROR(1,( "%d) firing torps\n", me->p_no));*/
	    for (burst = 0; (burst < 3) && (me->p_ntorp < MAXTORP); burst++) {
		ntorp(enemy_buf->e_tcourse, TWOBBLE | TOWNERSAFE | TDETTEAMSAFE | TPRACTICE);
	    }
	}
    }
    else {
	if (enemy_buf->e_flags & E_TSHOT) {
/*	    if (debug)
		ERROR(1,( "%d) firing torps\n", me->p_no));*/
	    for (burst = 0; (burst < 2) && (me->p_ntorp < MAXTORP); burst++) {
		repair_off();
		if (! cloaker) cloak_off();
		ntorp(enemy_buf->e_tcourse, TWOBBLE | TOWNERSAFE | TDETTEAMSAFE);
		no_cloak++;
                lastTorpped = roboclock; /* record time of firing 4/13/92 TC */
	    }
	}
	if (enemy_buf->e_flags & E_PSHOT) {
/*	    if (debug)
		ERROR(1,( "%d) phaser firing\n", me->p_no));*/
	    no_cloak++;
	    repair_off();
	    if (! cloaker) cloak_off();
	    phaser(enemy_buf->e_course);
	}
    }

    /* auto pressor 7/27/91 TC */
    /* tractor/pressor rewritten on 5/1/92... glitches galore :-| TC */

    /* whoa, too close for comfort, or he's tractoring me, or
       headed in for me, or I'm hurt */

    /* a little tuning -- 0.8 on phrange and +/- 90 degrees in for pressor */

    /* pressor_player(-1); this didn't do anything before, so we'll let
       the pressors disengage by themselves 5/1/92 TC */
    if (enemy_buf->e_flags & E_TRACT) {	/* if pressorable */
	if (((enemy_buf->e_dist < 0.8 * enemy_buf->e_phrange) &&
	     (angdist(enemy_buf->e_edir, enemy_buf->e_course) > 64)) ||
	    (isTractoringMe(enemy_buf)) ||
	    (me->p_damage > 0)) {
	    if (!(enemy->p_flags & PFCLOAK)) {
		  if (debug)
		    ERROR(1,( "%d) pressoring %d\n", me->p_no,
			    enemy_buf->e_info));
		  pressor_player(enemy->p_no);
		  no_cloak++;
		  repair_off();
		  if (!cloaker) cloak_off();
	    }
	}
    }

    /* auto tractor 7/31/91 TC */

    /* tractor if not pressoring and... */

    /* tractor if: in range, not too close, and not headed +/- 90 degrees */
    /* of me, and I'm not hurt */
    
    if ((!(me->p_flags & PFPRESS)) &&
	(enemy_buf->e_flags & E_TRACT) &&
	(angdist(enemy_buf->e_edir, enemy_buf->e_course) < 64) &&
	(enemy_buf->e_dist > 0.7 * enemy_buf->e_phrange)) {
	if (!(me->p_flags & PFTRACT)) {
	    if (debug)
		ERROR(1,( "%d) tractoring %d\n", me->p_no,
			enemy_buf->e_info));
	    tractor_player(enemy->p_no);
	    no_cloak++;
	}
    }	
    else
	tractor_player(-1);	/* otherwise don't tractor */

    /* Avoid torps */
    /*
    ** This section of code allows robots to avoid torps.
    ** Within a specific range they will check to see if
    ** any of the 'closest' enemies torps will hit them.
    ** If so, they will evade for four updates.
    ** Evading is all they will do for this round, other than shooting.
    */

    if (!practice) {
	if ((enemy->p_ntorp < 5)) {
	    if ((enemy_buf->e_dist < 15000) || (avoidTime > 0)) {
		numHits = projectDamage(enemy->p_no, &avDir);
		if (debug) {
		    ERROR(1,( "%d hits expected from %d from dir = %d\n",
			    numHits, enemy->p_no, avDir));
		}
		if (numHits == 0) {
		    if (--avoidTime > 0) {	/* we may still be avoiding */
			if (angdist(me->p_desdir, me->p_dir) > 64)
			    me->p_desspeed = dogslow;
			else
			    me->p_desspeed = dogfast;
			return;
		    }
		} else {
		    /*
		     * Actually avoid Torps
		     */ 
		    avoidTime = AVOID_TIME;
		    tDir = avDir - me->p_dir;
		    /* put into 0->255 range */
		    tDir = NORMALIZE(tDir);
		    if (debug)
			ERROR(1,( "mydir = %d avDir = %d tDir = %d q = %d\n",
			    me->p_dir, avDir, tDir, tDir / 64));
		    switch (tDir / 64) {
		    case 0:
		    case 1:
			    set_course(NORMALIZE(avDir + 64));
			    break;
		    case 2:
		    case 3:
			    set_course(NORMALIZE(avDir - 64));
			    break;
		    }
		    if (!no_cloak)
			cloak_on();

		    if (angdist(me->p_desdir, me->p_dir) > 64)
			me->p_desspeed = dogslow;
		    else
			me->p_desspeed = dogfast;
			
		    shield_up();
		    detothers();	/* hmm */
		    if (debug)
			ERROR(1,( "evading to dir = %d\n", me->p_desdir));
		    return;
		}
	    }
	}

	/*
	** Trying another scheme.
	** Robot will keep track of the number of torps a player has
	** launched.  If they are greater than say four, the robot will
	** veer off immediately.  Seems more humanlike to me.
	*/

	else if (enemy_buf->e_dist < 15000) {
	    if (--avoidTime > 0) {	/* we may still be avoiding */
		if (angdist(me->p_desdir, me->p_dir) > 64)
		    me->p_desspeed = dogslow;
		else
		    me->p_desspeed = dogfast;
		return;
	    }
	    if (random() % 2) {
		me->p_desdir = NORMALIZE(enemy_buf->e_course - 64);
		avoidTime = AVOID_TIME;
	    }
	    else {
		me->p_desdir = NORMALIZE(enemy_buf->e_course + 64);
		avoidTime = AVOID_TIME;
	    }
	    if (angdist(me->p_desdir, me->p_dir) > 64)
		me->p_desspeed = dogslow;
	    else
		me->p_desspeed = dogfast;
	    shield_up();
	    return;
	}
    }
	    
    /* Run away */
    /*
    ** The robot has taken damage.  He will now attempt to run away from
    ** the closest player.  This obviously won't do him any good if there
    ** is another player in the direction he wants to go.
    ** Note that the robot will not run away if he dodged torps, above.
    ** The robot will lower his shields in hopes of repairing some damage.
    */

#define STARTDELTA 5000		/* ships appear +/- delta of home planet */

    if (me->p_damage > 0 && enemy_buf->e_dist < 13000) {
	if (me->p_etemp > 900)		/* 90% of 1000 */
	    me->p_desspeed = runslow;
	else
	    me->p_desspeed = runfast;
	if (!no_cloak)
	    cloak_on();
	repair_off();
	shield_down();
	set_course(enemy_buf->e_course - 128);
	if (debug)
	    ERROR(1,( "%d(%d)(%d/%d) running from %c%d %16s damage (%d/%d) dist %d\n",
		me->p_no,
		(int) me->p_kills,
		me->p_damage,
		me->p_shield,
		teamlet[enemy->p_team],
		enemy->p_no,
		enemy->p_login,
		enemy->p_damage,
		enemy->p_shield,
		enemy_buf->e_dist));
	return;
    }

    /* Repair if necessary (we are safe) */
    /*
    ** The robot is safely away from players.  It can now repair in peace.
    ** It will try to do so now.
    */

    if (do_repair()) {
	return;
    }

    /* Attack. */
    /*
    ** The robot has nothing to do.  It will check and see if the nearest
    ** enemy fits any of its criterion for attack.  If it does, the robot
    ** will speed in and deliver a punishing blow.  (Well, maybe)
    */

    if ((enemy_buf->e_flags & E_INTRUDER) || (enemy_buf->e_dist < 15000)
	|| (hostile)) {
	if ((!no_cloak) && (enemy_buf->e_dist < 10000))
	    cloak_on();
	shield_up();
/*	if (debug)
	    ERROR(1,( "%d(%d)(%d/%d) attacking %c%d %16s damage (%d/%d) dist %d\n",
		me->p_no,
		(int) me->p_kills,
		me->p_damage,
		me->p_shield,
		teamlet[enemy->p_team],
		enemy->p_no,
		enemy->p_login,
		enemy->p_damage,
		enemy->p_shield,
		enemy_buf->e_dist));*/

	if (enemy_buf->e_dist < 15000) {
	    set_course(enemy_buf->e_course + 
		    avoid[(roboclock / AVOID_CLICKS) % SIZEOF(avoid)]);
	    if (angdist(me->p_desdir, me->p_dir) > 64)
		set_speed(closeslow);
	    else
		set_speed(closefast);
	}
	else {
	    me->p_desdir = enemy_buf->e_course;
	    if (angdist(me->p_desdir, me->p_dir) > 64)
		set_speed(closeslow);
	    if (target >= 0)	/* 7/27/91 TC */
		set_speed(12);
	    else if (me->p_etemp > 900)		/* 90% of 1000 */
		set_speed(runslow);
	    else
		set_speed(runfast);
	}
    }
    else {
	go_home(enemy_buf);
    }
}
Exemplo n.º 3
0
static void auto_features(void)
{
    struct player *pl;
    struct planet *pln;
    u_char course;
    int troop_capacity=0;
    static int sd_time_last = -1;
    int sd_time;

    check_observs();
    if (!living) return;

    if (me->p_flags & PFSELFDEST) {
        sd_time = (me->p_selfdest - me->p_updates) / 10;
        if (sd_time != sd_time_last) {
            sd_time_last = sd_time;
            switch (sd_time) {
            case 4:
            case 5:
              new_warning(UNDEF, "You notice everyone on the bridge is staring at you.");
              break;
            default:
              new_warning(UNDEF, "Stand By ... Self Destruct in %d seconds", sd_time);
              break;
            }
        }
    } else {
        sd_time_last = -1;
    }

    /* provide a refit countdown 4/6/92 TC */

    if (me->p_flags & PFREFITTING) {
	static int lastRefitValue = 0; /* for smooth display */
	if (lastRefitValue != (rdelay - me->p_updates)/10) {
	    lastRefitValue = (rdelay - me->p_updates)/10; /* CSE to the rescue? */
	    switch (lastRefitValue) {
	      case 3:
	      case 2:
		new_warning(UNDEF, "Engineering:  Energizing transporters in %d seconds", lastRefitValue);
		break;
	      case 1:
		new_warning(UNDEF, "Engineering:  Energize. [ SFX: chimes ]");
		break;
	      case 0:
		switch (random()%5) {
		  case 0:
		    new_warning(UNDEF,"Wait, you forgot your toothbrush!");
		    break;
		  case 1:
		    new_warning(UNDEF,"Nothing like turning in a used ship for a new one.");
		    break;
		  case 2:
		    new_warning(UNDEF,"First officer:  Oh no, not you again... we're doomed!");
		    break;
		  case 3:
		    new_warning(UNDEF,"First officer:  Uh, I'd better run diagnostics on the escape pods.");
		    break;
		  case 4:
		    new_warning(UNDEF,"Shipyard controller:  This time, *please* be more careful, okay?");
		    break;
		}
		break;
	    }
	}
    }

    /* provide a war declaration countdown 4/6/92 TC */

    if (me->p_flags & PFWAR) {
	static int lastWarValue = 0;
	if (lastWarValue != (delay - me->p_updates)/10) {
	    lastWarValue = (delay - me->p_updates)/10; /* CSE to the rescue? */
	    switch (lastWarValue) {
	      case 9:
		new_warning(UNDEF,"Weapons officer:  Not again!  This is absurd...");
		break;
	      case 8:
		break;
	      case 7:
		new_warning(UNDEF,"Weapons officer:  ... the whole ship's computer is down?");
		break;
	      case 6:
		break;
	      case 5:
		new_warning(UNDEF,"Weapons officer:  Just to twiddle a few bits of the ship's memory?");
		break;
	      case 4:
		break;
	      case 3:
		new_warning(UNDEF,"Weapons officer:  Bah! [ bangs fist on inoperative console ]");
		break;
	      case 2:
		break;
	      case 1:
		new_warning(UNDEF,"First Officer:  Easy, big guy... it's just one of those mysterious");
		break;
	      case 0:
		switch (random()%5) {
		  case 0:
		    new_warning(UNDEF,"First Officer:  laws of the universe, like 'tires on the ether'.");
		    break;
		  case 1:
		    new_warning(UNDEF,"First Officer:  laws of the universe, like 'Klingon bitmaps are ugly'.");
		    break;
		  case 2:
		    new_warning(UNDEF,"First Officer:  laws of the universe, like 'all admirals have scummed'.");
		    break;
		  case 3:
		    new_warning(UNDEF,"First Officer:  laws of the universe, like 'Mucus Pig exists'.");
		    break;
		  case 4:
		    new_warning(UNDEF,"First Officer:  laws of the universe, like 'guests advance 5x faster'.");
		    break;
		}
		break;
	    }
	}
    }

    /* give certain information about bombing or beaming */
    if (me->p_flags & PFBOMB) {
	if (planets[me->p_planet].pl_armies < 5) {
	    new_warning(UNDEF, "Weapons Officer: Bombarding %s... Ineffective, %d armies left.",
			planets[me->p_planet].pl_name,    /* Planet name for stats 10/20/96 [007] */
		    planets[me->p_planet].pl_armies); /* nifty info feature 2/14/92 TMC */
	    me->p_flags &= ~PFBOMB;
	}
	else {
	    new_warning(UNDEF, "Weapons Officer: Bombarding %s...  Sensors read %d armies left.",
		planets[me->p_planet].pl_name,
		planets[me->p_planet].pl_armies);
	}
    }

    /* Use person observed for kills if we are an observer */
    if (Observer && (me->p_flags & PFPLOCK))
        pl = &players[me->p_playerl];
    else
        pl = me;	/* Not observer, just use my kills */

    troop_capacity = (int)((float)((int)(pl->p_kills*100)/100.0) * (myship->s_type == ASSAULT?3:2));
    if (myship->s_type == STARBASE || troop_capacity > myship->s_maxarmies)
    	troop_capacity = myship->s_maxarmies;

    if (me->p_flags & PFBEAMUP) {
        /* Messages rewritten for stats 10/20/96 [007] */
        char *txt;
	if (me->p_flags & PFORBIT) {
	  if (planets[me->p_planet].pl_armies < 5) {
	    txt = "Too few armies to beam up";
	    me->p_flags &= ~PFBEAMUP;
	  } else if (me->p_armies == troop_capacity) {
	    txt = "No more room on board for armies";
	    me->p_flags &= ~PFBEAMUP;
	  } else {
	    txt = "Beaming up";
	  }
	  new_warning(UNDEF, "%s: (%d/%d) %s has %d armies left",
		      txt,
		      me->p_armies,
		      troop_capacity,
		      planets[me->p_planet].pl_name,	
		      planets[me->p_planet].pl_armies);
	    
	} else if (me->p_flags & PFDOCK) {
	    struct player *base = bay_owner(me);
	    if (base->p_armies <= 0) {
		txt = "Too few armies to beam up";
		me->p_flags &= ~PFBEAMUP;
	    } else if (me->p_armies >= troop_capacity) {
		txt = "No more room on board for armies";
		me->p_flags &= ~PFBEAMUP;
	    } else {
	        txt = "Beaming up";
	    }
	    new_warning(UNDEF, "%s: (%d/%d) Starbase %s has %d armies left",
			txt,
			me->p_armies,
			troop_capacity,
			base->p_name,
			base->p_armies);
	}
    }

    if (me->p_flags & PFBEAMDOWN) {
        /* Messages rewritten for stats 10/20/96 [007] */
        char *txt;
	if (me->p_flags & PFORBIT) {
	  if (me->p_armies == 0) {
	    txt = "No more armies to beam down";
	    me->p_flags &= ~PFBEAMDOWN;
	  } else {
	    txt = "Beaming down";
	  }
	  new_warning(UNDEF, "%s: (%d/%d) %s has %d armies left",
		      txt,
		      me->p_armies,
		      troop_capacity,
		      planets[me->p_planet].pl_name,	
		      planets[me->p_planet].pl_armies);

	} else if (me->p_flags & PFDOCK) {
	    struct player *base = bay_owner(me);
	    if (me->p_armies <= 0) {
		txt = "No more armies to beam down";
		me->p_flags &= ~PFBEAMDOWN;
	    } else if (base->p_armies >= base->p_ship.s_maxarmies) {
	        txt = "All troop bunkers are full";
	        me->p_flags &= ~PFBEAMDOWN;
	    } else {
	        txt = "Transfering ground units";
	    }
	    new_warning(UNDEF, "%s: (%d/%d) Starbase %s has %d armies left",
			txt,
			me->p_armies,
			troop_capacity,
			base->p_name,
			base->p_armies);
	}
    }

    if (me->p_flags & PFREPAIR) {
	if ((me->p_damage == 0) && (me->p_shield == me->p_ship.s_maxshield))
	    me->p_flags &= ~PFREPAIR;
    }
    if ((me->p_flags & PFPLOCK) && (!Observer)) { /* set course to player x */
	int dist;

	pl = &players[me->p_playerl];
	if (pl->p_status != PALIVE)
	    me->p_flags &= ~PFPLOCK;
	if (me->p_flags & PFTWARP){
	  if (pl->p_status != PALIVE){
	     new_warning(UNDEF, "Starbase is dead; Transwarp aborted!", -1);
	     me->p_flags &= ~PFTWARP;
	     me->p_speed = 3;
	     set_speed(0);
	  }
	  if (pl->p_ship.s_type != STARBASE){
	     new_warning(UNDEF, "Starbase has been turned in; Transwarp aborted!", -1);
	     me->p_flags &= ~PFTWARP;
	     me->p_speed = 3;
	     set_speed(0);
	  }
	  if(me->p_etemp > me->p_ship.s_maxegntemp - 10){
	     new_warning(UNDEF,"Warp drive reaching critical temperature!", -1);
	     me->p_flags &= ~PFTWARP;
	     me->p_speed = 3;
	     set_speed(0);
	  }
 	  else
	  if (me->p_fuel < (int) (me->p_ship.s_maxfuel/8)){
	     new_warning(UNDEF, "Not enough fuel to continue transwarp!", -1);
	     me->p_flags &= ~PFTWARP;
	     me->p_speed = 3;
	     set_speed(0);
	  }
	  else if(!(me->p_flags & PFPLOCK)){
	     new_warning(UNDEF, "Lost player lock!", -1);
	     me->p_flags &= ~PFTWARP;
	     me->p_speed = 3;
	     set_speed(0);
	  }
	}
	if (pl->p_ship.s_type == STARBASE) {
	    dist = hypot((double) (me->p_x - pl->p_x),
		(double) (me->p_y - pl->p_y));
	    if (!(me->p_flags & PFTWARP)) {
	        if (dist-(DOCKDIST/2) < (11500 * me->p_speed * me->p_speed) /
		        me->p_ship.s_decint) {
		    if (me->p_desspeed > 2) {
		        set_speed(me->p_desspeed-1);
		    }
	        }
	    }

	    if ((dist < 2*DOCKDIST) && (me->p_flags & PFTWARP)){
	        p_x_y_join(me, pl);
	        me->p_flags &= ~(PFPLOCK);
	        me->p_flags &= ~(PFTWARP);
#ifdef SB_CALVINWARP
                if (!(pl->p_flags & PFDOCKOK) ||
                    ((pl->p_flags & PFPRESS) &&
                     (pl->p_tractor == me->p_no))) ;
                else {
#endif

	            me->p_speed=2;
	            orbit();
#ifdef SB_CALVINWARP
                }
#endif
	    } else {
	        if ((dist < DOCKDIST) && (me->p_speed <= 2))  {
		    me->p_flags &= ~PFPLOCK;
		    orbit();
	        }
	    }
	}
	if (me->p_flags & PFPLOCK) {
	    course = newcourse(pl->p_x, pl->p_y);
	    if (me->p_flags & PFTWARP)
		me->p_dir = course;
	    else
	        set_course(course);
	}
    }
    if ((me->p_flags & PFPLLOCK) && (!Observer) ) { /* set course to planet */
	int dist;

	pln = &planets[me->p_planet];
	dist = hypot((double) (me->p_x - pln->pl_x),
	    (double) (me->p_y - pln->pl_y));

	/* This is magic.  It should be based on defines, but it slows
	   the ship down to warp two an appropriate distance from the
	   planet for orbit */

	if (dist-(ORBDIST/2) < (11500 * me->p_speed * me->p_speed) /
	        me->p_ship.s_decint) {
	    if (me->p_desspeed > 2) {
		set_speed(2);
	    }
	}

	if ((dist < ENTORBDIST) && (me->p_speed <= 2))  {
	    me->p_flags &= ~PFPLLOCK;
	    orbit();
	}
	else {
	    int ax, ay, ad, missing;
	    extern int nowobble;

	    /* calculate course to planet from current coordinates */
	    course = newcourse(pln->pl_x, pln->pl_y);

            /* avoid superfluous midflight wobble */
	    if (nowobble) {
	      /* test case; at 6 o'clock on earth, lock on altair, warp 8 */
	      /* calculate arrival point at current course */
	      ax = (double) (me->p_x + Cos[me->p_desdir] * dist);
	      ay = (double) (me->p_y + Sin[me->p_desdir] * dist);
	      ad = hypot((double) (ax - pln->pl_x),
			 (double) (ay - pln->pl_y));
	      
	      /* change to the corrected course if the expected error
		 exceeds the remaining distance divided by the nowobble
		 factor (25 works well) */
	      missing = (ad > dist / nowobble);
	      if (missing)
		set_course(course);
	    } else {
	      /* classical behaviour */
	      if ( (ABS(course-me->p_desdir) > 2) || (dist < ENTORBDIST*10) )
		set_course(course);
	    }
	}
    }
    /* Send ship cap if necessary */
    sndShipCap();

#ifdef STURGEON
    /* Check if eligible for free upgrade */
    if (sturgeon) {
        if (me->p_free_upgrade) {
            me->p_upgrades += baseupgradecost[me->p_free_upgrade] + me->p_upgradelist[me->p_free_upgrade]*adderupgradecost[me->p_free_upgrade];
            me->p_upgradelist[me->p_free_upgrade]++;
            sturgeon_apply_upgrade(me->p_free_upgrade, me, 1);
            me->p_free_upgrade = 0;
        }
    }
#endif
}