int setCourse(int crs_dir, int eng_type, int speed) { return set_course(crs_dir, eng_type, speed); }
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); } }
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 }