src/hcode/btech/autopilot_commands.c

Go to the documentation of this file.
00001 
00002 /*
00003  * $Id: autopilot.c,v 1.2 2005/08/03 21:40:54 av1-op Exp $
00004  *
00005  * Author: Markus Stenberg <fingon@iki.fi>
00006  *
00007  *  Copyright (c) 1996 Markus Stenberg
00008  *  Copyright (c) 1998-2002 Thomas Wouters
00009  *  Copyright (c) 2000-2002 Cord Awtry
00010  *       All rights reserved
00011  *
00012  * Created: Wed Oct 30 19:35:21 1996 fingon
00013  * Last modified: Sun Jun 14 14:13:13 1998 fingon
00014  *
00015  */
00016 
00017 #include <math.h>
00018 #include "mech.h"
00019 #include "mech.events.h"
00020 #include "autopilot.h"
00021 #include "create.h"
00022 #include "p.mech.startup.h"
00023 #include "p.econ.h"
00024 #include "p.econ_cmds.h"
00025 #include "p.mech.maps.h"
00026 #include "p.mech.utils.h"
00027 #include "p.eject.h"
00028 #include "p.btechstats.h"
00029 #include "p.bsuit.h"
00030 #include "p.mech.pickup.h"
00031 #include "p.mech.los.h"
00032 #include "p.ds.bay.h"
00033 #include "p.glue.h"
00034 
00035 /*
00036  * List of all the available autopilot commands
00037  * that can be given to the AI.  These use a
00038  * large enum that is located in autopilot.h
00039  */
00040 ACOM acom[AUTO_NUM_COMMANDS + 1] = {
00041         {"chasetarget", 1, GOAL_CHASETARGET, NULL}
00042         ,                                                       /* Extension of follow, for chasetarget */
00043         {"dumbfollow", 1, GOAL_DUMBFOLLOW, NULL}
00044         ,                                                       /* [dumbly] follow the given target */
00045         {"dumbgoto", 2, GOAL_DUMBGOTO, NULL}
00046         ,                                                       /* [dumbly] goto a given hex */
00047         {"enterbase", 1, GOAL_ENTERBASE, NULL}
00048         ,                                                       /* enterbase via <dir> */
00049         {"follow", 1, GOAL_FOLLOW, NULL}
00050         ,                                                       /* follow the given target */
00051         {"goto", 2, GOAL_GOTO, NULL}
00052         ,                                                       /* goto a given hex */
00053         {"leavebase", 1, GOAL_LEAVEBASE, NULL}
00054         ,                                                       /* leave a hangar */
00055         {"oldgoto", 2, GOAL_OLDGOTO, NULL}
00056         ,                                                       /* Old style goto - will phase out */
00057         {"roam", 1, GOAL_ROAM, NULL}
00058         ,                                                       /* roam around an area - like patroling */
00059         {"wait", 2, GOAL_WAIT, NULL}
00060         ,                                                       /* sit there and don't do anything for a while */
00061         {"attackleg", 1, COMMAND_ATTACKLEG, NULL}
00062         ,                                                       /* ? */
00063         {"autogun", 1, COMMAND_AUTOGUN, NULL}
00064         ,                                                       /* Let the AI decide what to shoot */
00065         {"chasemode", 1, COMMAND_CHASEMODE, NULL}
00066         ,                                                       /* chase after a target or not */
00067         {"cmode", 2, COMMAND_CMODE, NULL}
00068         ,                                                       /* ? */
00069         {"dropoff", 0, COMMAND_DROPOFF, NULL}
00070         ,                                                       /* dropoff whatever the AI is towing */
00071         {"embark", 1, COMMAND_EMBARK, NULL}
00072         ,                                                       /* embark a carrier */
00073         {"enterbay", 0, COMMAND_ENTERBAY, NULL}
00074         ,                                                       /* enter a DS's bay */
00075         {"jump", 1, COMMAND_JUMP, NULL}
00076         ,                                                       /* jump */
00077         {"load", 0, COMMAND_LOAD, NULL}
00078         ,                                                       /* load cargo */
00079         {"pickup", 1, COMMAND_PICKUP, NULL}
00080         ,                                                       /* pickup a given target */
00081         {"report", 0, COMMAND_REPORT, NULL}
00082         ,                                                       /* report current conditions */
00083         {"roammode", 1, COMMAND_ROAMMODE, NULL}
00084         ,                                                       /* more roam stuff */
00085         {"shutdown", 0, COMMAND_SHUTDOWN, NULL}
00086         ,                                                       /* shutdown the AI's unit */
00087         {"speed", 1, COMMAND_SPEED, NULL}
00088         ,                                                       /* set a given speed (% of max) */
00089         {"startup", 0, COMMAND_STARTUP, NULL}
00090         ,                                                       /* startup an AI's unit */
00091         {"stopgun", 0, COMMAND_STOPGUN, NULL}
00092         ,                                                       /* make the AI stop shooting stuff */
00093         {"swarm", 1, COMMAND_SWARM, NULL}
00094         ,                                                       /* ? */
00095         {"swarmmode", 1, COMMAND_SWARMMODE, NULL}
00096         ,                                                       /* ? */
00097         {"udisembark", 0, COMMAND_UDISEMBARK, NULL}
00098         ,                                                       /* disembark from a carrier */
00099         {"unload", 0, COMMAND_UNLOAD, NULL}
00100         ,                                                       /* unload cargo */
00101         {NULL, 0, AUTO_NUM_COMMANDS, NULL}
00102 };
00103 
00104 /* backwards compat till I can fix all of these */
00105 /* \todo {Get rid of these once we're done redoing the AI} */
00106 #define GSTART      AUTO_GSTART
00107 #define PSTART      AUTO_PSTART
00108 #define CCH         AUTO_CHECKS
00109 #define REDO        AUTO_COM
00110 
00111 /*
00112  * AI Startup - force AI to startup if its not
00113  */
00114 void auto_command_startup(AUTO * autopilot, MECH * mech)
00115 {
00116 
00117         if(Started(mech))
00118                 return;
00119 
00120         if(!Starting(mech)) {
00121                 mech_startup(autopilot->mynum, mech, "");
00122                 auto_goto_next_command(autopilot, AUTOPILOT_STARTUP_TICK);
00123         }
00124 
00125 }
00126 
00127 /*
00128  * AI Shutdown - force AI to shutdown if its not
00129  */
00130 void auto_command_shutdown(AUTO * autopilot, MECH * mech)
00131 {
00132 
00133         if(!Started(mech))
00134                 return;
00135 
00136         mech_shutdown(autopilot->mynum, mech, "");
00137 
00138 }
00139 
00140 #if 0
00141 
00143 void gradually_load(MECH * mech, int loc, int percent)
00144 {
00145         int pile[BRANDCOUNT + 1][NUM_ITEMS];
00146         float spd = (float) MMaxSpeed(mech);
00147         float nspd = (float) MechCargoMaxSpeed(mech, (float) spd);
00148         int cnt = 0;
00149         char *t;
00150         int i, j;
00151         int i1, i2, i3;
00152         int lastid = -1, lastbrand = -1;
00153 
00154         /* XXX Fix this - was broken when CargoMaxSpeed interface changed */
00155         bzero(pile, sizeof(pile));
00156         t = silly_atr_get(loc, A_ECONPARTS);
00157         while (*t) {
00158                 if(*t == '[')
00159                         if((sscanf(t, "[%d,%d,%d]", &i1, &i2, &i3)) == 3) {
00160                                 pile[i2][i1] += i3;
00161                                 cnt++;
00162                         }
00163                 t++;
00164         }
00165         while (nspd > ((float) spd * percent / 100) && cnt) {
00166                 for(j = 0; j <= BRANDCOUNT; j++) {
00167                         for(i = 0; i < NUM_ITEMS; i++)
00168                                 if(pile[j][i])
00169                                         break;
00170                         if(i != NUM_ITEMS)
00171                                 break;
00172                 }
00173                 if(i == NUM_ITEMS)
00174                         break;
00175                 lastid = i;
00176                 lastbrand = j;
00177                 econ_change_items(loc, i, j, -1);
00178                 econ_change_items(mech->mynum, i, j, 1);
00179                 pile[j][i]--;
00180                 cnt--;
00181                 SetCargoWeight(mech);
00182                 nspd = (float) MechCargoMaxSpeed(mech, (float) spd);
00183         }
00184         if(lastid >= 0) {
00185                 i = lastid;
00186                 j = lastbrand;
00187                 econ_change_items(loc, i, j, 1);
00188                 econ_change_items(mech->mynum, i, j, -1);
00189         }
00190         SetCargoWeight(mech);
00191 }
00192 
00193 void autopilot_load_cargo(dbref player, MECH * mech, int percent)
00194 {
00195         DOCHECK(fabs(MechSpeed(mech)) > MP1, "You're moving too fast!");
00196         DOCHECK(Location(mech->mynum) != mech->mapindex ||
00197                         In_Character(Location(mech->mynum)), "You aren't inside hangar!");
00198         if(loading_bay_whine(player, Location(mech->mynum), mech))
00199                 return;
00200         gradually_load(mech, mech->mapindex, percent);
00201         SetCargoWeight(mech);
00202 }
00203 #endif
00204 
00205 /* Recal the AI to the proper map */
00207 void auto_cal_mapindex(MECH * mech)
00208 {
00209 
00210         AUTO *autopilot;
00211         char error_buf[MBUF_SIZE];
00212 
00213         if(!mech) {
00214                 SendError("Null pointer catch in auto_cal_mapindex");
00215                 return;
00216         }
00217 
00218         if(MechAuto(mech) > 0) {
00219                 if(!(autopilot = FindObjectsData(MechAuto(mech))) ||
00220                    !Good_obj(MechAuto(mech)) ||
00221                    Location(MechAuto(mech)) != mech->mynum) {
00222                         snprintf(error_buf, MBUF_SIZE,
00223                                          "Mech #%d thinks it has the Autopilot #%d on it"
00224                                          " but FindObj breaks", mech->mynum, MechAuto(mech));
00225                         SendError(error_buf);
00226                         MechAuto(mech) = -1;
00227                 } else {
00228 
00229                         /* Check here if the AI is either entering or leaving a base
00230                          * so it doesn't reset the mapindex which the specific commands
00231                          * need */
00232                         switch (auto_get_command_enum(autopilot, 1)) {
00233 
00234                         case GOAL_LEAVEBASE:
00235                                 break;
00236                         case GOAL_ENTERBASE:
00237                                 break;
00238                         default:
00239                                 autopilot->mapindex = mech->mapindex;
00240                         }
00241 
00242                 }
00243         }
00244         return;
00245 }
00246 
00247 /*
00248  * Function to turn chasetarget on/off as well as let the AI
00249  * remember that it was on.
00250  *
00251  * Figured this was easier then coding a bunch of blocks of
00252  * stuff all over the place.
00253  */
00254 void auto_set_chasetarget_mode(AUTO * autopilot, int mode)
00255 {
00256 
00257         /* Depending on the mode we do different things */
00258         switch (mode) {
00259 
00260         case AUTO_CHASETARGET_ON:
00261 
00262                 /* Start Chasing */
00263                 if(!ChasingTarget(autopilot))
00264                         StartChasingTarget(autopilot);
00265 
00266                 /* Reset this flag because we don't need it set */
00267                 if(WasChasingTarget(autopilot))
00268                         ForgetChasingTarget(autopilot);
00269 
00270                 /* Flags to reset */
00271                 autopilot->chase_target = -10;
00272                 autopilot->chasetarg_update_tick = AUTOPILOT_CHASETARG_UPDATE_TICK;
00273 
00274                 break;
00275 
00276         case AUTO_CHASETARGET_OFF:
00277 
00278                 /* Stop Chasing */
00279                 if(ChasingTarget(autopilot))
00280                         StopChasingTarget(autopilot);
00281 
00282                 /* Reset this flag because we don't need it set */
00283                 if(WasChasingTarget(autopilot))
00284                         ForgetChasingTarget(autopilot);
00285 
00286                 break;
00287 
00288         case AUTO_CHASETARGET_REMEMBER:
00289 
00290                 /* If we we had chasetarget on - turn it back on */
00291                 if(WasChasingTarget(autopilot)) {
00292 
00293                         /* Start chasing */
00294                         if(!ChasingTarget(autopilot))
00295                                 StartChasingTarget(autopilot);
00296 
00297                         /* Reset the values */
00298                         autopilot->chase_target = -10;
00299                         autopilot->chasetarg_update_tick =
00300                                 AUTOPILOT_CHASETARG_UPDATE_TICK;
00301 
00302                         /* Unset the flag because we don't need it now */
00303                         ForgetChasingTarget(autopilot);
00304 
00305                 }
00306 
00307                 break;
00308 
00309         case AUTO_CHASETARGET_SAVE:
00310 
00311                 /* If we are chasing a target turn this off 
00312                  * but save it */
00313                 if(ChasingTarget(autopilot)) {
00314 
00315                         StopChasingTarget(autopilot);
00316                         RememberChasingTarget(autopilot);
00317 
00318                 }
00319 
00320                 break;
00321 
00322         }
00323 
00324 }
00325 
00326 #if 0
00327 void autopilot_cmode(AUTO * a, MECH * mech, int mode, int range)
00328 {
00329         static char buf[MBUF_SIZE];
00330         if(!a || !mech)
00331                 return;
00332         if(mode < 0 || mode > 2)
00333                 return;
00334         if(range < 0 || range > 40)
00335                 return;
00336         a->auto_cdist = range;
00337         a->auto_cmode = mode;
00338         return;
00339 
00340 }
00341 
00342 void autopilot_swarm(MECH * mech, char *id)
00343 {
00344         if(MechType(mech) == CLASS_BSUIT)
00345                 bsuit_swarm(GOD, mech, id);
00346 }
00347 
00348 void autopilot_attackleg(MECH * mech, char *id)
00349 {
00350         bsuit_attackleg(GOD, mech, id);
00351 }
00352 
00353 #endif
00354 
00355 /*
00356  * Interface to the autogun system
00357  * Even tho it takes 1 argument, we will parse that
00358  * 1 argument looking for pieces.
00359  */
00360 void auto_command_autogun(AUTO * autopilot, MECH * mech)
00361 {
00362 
00363         dbref target_dbref;
00364         MECH *target;
00365         char *argument;
00366         char error_buf[MBUF_SIZE];
00367         char *args[AUTOPILOT_MAX_ARGS - 1];
00368         int argc;
00369         int i;
00370 
00371         /* Read in the argument */
00372         argument = auto_get_command_arg(autopilot, 1, 1);
00373 
00374         /* Parse the argument */
00375         argc = proper_explodearguments(argument, args, AUTOPILOT_MAX_ARGS - 1);
00376 
00377         /* Free the argument */
00378         free(argument);
00379 
00380         /* Now we check to see how many arguments it found */
00381         if(argc == 1) {
00382 
00383                 /* Ok its either going to be on or off */
00384                 if(strcmp(args[0], "on") == 0) {
00385 
00386                         /* Reset the AI parameters */
00387                         autopilot->target = -1;
00388                         autopilot->target_score = 0;
00389                         autopilot->target_update_tick = AUTO_GUN_UPDATE_TICK;
00390 
00391                         /* Check if assigned target flag on */
00392                         if(AssignedTarget(autopilot)) {
00393                                 UnassignTarget(autopilot);
00394                         }
00395 
00396                         /* Get the AI going */
00397                         AUTO_GSTART(autopilot, mech);
00398 
00399                         if(Gunning(autopilot)) {
00400                                 DoStopGun(autopilot);
00401                         }
00402 
00403                         DoStartGun(autopilot);
00404 
00405                 } else if(strcmp(args[0], "off") == 0) {
00406 
00407                         /* Reset the target */
00408                         autopilot->target = -2;
00409                         autopilot->target_score = 0;
00410                         autopilot->target_update_tick = 0;
00411 
00412                         /* Check if Assigned Target Flag on */
00413                         if(AssignedTarget(autopilot)) {
00414                                 UnassignTarget(autopilot);
00415                         }
00416 
00417                         if(Gunning(autopilot)) {
00418                                 DoStopGun(autopilot);
00419                         }
00420 
00421                 } else {
00422 
00423                         /* Invalid command */
00424                         snprintf(error_buf, MBUF_SIZE, "AI Error - AI #%d given bad"
00425                                          " argument for autogun command", autopilot->mynum);
00426                         SendAI(error_buf);
00427 
00428                 }
00429 
00430         } else if(argc == 2) {
00431 
00432                 /* Check for 'target' */
00433                 if(strcmp(args[0], "target") == 0) {
00434 
00435                         /* Read in the 2nd argument - the target */
00436                         if(Readnum(target_dbref, args[1])) {
00437 
00438                                 /* Invalid command */
00439                                 snprintf(error_buf, MBUF_SIZE, "AI Error - AI #%d given bad"
00440                                                  " argument for autogun command", autopilot->mynum);
00441                                 SendAI(error_buf);
00442 
00443                                 /* Free Args */
00444                                 for(i = 0; i < AUTOPILOT_MAX_ARGS - 1; i++) {
00445                                         if(args[i])
00446                                                 free(args[i]);
00447                                 }
00448 
00449                                 return;
00450                         }
00451 
00452                         /* Now see if its a mech */
00453                         if(!(target = getMech(target_dbref))) {
00454 
00455                                 snprintf(error_buf, MBUF_SIZE, "AI Error - AI #%d given bad"
00456                                                  " target for autogun command", autopilot->mynum);
00457                                 SendAI(error_buf);
00458 
00459                                 /* Free Args */
00460                                 for(i = 0; i < AUTOPILOT_MAX_ARGS - 1; i++) {
00461                                         if(args[i])
00462                                                 free(args[i]);
00463                                 }
00464 
00465                                 return;
00466                         }
00467 
00468                         /* Ok valid unit so lets lock it and setup parameters */
00469                         autopilot->target = target_dbref;
00470                         autopilot->target_score = 0;
00471                         autopilot->target_update_tick = 0;
00472 
00473                         /* Set the Assigned Flag */
00474                         if(!AssignedTarget(autopilot)) {
00475                                 AssignTarget(autopilot);
00476                         }
00477 
00478                         /* Get the AI going */
00479                         AUTO_GSTART(autopilot, mech);
00480 
00481                         if(Gunning(autopilot)) {
00482                                 DoStopGun(autopilot);
00483                         }
00484 
00485                         DoStartGun(autopilot);
00486 
00487                 } else {
00488 
00489                         /* Invalid command */
00490                         snprintf(error_buf, MBUF_SIZE, "AI Error - AI #%d given bad"
00491                                          " argument for autogun command", autopilot->mynum);
00492                         SendAI(error_buf);
00493 
00494                 }
00495 
00496         }
00497 
00498         /* Free Args */
00499         for(i = 0; i < AUTOPILOT_MAX_ARGS - 1; i++) {
00500                 if(args[i])
00501                         free(args[i]);
00502         }
00503 
00504 }
00505 
00506 /*
00507  * Command to interface between chasetarget and follow
00508  */
00509 void auto_command_chasetarget(AUTO * autopilot)
00510 {
00511 
00512         /* Fire off follow event */
00513         AUTOEVENT(autopilot, EVENT_AUTOFOLLOW, auto_astar_follow_event,
00514                           AUTOPILOT_FOLLOW_TICK, 1);
00515 
00516         return;
00517 }
00518 
00519 /*
00520  * Command to try to get AI to pickup a target
00521  */
00522 void auto_command_pickup(AUTO * autopilot, MECH * mech)
00523 {
00524 
00525         char *argument;
00526         int target;
00527         char error_buf[MBUF_SIZE];
00528         char buf[SBUF_SIZE];
00529         MECH *tempmech;
00530 
00533         /* Read in the argument */
00534         argument = auto_get_command_arg(autopilot, 1, 1);
00535         if(Readnum(target, argument)) {
00536 
00537                 snprintf(error_buf, MBUF_SIZE, "AI Error - AI #%d given bad"
00538                                  " argument for pickup command", autopilot->mynum);
00539                 SendAI(error_buf);
00540                 free(argument);
00541                 return;
00542 
00543         }
00544         free(argument);
00545 
00546         /* Check the target */
00547         if(!(tempmech = getMech(target))) {
00548                 snprintf(error_buf, MBUF_SIZE, "AI Error - AI #%d unable to pickup"
00549                                  " unit #%d", autopilot->mynum, target);
00550                 SendAI(error_buf);
00551                 return;
00552         }
00553 
00554         /* Now try and pick it up */
00555         strcpy(buf, MechIDS(tempmech, 1));
00556         mech_pickup(GOD, mech, buf);
00557 
00561 }
00562 
00563 /*
00564  * Tell AI to drop whatever they're carrying
00565  */
00566 void auto_command_dropoff(MECH * mech)
00567 {
00568         mech_dropoff(GOD, mech, NULL);
00569 }
00570 
00571 /*
00572  * Tell AI to set its speed (in %)
00573  */
00574 void auto_command_speed(AUTO * autopilot)
00575 {
00576 
00577         char *argument;
00578         unsigned short speed;
00579         char error_buf[MBUF_SIZE];
00580 
00581         /* Read in the argument */
00582         argument = auto_get_command_arg(autopilot, 1, 1);
00583         if(Readnum(speed, argument)) {
00584 
00585                 snprintf(error_buf, MBUF_SIZE, "AI Error - AI #%d given bad"
00586                                  " argument for speed command", autopilot->mynum);
00587                 SendAI(error_buf);
00588                 free(argument);
00589                 return;
00590 
00591         }
00592         free(argument);
00593 
00594         /* Make sure its a valid speed value */
00595         if(speed < 1 || speed > 100) {
00596 
00597                 snprintf(error_buf, MBUF_SIZE, "AI Error - AI #%d given bad"
00598                                  " argument for speed command - out side of the range",
00599                                  autopilot->mynum);
00600                 SendAI(error_buf);
00601                 return;
00602 
00603         }
00604 
00605         /* Now set it */
00606         autopilot->speed = speed;
00607 
00608 }
00609 
00610 /*
00611  * Command to get AI to embark a carrier
00612  */
00613 void auto_command_embark(AUTO * autopilot, MECH * mech)
00614 {
00615 
00616         char *argument;
00617         int target;
00618         char error_buf[MBUF_SIZE];
00619         char buf[SBUF_SIZE];
00620         MECH *tempmech;
00621 
00622         /* Make sure the mech is on and standing */
00623         AUTO_GSTART(autopilot, mech);
00624 
00625         /* Read in the argument */
00626         argument = auto_get_command_arg(autopilot, 1, 1);
00627         if(Readnum(target, argument)) {
00628 
00629                 snprintf(error_buf, MBUF_SIZE, "AI Error - AI #%d given bad"
00630                                  " argument for embark command", autopilot->mynum);
00631                 SendAI(error_buf);
00632                 free(argument);
00633                 return;
00634 
00635         }
00636         free(argument);
00637 
00638         /* Check the target */
00639         if(!(tempmech = getMech(target))) {
00640                 snprintf(error_buf, MBUF_SIZE, "AI Error - AI #%d unable to embark"
00641                                  " unit #%d", autopilot->mynum, target);
00642                 SendAI(error_buf);
00643                 return;
00644         }
00645 
00646         strcpy(buf, MechIDS(tempmech, 1));
00647         mech_embark(GOD, mech, buf);
00648 
00649 }
00650 
00651 /*
00652  * Function to force AI to disembark a carrier
00653  */
00654 void auto_command_udisembark(MECH * mech)
00655 {
00656 
00657         dbref pil = -1;
00658         char *buf;
00659 
00660         buf = silly_atr_get(mech->mynum, A_PILOTNUM);
00661         sscanf(buf, "#%d", &pil);
00662         mech_udisembark(pil, mech, "");
00663 
00664 }
00665 
00666 #if 0
00667 void autopilot_enterbase(MECH * mech, int dir)
00668 {
00669         static char strng[2];
00670 
00671         switch (dir) {
00672         case 0:
00673                 strcpy(strng, "n");
00674                 break;
00675         case 1:
00676                 strcpy(strng, "e");
00677                 break;
00678         case 2:
00679                 strcpy(strng, "s");
00680                 break;
00681         case 3:
00682                 strcpy(strng, "w");
00683                 break;
00684         default:
00685                 sprintf(strng, "%c", dir);
00686                 break;
00687         }
00688         mech_enterbase(GOD, mech, strng);
00689 }
00690 #endif
00691 
00692 /*
00693  * Main Autopilot event, checks to see what command we should
00694  * be running and tries to run it
00695  */
00696 void auto_com_event(MUXEVENT * muxevent)
00697 {
00698 
00699         AUTO *autopilot = (AUTO *) muxevent->data;
00700         MECH *mech = autopilot->mymech;
00701         MECH *tempmech;
00702         char buf[SBUF_SIZE];
00703         int i, j, t;
00704 
00705         command_node *command;
00706 
00707         /* No mech and/or no AI */
00708         if(!IsMech(mech->mynum) || !IsAuto(autopilot->mynum))
00709                 return;
00710 
00711         /* Make sure the map exists */
00712         if(!(FindObjectsData(mech->mapindex))) {
00713                 autopilot->mapindex = mech->mapindex;
00714                 PilZombify(autopilot);
00715                 /*
00716                    if (GVAL(a, 0) != COMMAND_UDISEMBARK && GVAL(a, 0) != GOAL_WAIT)
00717                    return;
00718                  */
00719                 if(auto_get_command_enum(autopilot, 1) != COMMAND_UDISEMBARK)
00720                         return;
00721         }
00722 
00723         /* Set the MAP on the AI */
00724         if(autopilot->mapindex < 0)
00725                 autopilot->mapindex = mech->mapindex;
00726 
00727         /* Basic Checks */
00728         AUTO_CHECKS(autopilot);
00729 
00730         /* Get the enum value for the FIRST command */
00731         switch (auto_get_command_enum(autopilot, 1)) {
00732 
00733                 /* First check the various GOALs then the COMMANDs */
00734         case GOAL_CHASETARGET:
00735                 auto_command_chasetarget(autopilot);
00736                 return;
00737         case GOAL_DUMBGOTO:
00738                 AUTOEVENT(autopilot, EVENT_AUTOGOTO, auto_dumbgoto_event,
00739                                   AUTOPILOT_GOTO_TICK, 0);
00740                 return;
00741         case GOAL_DUMBFOLLOW:
00742                 AUTOEVENT(autopilot, EVENT_AUTOFOLLOW, auto_dumbfollow_event,
00743                                   AUTOPILOT_FOLLOW_TICK, 0);
00744                 return;
00745 
00746         case GOAL_ENTERBASE:
00747                 AUTOEVENT(autopilot, EVENT_AUTOENTERBASE, auto_enter_event,
00748                                   AUTOPILOT_NC_DELAY, 1);
00749                 return;
00750 
00751         case GOAL_FOLLOW:
00752                 AUTOEVENT(autopilot, EVENT_AUTOFOLLOW, auto_astar_follow_event,
00753                                   AUTOPILOT_FOLLOW_TICK, 1);
00754                 return;
00755 
00756         case GOAL_GOTO:
00757                 AUTOEVENT(autopilot, EVENT_AUTOGOTO, auto_astar_goto_event,
00758                                   AUTOPILOT_GOTO_TICK, 1);
00759                 return;
00760 
00761         case GOAL_LEAVEBASE:
00762                 AUTOEVENT(autopilot, EVENT_AUTOLEAVE, auto_leave_event,
00763                                   AUTOPILOT_LEAVE_TICK, 1);
00764                 return;
00765 
00766         case GOAL_OLDGOTO:
00767                 AUTO_GSTART(autopilot, mech);
00768                 AUTOEVENT(autopilot, EVENT_AUTOGOTO, auto_goto_event,
00769                                   AUTOPILOT_GOTO_TICK, 0);
00770                 return;
00771 
00772         case GOAL_ROAM:
00773                 auto_command_roam(autopilot, mech);
00774                 return;
00775 
00776 #if 0
00777         case GOAL_WAIT:
00778                 i = GVAL(a, 1);
00779                 j = GVAL(a, 2);
00780                 if(!i) {
00781                         PG(a) += CCLEN(a);
00782                         AUTOEVENT(a, EVENT_AUTOCOM, auto_com_event, MAX(1, j), 0);
00783                 } else {
00784                         if(i == 1) {
00785                                 if(MechNumSeen(mech)) {
00786                                         ADVANCE_PG(a);
00787                                 } else {
00788                                         AUTOEVENT(a, EVENT_AUTOCOM, auto_com_event,
00789                                                           AUTOPILOT_WAITFOE_TICK, 0);
00790                                 }
00791                         } else {
00792                                 ADVANCE_PG(a);
00793                         }
00794                 }
00795                 return;
00796 #endif
00797 #if 0
00798         case COMMAND_ATTACKLEG:
00799                 if(!(tempmech = getMech(GVAL(a, 1)))) {
00800                         SendAI(tprintf("AIAttacklegError #%d", GVAL(a, 1)));
00801                         //ADVANCE_PG(a);
00802                         auto_goto_next_command(a);
00803                         return;
00804                 }
00805                 strcpy(buf, MechIDS(tempmech, 1));
00806                 autopilot_attackleg(mech, buf);
00807                 //ADVANCE_PG(a);
00808                 auto_goto_next_command(a);
00809                 return;
00810 #endif
00811 
00812         case COMMAND_AUTOGUN:
00813                 auto_command_autogun(autopilot, mech);
00814                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
00815                 break;
00816 
00817 #if 0
00818         case COMMAND_CHASEMODE:
00819                 if(GVAL(a, 1))
00820                         a->flags |= AUTOPILOT_CHASETARG;
00821                 else
00822                         a->flags &= ~AUTOPILOT_CHASETARG;
00823                 //ADVANCE_PG(a);
00824                 auto_goto_next_command(a);
00825                 return;
00826 #endif
00827 #if 0
00828         case COMMAND_CMODE:
00829                 i = GVAL(a, 1);
00830                 j = GVAL(a, 2);
00831                 autopilot_cmode(a, mech, i, j);
00832                 //ADVANCE_PG(a);
00833                 auto_goto_next_command(a);
00834                 return;
00835 #endif
00836 
00837         case COMMAND_DROPOFF:
00838                 auto_command_dropoff(mech);
00839                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
00840                 return;
00841 
00842         case COMMAND_EMBARK:
00843                 auto_command_embark(autopilot, mech);
00844                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
00845                 return;
00846 
00847 #if 0
00848         case COMMAND_ENTERBAY:
00849                 PSTART(a, mech);
00850                 mech_enterbay(GOD, mech, my2string(""));
00851                 //ADVANCE_PG(a);
00852                 auto_goto_next_command(a);
00853                 return;
00854 #endif
00855 #if 0
00856         case COMMAND_JUMP:
00857                 if(auto_valid_progline(a, GVAL(a, 1))) {
00858                         PG(a) = GVAL(a, 1);
00859                         AUTOEVENT(a, EVENT_AUTOCOM, auto_com_event,
00860                                           AUTOPILOT_NC_DELAY, 0);
00861                 } else {
00862                         ADVANCE_PG(a);
00863                 }
00864                 return;
00865 #endif
00866 #if 0
00867         case COMMAND_LOAD:
00868 /*          mech_loadcargo(GOD, mech, "50"); */
00869                 autopilot_load_cargo(GOD, mech, 50);
00870                 //ADVANCE_PG(a);
00871                 auto_goto_next_command(a);
00872                 break;
00873 #endif
00874         case COMMAND_PICKUP:
00875                 auto_command_pickup(autopilot, mech);
00876                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
00877                 return;
00878 #if 0
00879         case COMMAND_ROAMMODE:
00880                 t = a->flags;
00881                 if(GVAL(a, 1)) {
00882                         a->flags |= AUTOPILOT_ROAMMODE;
00883                         if(!(t & AUTOPILOT_ROAMMODE)) {
00884                                 if(MechType(mech) == CLASS_BSUIT)
00885                                         a->flags |= AUTOPILOT_SWARMCHARGE;
00886                                 auto_addcommand(a->mynum, a, tprintf("roam 0 0"));
00887                         }
00888                 } else {
00889                         a->flags &= ~AUTOPILOT_ROAMMODE;
00890                 }
00891                 //ADVANCE_PG(a);
00892                 auto_goto_next_command(a);
00893                 return;
00894 #endif
00895         case COMMAND_SHUTDOWN:
00896                 auto_command_shutdown(autopilot, mech);
00897                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
00898                 return;
00899 
00900         case COMMAND_SPEED:
00901                 auto_command_speed(autopilot);
00902                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
00903                 return;
00904 
00905         case COMMAND_STARTUP:
00906                 auto_command_startup(autopilot, mech);
00907                 return;
00908 #if 0
00909         case COMMAND_STOPGUN:
00910                 if(Gunning(a))
00911                         DoStopGun(a);
00912                 //ADVANCE_PG(a);
00913                 auto_goto_next_command(a);
00914                 break;
00915 #endif
00916 #if 0
00917         case COMMAND_SWARM:
00918                 if(!(tempmech = getMech(GVAL(a, 1)))) {
00919                         SendAI(tprintf("AISwarmError #%d", GVAL(a, 1)));
00920                         //ADVANCE_PG(a);
00921                         auto_goto_next_command(a);
00922                         return;
00923                 }
00924                 strcpy(buf, MechIDS(tempmech, 1));
00925                 autopilot_swarm(mech, buf);
00926                 //ADVANCE_PG(a);
00927                 auto_goto_next_command(a);
00928                 return;
00929 #endif
00930 #if 0
00931         case COMMAND_SWARMMODE:
00932                 if(MechType(mech) != CLASS_BSUIT) {
00933                         //ADVANCE_PG(a);
00934                         auto_goto_next_command(a);
00935                         return;
00936                 }
00937                 if(GVAL(a, 1))
00938                         a->flags |= AUTOPILOT_SWARMCHARGE;
00939                 else
00940                         a->flags &= ~AUTOPILOT_SWARMCHARGE;
00941                 //ADVANCE_PG(a);
00942                 auto_goto_next_command(a);
00943                 return;
00944 #endif
00945 
00946         case COMMAND_UDISEMBARK:
00947                 auto_command_udisembark(mech);
00948                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
00949                 return;
00950 
00951 #if 0
00952         case COMMAND_UNLOAD:
00953                 mech_unloadcargo(GOD, mech, my2string(" * 9999"));
00954                 //ADVANCE_PG(a);
00955                 auto_goto_next_command(a);
00956                 break;
00957 #endif
00958         }
00959 }
00960 
00963 /*
00964  * Function to force the AI to move if its not near its target
00965  */
00966 static void speed_up_if_neccessary(AUTO * a, MECH * mech, int tx, int ty,
00967                                                                    int bearing)
00968 {
00969 
00970         if(bearing < 0 || abs((int) MechDesiredSpeed(mech)) < 2)
00971                 if(bearing < 0 || abs(bearing - MechFacing(mech)) <= 30)
00972                         if(MechX(mech) != tx || MechY(mech) != ty) {
00973                                 ai_set_speed(mech, a, MMaxSpeed(mech));
00974                         }
00975 }
00976 
00977 /*
00978  * Quick function to change the AI's heading to the current
00979  * bearing of its target
00980  */
00981 static void update_wanted_heading(AUTO * a, MECH * mech, int bearing)
00982 {
00983 
00984         if(MechDesiredFacing(mech) != bearing)
00985                 mech_heading(a->mynum, mech, tprintf("%d", bearing));
00986 
00987 }
00988 
00989 /*
00990  * Slow down the AI if its close to its target hex
00991  */
00993 static int slow_down_if_neccessary(AUTO * a, MECH * mech, float range,
00994                                                                    int bearing, int tx, int ty)
00995 {
00996 
00997         if(range < 0)
00998                 range = 0;
00999         if(range > 2.0)
01000                 return 0;
01001         if(abs(bearing - MechFacing(mech)) > 30) {
01002                 /* Fix the bearing as well */
01003                 ai_set_speed(mech, a, 0);
01004                 update_wanted_heading(a, mech, bearing);
01005         } else if(tx == MechX(mech) && ty == MechY(mech)) {
01006                 ai_set_speed(mech, a, 0);
01007         } else {                                        /* slowdown */
01008                 ai_set_speed(mech, a, (float) (0.4 + range / 2.0) * MMaxSpeed(mech));
01009         }
01010         return 1;
01011 }
01012 
01013 /*
01014  * Quick calcualtion of range and bearing from mech to target
01015  * hex
01016  */
01017 void figure_out_range_and_bearing(MECH * mech, int tx, int ty,
01018                                                                   float *range, int *bearing)
01019 {
01020 
01021         float x, y;
01022 
01023         MapCoordToRealCoord(tx, ty, &x, &y);
01024         *bearing = FindBearing(MechFX(mech), MechFY(mech), x, y);
01025         *range = FindHexRange(MechFX(mech), MechFY(mech), x, y);
01026 }
01027 
01028 /* Basically, all we need to do is course correction now and then.
01029    In case we get disabled, we call for help now and then */
01030 /*
01031  * Old goto system - will phase it out
01032  */
01033 void auto_goto_event(MUXEVENT * e)
01034 {
01035 
01036         AUTO *autopilot = (AUTO *) e->data;
01037         int tx, ty;
01038         float dx, dy;
01039         MECH *mech = autopilot->mymech;
01040         float range;
01041         int bearing;
01042 
01043         char *argument;
01044 
01045         if(!IsMech(mech->mynum) || !IsAuto(autopilot->mynum))
01046                 return;
01047 
01048         /* Basic Checks */
01049         AUTO_CHECKS(autopilot);
01050 
01051         /* Make sure mech is started and standing */
01052         AUTO_GSTART(autopilot, mech);
01053 
01054         /* Get the first argument - x coord */
01055         argument = auto_get_command_arg(autopilot, 1, 1);
01056         if(Readnum(tx, argument)) {
01058                 free(argument);
01059         }
01060         free(argument);
01061 
01062         /* Get the second argument - y coord */
01063         argument = auto_get_command_arg(autopilot, 1, 2);
01064         if(Readnum(ty, argument)) {
01066                 free(argument);
01067         }
01068         free(argument);
01069 
01070         if(MechX(mech) == tx && MechY(mech) == ty && abs(MechSpeed(mech)) < 0.5) {
01071 
01072                 /* We've reached this goal! Time for next one. */
01073                 ai_set_speed(mech, autopilot, 0);
01074 
01075                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
01076                 return;
01077         }
01078 
01079         MapCoordToRealCoord(tx, ty, &dx, &dy);
01080         figure_out_range_and_bearing(mech, tx, ty, &range, &bearing);
01081         if(!slow_down_if_neccessary(autopilot, mech, range, bearing, tx, ty)) {
01082 
01083                 /* Use the AI */
01084                 if(ai_check_path(mech, autopilot, dx, dy, 0.0, 0.0))
01085                         AUTOEVENT(autopilot, EVENT_AUTOGOTO, auto_goto_event,
01086                                           AUTOPILOT_GOTO_TICK, 0);
01087 
01088         } else {
01089                 AUTOEVENT(autopilot, EVENT_AUTOGOTO, auto_goto_event,
01090                                   AUTOPILOT_GOTO_TICK, 0);
01091         }
01092 
01093 }
01094 
01095 #if 0
01096 /* ROAMMODE is a funky beast */
01097 void auto_roam_event(MUXEVENT * e)
01098 {
01099         AUTO *a = (AUTO *) e->data;
01100         int tx, ty;
01101         float dx, dy, range;
01102         MECH *mech = a->mymech;
01103         MAP *map;
01104         int bearing, i = 1, t;
01105 
01106         if(!IsMech(mech->mynum) || !IsAuto(a->mynum))
01107                 return;
01108 
01109         CCH(a);
01110         GSTART(a, mech);
01111         tx = GVAL(a, 1);
01112         ty = GVAL(a, 2);
01113 
01114         if(!mech || !(map = FindObjectsData(mech->mapindex))) {
01115                 return;
01116         }
01117 
01118         if(!(a->flags & AUTOPILOT_ROAMMODE) || MechTarget(mech) > 0) {
01119                 return;
01120         }
01121 
01122         if((tx == 0 && ty == 0) || e->data2 > 0 || (MechX(mech) == tx
01123                                                                                                 && MechY(mech) == ty
01124                                                                                                 && abs(MechSpeed(mech)) <
01125                                                                                                 0.5)) {
01126                 while (i) {
01127                         tx = BOUNDED(1, Number(20, map->map_width - 21),
01128                                                  map->map_width - 1);
01129                         ty = BOUNDED(1, Number(20, map->map_height - 21),
01130                                                  map->map_height - 1);
01131                         MapCoordToRealCoord(tx, ty, &dx, &dy);
01132                         t = GetRTerrain(map, tx, ty);
01133                         range = FindRange(MechFX(mech), MechFY(mech), MechFZ(mech),
01134                                                           dx, dy, ZSCALE * GetElev(map, tx, ty));
01135                         if((InLineOfSight(mech, NULL, tx, ty, range) &&
01136                                 t != WATER && t != HIGHWATER && t != MOUNTAINS) || i > 5000) {
01137                                 i = 0;
01138                         } else {
01139                                 i++;
01140                         }
01141                 }
01142                 a->commands[a->program_counter + 1] = tx;
01143                 a->commands[a->program_counter + 2] = ty;
01144                 AUTOEVENT(a, EVENT_AUTOGOTO, auto_roam_event, AUTOPILOT_GOTO_TICK, 0);
01145                 return;
01146         }
01147         MapCoordToRealCoord(tx, ty, &dx, &dy);
01148         figure_out_range_and_bearing(mech, tx, ty, &range, &bearing);
01149         if(!slow_down_if_neccessary(a, mech, range, bearing, tx, ty)) {
01150                 /* Use the AI */
01151                 if(ai_check_path(mech, a, dx, dy, 0.0, 0.0))
01152                         AUTOEVENT(a, EVENT_AUTOGOTO, auto_roam_event, AUTOPILOT_GOTO_TICK,
01153                                           0);
01154         } else {
01155                 AUTOEVENT(a, EVENT_AUTOGOTO, auto_roam_event, AUTOPILOT_GOTO_TICK, 0);
01156         }
01157 }
01158 #endif
01159 
01160 /*
01161  * Dumbly[goto] a given a hex
01162  */
01163 void auto_dumbgoto_event(MUXEVENT * muxevent)
01164 {
01165 
01166         AUTO *autopilot = (AUTO *) muxevent->data;
01167         int tx, ty;
01168         MECH *mech = autopilot->mymech;
01169         MAP *map;
01170         float range;
01171         int bearing;
01172 
01173         char *argument;
01174         char error_buf[MBUF_SIZE];
01175 
01176         if(!IsMech(mech->mynum) || !IsAuto(autopilot->mynum))
01177                 return;
01178 
01179         /* Are we in the mech we're supposed to be in */
01180         if(Location(autopilot->mynum) != autopilot->mymechnum)
01181                 return;
01182 
01183         /* Our mech is destroyed */
01184         if(Destroyed(mech))
01185                 return;
01186 
01187         /* Check to make sure the first command in the queue is this one */
01188         if(auto_get_command_enum(autopilot, 1) != GOAL_DUMBGOTO)
01189                 return;
01190 
01191         /* Get the Map */
01192         if(!(map = getMap(autopilot->mapindex))) {
01193 
01194                 /* Bad Map */
01195                 snprintf(error_buf, MBUF_SIZE, "Internal AI Error - Attempting to"
01196                                  " goto [dumbly] with AI #%d but AI is not on a valid"
01197                                  " Map (#%d).", autopilot->mynum, autopilot->mapindex);
01198                 SendAI(error_buf);
01199 
01200                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
01201                 return;
01202 
01203         }
01204 
01205         /* Make sure mech is started */
01206         if(!Started(mech)) {
01207 
01208                 /* Startup */
01209                 if(!Starting(mech))
01210                         auto_command_startup(autopilot, mech);
01211 
01212                 /* Run this command after startup */
01213                 AUTOEVENT(autopilot, EVENT_AUTOGOTO, auto_dumbgoto_event,
01214                                   AUTOPILOT_STARTUP_TICK, 0);
01215                 return;
01216         }
01217 
01218         /* Ok not standing so lets do that first */
01219         if(MechType(mech) == CLASS_MECH && Fallen(mech) &&
01220            !(CountDestroyedLegs(mech) > 0)) {
01221 
01222                 if(!Standing(mech))
01223                         mech_stand(autopilot->mynum, mech, "");
01224 
01225                 /* Ok lets run this command again */
01226                 AUTOEVENT(autopilot, EVENT_AUTOGOTO, auto_dumbgoto_event,
01227                                   AUTOPILOT_NC_DELAY, 0);
01228                 return;
01229         }
01230 
01233         /* Get the first argument - x coord */
01234         if(!(argument = auto_get_command_arg(autopilot, 1, 1))) {
01235 
01236                 /* Ok bad argument - means the command is messed up
01237                  * so should go to next one */
01238                 snprintf(error_buf, MBUF_SIZE, "Internal AI Error - Attempting to"
01239                                  " goto [dumbly] with AI #%d but was unable to - bad"
01240                                  " first argument - going to next command", autopilot->mynum);
01241                 SendAI(error_buf);
01242                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
01243                 return;
01244         }
01245 
01246         /* Read in the argument */
01247         if(Readnum(tx, argument)) {
01248 
01249                 snprintf(error_buf, MBUF_SIZE, "Internal AI Error - Attempting to"
01250                                  " goto [dumbly] with AI #%d but was unable to - bad"
01251                                  " first argument '%s' - going to next command",
01252                                  autopilot->mynum, argument);
01253                 SendAI(error_buf);
01254                 free(argument);
01255                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
01256                 return;
01257         }
01258         free(argument);
01259 
01260         /* Get the first argument - y coord */
01261         if(!(argument = auto_get_command_arg(autopilot, 1, 2))) {
01262 
01263                 /* Ok bad argument - means the command is messed up
01264                  * so should go to next one */
01265                 snprintf(error_buf, MBUF_SIZE, "Internal AI Error - Attempting to"
01266                                  " goto [dumbly] with AI #%d but was unable to - bad"
01267                                  " second argument - going to next command",
01268                                  autopilot->mynum);
01269                 SendAI(error_buf);
01270                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
01271                 return;
01272         }
01273 
01274         /* Read in the argument */
01275         if(Readnum(ty, argument)) {
01276 
01277                 snprintf(error_buf, MBUF_SIZE, "Internal AI Error - Attempting to"
01278                                  " goto [dumbly] with AI #%d but was unable to - bad"
01279                                  " second argument '%s' - going to next command",
01280                                  autopilot->mynum, argument);
01281                 SendAI(error_buf);
01282                 free(argument);
01283                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
01284                 return;
01285         }
01286         free(argument);
01287 
01288         /* If we're at the target hex - stop */
01289         if(MechX(mech) == tx && MechY(mech) == ty && abs(MechSpeed(mech)) < 0.5) {
01290 
01291                 /* We've reached this goal! Time for next one. */
01292                 ai_set_speed(mech, autopilot, 0);
01293 
01294                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
01295                 return;
01296         }
01297 
01298         /* Make our way to the goal */
01299         figure_out_range_and_bearing(mech, tx, ty, &range, &bearing);
01300         speed_up_if_neccessary(autopilot, mech, tx, ty, bearing);
01301         slow_down_if_neccessary(autopilot, mech, range, bearing, tx, ty);
01302         update_wanted_heading(autopilot, mech, bearing);
01303         AUTOEVENT(autopilot, EVENT_AUTOGOTO, auto_dumbgoto_event,
01304                           AUTOPILOT_GOTO_TICK, 0);
01305 }
01306 
01307 /*
01308  * The Astar goto event
01309  * Uses the A* (Astar) pathfinding method used
01310  * in common games to get the AI from point A
01311  * to point B
01312  */
01313 void auto_astar_goto_event(MUXEVENT * muxevent)
01314 {
01315 
01316         AUTO *autopilot = (AUTO *) muxevent->data;
01317         int tx, ty;
01318         MECH *mech = autopilot->mymech;
01319         MAP *map;
01320         float range;
01321         int bearing;
01322 
01323         int generate_path = (int) muxevent->data2;
01324 
01325         char *argument;
01326         astar_node *temp_astar_node;
01327 
01328         char error_buf[MBUF_SIZE];
01329 
01330         /* Make sure the mech is a mech and the autopilot is an autopilot */
01331         if(!IsMech(mech->mynum) || !IsAuto(autopilot->mynum))
01332                 return;
01333 
01334         /* Are we in the mech we're supposed to be in */
01335         if(Location(autopilot->mynum) != autopilot->mymechnum)
01336                 return;
01337 
01338         /* Our mech is destroyed */
01339         if(Destroyed(mech))
01340                 return;
01341 
01342         /* Check to make sure the first command in the queue is this one */
01343         if(auto_get_command_enum(autopilot, 1) != GOAL_GOTO)
01344                 return;
01345 
01346         /* Get the Map */
01347         if(!(map = getMap(autopilot->mapindex))) {
01348 
01349                 /* Bad Map */
01350                 snprintf(error_buf, MBUF_SIZE, "Internal AI Error - Attempting to"
01351                                  " goto with AI #%d but AI is not on a valid"
01352                                  " Map (#%d).", autopilot->mynum, autopilot->mapindex);
01353                 SendAI(error_buf);
01354 
01355                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
01356                 return;
01357 
01358         }
01359 
01360         /* Make sure mech is started and standing */
01361         if(!Started(mech)) {
01362 
01363                 /* Startup */
01364                 if(!Starting(mech))
01365                         auto_command_startup(autopilot, mech);
01366 
01367                 /* Run this command after startup */
01368                 AUTOEVENT(autopilot, EVENT_AUTOGOTO, auto_astar_goto_event,
01369                                   AUTOPILOT_STARTUP_TICK, generate_path);
01370                 return;
01371         }
01372 
01373         /* Ok not standing so lets do that first */
01374         if(MechType(mech) == CLASS_MECH && Fallen(mech) &&
01375            !(CountDestroyedLegs(mech) > 0)) {
01376 
01377                 if(!Standing(mech))
01378                         mech_stand(autopilot->mynum, mech, "");
01379 
01380                 /* Ok lets run this command again */
01381                 AUTOEVENT(autopilot, EVENT_AUTOGOTO, auto_astar_goto_event,
01382                                   AUTOPILOT_NC_DELAY, generate_path);
01383                 return;
01384         }
01385 
01388         /* Do we need to generate the path */
01389         if(generate_path) {
01390 
01391                 /* Get the first argument - x coord */
01392                 if(!(argument = auto_get_command_arg(autopilot, 1, 1))) {
01393 
01394                         /* Ok bad argument - means the command is messed up
01395                          * so should go to next one */
01396                         snprintf(error_buf, MBUF_SIZE, "Internal AI Error - Attempting to"
01397                                          " generate an astar path for AI #%d to hex %d,%d but was"
01398                                          " unable to - bad first argument - going to next command",
01399                                          autopilot->mynum, tx, ty);
01400                         SendAI(error_buf);
01401                         auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
01402                         return;
01403                 }
01404 
01405                 /* Now change it into a number and make sure its valid */
01406                 if(Readnum(tx, argument)) {
01407 
01408                         snprintf(error_buf, MBUF_SIZE, "Internal AI Error - Attempting to"
01409                                          " generate an astar path for AI #%d to hex %d,%d but was"
01410                                          " unable to - bad first argument '%s' - going to next command",
01411                                          autopilot->mynum, tx, ty, argument);
01412                         SendAI(error_buf);
01413 
01414                         free(argument);
01415                         auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
01416                         return;
01417                 }
01418                 free(argument);
01419 
01420                 /* Get the second argument - y coord */
01421                 if(!(argument = auto_get_command_arg(autopilot, 1, 2))) {
01422 
01423                         /* Ok bad argument - either means the command is messed up
01424                          * so should go to next one */
01425                         snprintf(error_buf, MBUF_SIZE, "Internal AI Error - Attempting to"
01426                                          " generate an astar path for AI #%d to hex %d,%d but was"
01427                                          " unable to - bad second argument - going to next command",
01428                                          autopilot->mynum, tx, ty);
01429                         SendAI(error_buf);
01430                         auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
01431                         return;
01432                 }
01433 
01434                 /* Read second argument into a number and make sure its ok */
01435                 if(Readnum(ty, argument)) {
01436 
01437                         snprintf(error_buf, MBUF_SIZE, "Internal AI Error - Attempting to"
01438                                          " generate an astar path for AI #%d to hex %d,%d but was"
01439                                          " unable to - bad second argument '%s' - going to next command",
01440                                          autopilot->mynum, tx, ty, argument);
01441                         SendAI(error_buf);
01442 
01443                         free(argument);
01444                         auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
01445                         return;
01446                 }
01447                 free(argument);
01448 
01449         /* Boundaries */
01450         if (tx < 0 || ty < 0 || tx >= map->map_width || ty >= map->map_width) {
01451 
01452             /* Bad location to go to */
01453             snprintf(error_buf, MBUF_SIZE, "Internal AI Error - Attempting to"
01454                     " generate an astar path for AI #%d to bad hex"
01455                     " (%d, %d)", autopilot->mynum, tx, ty);
01456             SendAI(error_buf);
01457             auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
01458             return;
01459         }
01460 
01461                 /* Look for a path */
01462                 if(!(auto_astar_generate_path(autopilot, mech, tx, ty))) {
01463 
01464                         /* Couldn't find a path for some reason */
01465                         snprintf(error_buf, MBUF_SIZE, "Internal AI Error - Attempting to"
01466                                          " generate an astar path for AI #%d to hex %d,%d but was"
01467                                          " unable to", autopilot->mynum, tx, ty);
01468                         SendAI(error_buf);
01469 
01472                         auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
01473                         return;
01474 
01475                 }
01476 
01477         }
01478 
01479         /* Make sure list is ok */
01480         if(!(autopilot->astar_path) || (dllist_size(autopilot->astar_path) <= 0)) {
01481 
01482                 snprintf(error_buf, MBUF_SIZE,
01483                                  "Internal AI Error - Attempting to follow"
01484                                  " Astar path for AI #%d - but the path is not there",
01485                                  autopilot->mynum);
01486                 SendAI(error_buf);
01487 
01488                 auto_destroy_astar_path(autopilot);
01489                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
01490                 return;
01491 
01492         }
01493 
01494         /* Get the current hex target */
01495         temp_astar_node =
01496                 (astar_node *) dllist_get_node(autopilot->astar_path, 1);
01497 
01498         if(!(temp_astar_node)) {
01499 
01500                 snprintf(error_buf, MBUF_SIZE,
01501                                  "Internal AI Error - Attemping to follow"
01502                                  " Astar path for AI #%d - but the current astar node does not"
01503                                  " exist", autopilot->mynum);
01504                 SendAI(error_buf);
01505 
01506                 auto_destroy_astar_path(autopilot);
01507                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
01508                 return;
01509 
01510         }
01511 
01512         /* Are we in the current target hex */
01513         if((MechX(mech) == temp_astar_node->x) &&
01514            (MechY(mech) == temp_astar_node->y)) {
01515 
01516                 /* Is this the last hex */
01517                 if(dllist_size(autopilot->astar_path) == 1) {
01518 
01519                         /* Done! */
01520                         ai_set_speed(mech, autopilot, 0);
01521 
01522                         /* Destroy the path and goto the next command */
01523                         auto_destroy_astar_path(autopilot);
01524                         auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
01525                         return;
01526 
01527                 } else {
01528 
01529                         /* Delete the node and goto the next one */
01530                         temp_astar_node =
01531                                 (astar_node *) dllist_remove_node_at_pos(autopilot->
01532                                                                                                                  astar_path, 1);
01533                         free(temp_astar_node);
01534 
01535                         /* Call this event again */
01536                         AUTOEVENT(autopilot, EVENT_AUTOGOTO, auto_astar_goto_event,
01537                                           AUTOPILOT_GOTO_TICK, 0);
01538                         return;
01539 
01540                 }
01541 
01542         }
01543 
01544         /* Set our current goal - not the end goal tho - unless this is
01545          * the end hex but whatever */
01546         tx = temp_astar_node->x;
01547         ty = temp_astar_node->y;
01548 
01549         /* Move towards our next hex */
01550         figure_out_range_and_bearing(mech, tx, ty, &range, &bearing);
01551         speed_up_if_neccessary(autopilot, mech, tx, ty, bearing);
01552         slow_down_if_neccessary(autopilot, mech, range, bearing, tx, ty);
01553         update_wanted_heading(autopilot, mech, bearing);
01554 
01555         AUTOEVENT(autopilot, EVENT_AUTOGOTO, auto_astar_goto_event,
01556                           AUTOPILOT_GOTO_TICK, 0);
01557 
01558 }
01559 
01560 /*
01561  * New follow system based on astar goto
01562  */
01563 void auto_astar_follow_event(MUXEVENT * muxevent)
01564 {
01565 
01566         AUTO *autopilot = (AUTO *) muxevent->data;
01567         MECH *mech = autopilot->mymech;
01568         MECH *target;
01569         MAP *map;
01570 
01571         dbref target_dbref;
01572 
01573         float range;
01574         float fx, fy;
01575         short x, y;
01576         int bearing;
01577         int destroy_path = (int) muxevent->data2;
01578 
01579         char *argument;
01580         astar_node *temp_astar_node;
01581 
01582         char error_buf[MBUF_SIZE];
01583 
01584         if(!IsMech(mech->mynum) || !IsAuto(autopilot->mynum))
01585                 return;
01586 
01587         /* Are we in the mech we're supposed to be in */
01588         if(Location(autopilot->mynum) != autopilot->mymechnum)
01589                 return;
01590 
01591         /* Our mech is destroyed */
01592         if(Destroyed(mech))
01593                 return;
01594 
01595         /* Check to make sure the first command in the queue is this one */
01596         switch (auto_get_command_enum(autopilot, 1)) {
01597 
01598         case GOAL_FOLLOW:
01599                 break;
01600         case GOAL_CHASETARGET:
01601                 break;
01602         default:
01603                 return;
01604         }
01605 
01606         /* Get the Map */
01607         if(!(map = getMap(autopilot->mapindex))) {
01608 
01609                 /* Bad Map */
01610                 snprintf(error_buf, MBUF_SIZE, "Internal AI Error - Attempting to"
01611                                  " follow with AI #%d but AI is not on a valid"
01612                                  " Map (#%d).", autopilot->mynum, autopilot->mapindex);
01613                 SendAI(error_buf);
01614 
01615                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
01616                 return;
01617 
01618         }
01619 
01620         /* Make sure mech is started and standing */
01621         if(!Started(mech)) {
01622 
01623                 /* Startup */
01624                 if(!Starting(mech))
01625                         auto_command_startup(autopilot, mech);
01626 
01627                 /* Run this command after startup */
01628                 AUTOEVENT(autopilot, EVENT_AUTOFOLLOW, auto_astar_follow_event,
01629                                   AUTOPILOT_STARTUP_TICK, destroy_path);
01630                 return;
01631         }
01632 
01633         /* Ok not standing so lets do that first */
01634         if(MechType(mech) == CLASS_MECH && Fallen(mech) &&
01635            !(CountDestroyedLegs(mech) > 0)) {
01636 
01637                 if(!Standing(mech))
01638                         mech_stand(autopilot->mynum, mech, "");
01639 
01640                 /* Ok lets run this command again */
01641                 AUTOEVENT(autopilot, EVENT_AUTOFOLLOW, auto_astar_follow_event,
01642                                   AUTOPILOT_NC_DELAY, destroy_path);
01643                 return;
01644         }
01645 
01648         /* Get the only argument - dbref of target */
01649         if(!(argument = auto_get_command_arg(autopilot, 1, 1))) {
01650 
01651                 /* Ok bad argument - means the command is messed up
01652                  * so should go to next one */
01653                 snprintf(error_buf, MBUF_SIZE, "Internal AI Error - AI #%d attempting"
01654                                  " to follow target but was unable to - bad argument - going"
01655                                  " to next command", autopilot->mynum);
01656                 SendAI(error_buf);
01657                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
01658                 return;
01659         }
01660 
01661         /* See if its a valid number */
01662         if(Readnum(target_dbref, argument)) {
01663 
01664                 snprintf(error_buf, MBUF_SIZE, "Internal AI Error - AI #%d attempting"
01665                                  " to follow target but was unable to - bad argument '%s' - going"
01666                                  " to next command", autopilot->mynum, argument);
01667                 SendAI(error_buf);
01668                 free(argument);
01669                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
01670                 return;
01671         }
01672         free(argument);
01673 
01674         /* Get the target */
01675         if(!(target = getMech(target_dbref))) {
01676 
01677                 /* Bad Target */
01678                 snprintf(error_buf, MBUF_SIZE, "Internal AI Error - Attempting to"
01679                                  " follow unit #%d with AI #%d but its not a valid unit.",
01680                                  target_dbref, autopilot->mynum);
01681                 SendAI(error_buf);
01682 
01683                 ai_set_speed(mech, autopilot, 0);
01684                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
01685                 return;
01686         }
01687 
01688         /* Is the target destroyed or we not even on the same map */
01689         if(Destroyed(target) || (target->mapindex != mech->mapindex)) {
01690 
01691                 snprintf(error_buf, MBUF_SIZE, "Internal AI Error - Attempting to"
01692                                  " follow unit #%d with AI #%d but it is either dead or"
01693                                  " not on the same map.", target_dbref, autopilot->mynum);
01694                 SendAI(error_buf);
01695 
01696                 ai_set_speed(mech, autopilot, 0);
01697                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
01698                 return;
01699         }
01700 
01701         /* Generate the target hex - since this can be altered by position command */
01702         FindXY(MechFX(target), MechFY(target),
01703                    MechFacing(target) + autopilot->ofsx, autopilot->ofsy, &fx, &fy);
01704 
01705         RealCoordToMapCoord(&x, &y, fx, fy);
01706 
01707         /* Make sure the hex is sane - if not set the target hex to the target's
01708          * hex */
01709         if(x < 0 || y < 0 || x >= map->map_width || y >= map->map_height) {
01710 
01711                 /* Reset the hex to the Target's current hex */
01712                 x = MechX(target);
01713                 y = MechY(target);
01714 
01715         }
01716 
01717         /* Are we in the target hex and the target isn't moving ? */
01718         if((MechX(mech) == x) && (MechY(mech) == y) && (MechSpeed(target) < 0.5)) {
01719 
01720                 /* Ok go into holding pattern */
01721                 ai_set_speed(mech, autopilot, 0.0);
01722 
01723                 /* Destroy the path so we can force the path to be generated if the
01724                  * target moves */
01725                 if(autopilot->astar_path) {
01726                         auto_destroy_astar_path(autopilot);
01727                 }
01728 
01729                 AUTOEVENT(autopilot, EVENT_AUTOFOLLOW, auto_astar_follow_event,
01730                                   AUTOPILOT_FOLLOW_TICK, 0);
01731                 return;
01732         }
01733 
01734         /* Destroy the path if we need to - this typically happens
01735          * if its the first run of the event */
01736         if(destroy_path) {
01737                 auto_destroy_astar_path(autopilot);
01738         }
01739 
01740         /* Do we need to generate the path - only switch paths if we don't have
01741          * one or if the ticker has gone high enough */
01742         if(!(autopilot->astar_path) ||
01743            autopilot->follow_update_tick >= AUTOPILOT_FOLLOW_UPDATE_TICK) {
01744 
01745                 /* Target hex is not target's hex */
01746                 if((x != MechX(mech)) || (y != MechY(mech))) {
01747 
01748                         /* Try and generate path with target hex */
01749                         if(!(auto_astar_generate_path(autopilot, mech, x, y))) {
01750 
01751                                 /* Didn't work so reset the x,y coords to target's hex
01752                                  * and try again */
01753                                 x = MechX(target);
01754                                 y = MechY(target);
01755 
01756                                 /* This is how we try again - reset the ticker and
01757                                  * it will try again */
01758                                 autopilot->follow_update_tick = AUTOPILOT_FOLLOW_UPDATE_TICK;
01759 
01760                         } else {
01761 
01762                                 /* Reset the ticker - found path */
01763                                 autopilot->follow_update_tick = 0;
01764 
01765                         }
01766 
01767                         if((autopilot->follow_update_tick != 0) &&
01768                            !(auto_astar_generate_path(autopilot, mech, x, y))) {
01769 
01770                                 /* Major failure - No path found */
01771                                 snprintf(error_buf, MBUF_SIZE,
01772                                                  "Internal AI Error - Attempting to"
01773                                                  " generate an astar path for AI #%d to hex %d,%d to follow"
01774                                                  " unit #%d, but was unable to.", autopilot->mynum, x,
01775                                                  y, target_dbref);
01776                                 SendAI(error_buf);
01777 
01780                                 ai_set_speed(mech, autopilot, 0);
01781                                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
01782                                 return;
01783 
01784                         } else {
01785 
01786                                 /* Path found */
01787                                 autopilot->follow_update_tick = 0;
01788                         }
01789 
01790                 } else {
01791 
01792                         /* Ok same hex so try and generate path */
01793                         if(!(auto_astar_generate_path(autopilot, mech, x, y))) {
01794 
01795                                 /* Couldn't find a path for some reason */
01796                                 snprintf(error_buf, MBUF_SIZE,
01797                                                  "Internal AI Error - Attempting to"
01798                                                  " generate an astar path for AI #%d to hex %d,%d to follow"
01799                                                  " unit #%d, but was unable to.", autopilot->mynum, x,
01800                                                  y, target_dbref);
01801                                 SendAI(error_buf);
01802 
01805                                 ai_set_speed(mech, autopilot, 0);
01806                                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
01807                                 return;
01808 
01809                         } else {
01810 
01811                                 /* Zero the ticker */
01812                                 autopilot->follow_update_tick = 0;
01813 
01814                         }
01815 
01816                 }
01817 
01818         }
01819 
01820         /* Make sure list is ok */
01821         if(!(autopilot->astar_path) || (dllist_size(autopilot->astar_path) <= 0)) {
01822 
01823                 snprintf(error_buf, MBUF_SIZE,
01824                                  "Internal AI Error - Attempting to follow"
01825                                  " Astar path for AI #%d - but the path is not there",
01826                                  autopilot->mynum);
01827                 SendAI(error_buf);
01828 
01829                 /* Destroy List */
01830                 auto_destroy_astar_path(autopilot);
01831                 ai_set_speed(mech, autopilot, 0);
01832                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
01833                 return;
01834 
01835         }
01836 
01837         /* Get the current hex target */
01838         temp_astar_node =
01839                 (astar_node *) dllist_get_node(autopilot->astar_path, 1);
01840 
01841         if(!(temp_astar_node)) {
01842 
01843                 snprintf(error_buf, MBUF_SIZE,
01844                                  "Internal AI Error - Attemping to follow"
01845                                  " Astar path for AI #%d - but the current astar node does not"
01846                                  " exist", autopilot->mynum);
01847                 SendAI(error_buf);
01848 
01849                 /* Destroy List */
01850                 auto_destroy_astar_path(autopilot);
01851                 ai_set_speed(mech, autopilot, 0);
01852                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
01853                 return;
01854 
01855         }
01856 
01857         /* Are we in the current target hex */
01858         if((MechX(mech) == temp_astar_node->x) &&
01859            (MechY(mech) == temp_astar_node->y)) {
01860 
01861                 /* Is this the last hex */
01862                 if(dllist_size(autopilot->astar_path) == 1) {
01863 
01864                         /* Done! */
01865                         ai_set_speed(mech, autopilot, 0);
01866                         auto_destroy_astar_path(autopilot);
01867 
01868                         /* Re-Run Follow */
01869                         AUTOEVENT(autopilot, EVENT_AUTOFOLLOW, auto_astar_follow_event,
01870                                           AUTOPILOT_FOLLOW_TICK, 0);
01871                         return;
01872 
01873                 } else {
01874 
01875                         /* Delete the node and goto the next one */
01876                         temp_astar_node =
01877                                 (astar_node *) dllist_remove_node_at_pos(autopilot->
01878                                                                                                                  astar_path, 1);
01879                         free(temp_astar_node);
01880 
01881                         /* Call this event again */
01882                         AUTOEVENT(autopilot, EVENT_AUTOFOLLOW, auto_astar_follow_event,
01883                                           AUTOPILOT_FOLLOW_TICK, 0);
01884                         return;
01885 
01886                 }
01887 
01888         }
01889 
01890         /* Set our current goal - not the end goal tho - unless this is
01891          * the end hex but whatever */
01892         x = temp_astar_node->x;
01893         y = temp_astar_node->y;
01894 
01895         /* Move towards our next hex */
01896         figure_out_range_and_bearing(mech, x, y, &range, &bearing);
01897         speed_up_if_neccessary(autopilot, mech, x, y, bearing);
01898         slow_down_if_neccessary(autopilot, mech, range, bearing, x, y);
01899         update_wanted_heading(autopilot, mech, bearing);
01900 
01901         /* Increase Tick */
01902         autopilot->follow_update_tick++;
01903 
01904         AUTOEVENT(autopilot, EVENT_AUTOFOLLOW, auto_astar_follow_event,
01905                           AUTOPILOT_FOLLOW_TICK, 0);
01906 
01907 }
01908 
01909 #if 0
01910 /* Old follow system - will phase out */
01911 void auto_follow_event(MUXEVENT * e)
01912 {
01913         AUTO *a = (AUTO *) e->data;
01914         float fx, fy, newx, newy;
01915         int h;
01916         MECH *leader;
01917         MECH *mech = a->mymech;
01918 
01919         if(!IsMech(mech->mynum) || !IsAuto(a->mynum))
01920                 return;
01921 
01922         CCH(a);
01923         GSTART(a, mech);
01924         if(!(leader = getMech(GVAL(a, 1)))) {
01925                 /* For some reason, leader is missing(?) */
01926                 ADVANCE_PG(a);
01927                 return;
01928         }
01929         h = MechFacing(leader);
01930         FindXY(MechFX(leader), MechFY(leader), h + a->ofsx, a->ofsy, &fx, &fy);
01931         FindComponents(MechSpeed(leader) * MOVE_MOD, MechFacing(leader),
01932                                    &newx, &newy);
01933         if(ai_check_path(mech, a, fx, fy, newx, newy))
01934                 AUTOEVENT(a, EVENT_AUTOFOLLOW, auto_follow_event,
01935                                   AUTOPILOT_FOLLOW_TICK, 0);
01936 }
01937 #endif
01938 
01939 /*
01940  * Make the AI [dumbly]follow the given target
01941  */
01942 void auto_dumbfollow_event(MUXEVENT * muxevent)
01943 {
01944 
01945         AUTO *autopilot = (AUTO *) muxevent->data;
01946         int tx, ty, x, y;
01947         int h;
01948         MECH *leader;
01949         MECH *mech = autopilot->mymech;
01950         MAP *map;
01951         float range;
01952         int bearing;
01953 
01954         char *argument;
01955         int target;
01956 
01957         char error_buf[MBUF_SIZE];
01958         char buffer[SBUF_SIZE];
01959 
01960         /* Making sure the mech is a mech and the autopilot is an autopilot */
01961         if(!IsMech(mech->mynum) || !IsAuto(autopilot->mynum))
01962                 return;
01963 
01964         /* Are we in the mech we're supposed to be in */
01965         if(Location(autopilot->mynum) != autopilot->mymechnum)
01966                 return;
01967 
01968         /* Our mech is destroyed */
01969         if(Destroyed(mech))
01970                 return;
01971 
01972         /* Check to make sure the first command in the queue is this one */
01973         if(auto_get_command_enum(autopilot, 1) != GOAL_DUMBFOLLOW)
01974                 return;
01975 
01976         /* Get the Map */
01977         if(!(map = getMap(autopilot->mapindex))) {
01978 
01979                 /* Bad Map */
01980                 snprintf(error_buf, MBUF_SIZE, "Internal AI Error - Attempting to"
01981                                  " follow [dumbly] with AI #%d but AI is not on a valid"
01982                                  " Map (#%d).", autopilot->mynum, autopilot->mapindex);
01983                 SendAI(error_buf);
01984 
01985                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
01986                 return;
01987 
01988         }
01989 
01990         /* Make sure mech is started and standing */
01991         if(!Started(mech)) {
01992 
01993                 /* Startup */
01994                 if(!Starting(mech))
01995                         auto_command_startup(autopilot, mech);
01996 
01997                 /* Run this command after startup */
01998                 AUTOEVENT(autopilot, EVENT_AUTOFOLLOW, auto_dumbfollow_event,
01999                                   AUTOPILOT_STARTUP_TICK, 0);
02000                 return;
02001         }
02002 
02003         /* Make sure the mech is standing before going on */
02004         if(MechType(mech) == CLASS_MECH && Fallen(mech) &&
02005            !(CountDestroyedLegs(mech) > 0)) {
02006 
02007                 if(!Standing(mech))
02008                         mech_stand(autopilot->mynum, mech, "");
02009 
02010                 /* Ok lets run this command again */
02011                 AUTOEVENT(autopilot, EVENT_AUTOFOLLOW, auto_dumbfollow_event,
02012                                   AUTOPILOT_NC_DELAY, 0);
02013                 return;
02014         }
02015 
02018         /* Get the target */
02019         if(!(argument = auto_get_command_arg(autopilot, 1, 1))) {
02020 
02021                 /* Ok bad argument - means the command is messed up
02022                  * so should go to next one */
02023                 snprintf(error_buf, MBUF_SIZE, "Internal AI Error - AI #%d attempting"
02024                                  " to follow target [dumbly] but was unable to - bad argument - going"
02025                                  " to next command", autopilot->mynum);
02026                 SendAI(error_buf);
02027                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
02028                 return;
02029         }
02030 
02031         /* Try and read the value */
02032         if(Readnum(target, argument)) {
02033 
02034                 /* Not proper number so skip command goto next */
02035                 snprintf(error_buf, MBUF_SIZE, "Internal AI Error - AI #%d attempting"
02036                                  " to follow target [dumbly] but was unable to - bad argument '%s' - going"
02037                                  " to next command", autopilot->mynum, argument);
02038                 SendAI(error_buf);
02039                 free(argument);
02040                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
02041                 return;
02042 
02043         }
02044         free(argument);
02045 
02046         /* Make sure its a valid target */
02047         if(!(leader = getMech(target)) || Destroyed(leader)) {
02048 
02049                 /* For some reason, leader is missing(?) */
02050                 snprintf(error_buf, MBUF_SIZE, "Internal AI Error - AI #%d attempting"
02051                                  " to follow target [dumbly] but was unable to - bad or dead target -"
02052                                  " going to next command", autopilot->mynum);
02053                 SendAI(error_buf);
02054                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
02055                 return;
02056         }
02057 
02058         h = MechDesiredFacing(leader);
02059         x = autopilot->ofsy * cos(TWOPIOVER360 * (270.0 + (h + autopilot->ofsx)));
02060         y = autopilot->ofsy * sin(TWOPIOVER360 * (270.0 + (h + autopilot->ofsx)));
02061         tx = MechX(leader) + x;
02062         ty = MechY(leader) + y;
02063 
02064         if(MechX(mech) == tx && MechY(mech) == ty) {
02065 
02066                 /* Do ugly stuff */
02067                 /* For now, try to match speed (if any) and heading (if any) of the
02068                    leader */
02069                 if(MechSpeed(leader) > 1 || MechSpeed(leader) < -1 ||
02070                    MechSpeed(mech) > 1 || MechSpeed(mech) < -1) {
02071 
02072                         if(MechDesiredFacing(mech) != MechFacing(leader)) {
02073                                 snprintf(buffer, SBUF_SIZE, "%d", MechFacing(leader));
02074                                 mech_heading(autopilot->mynum, mech, buffer);
02075                         }
02076 
02077                         if(MechSpeed(mech) != MechSpeed(leader)) {
02078                                 snprintf(buffer, SBUF_SIZE, "%.2f", MechSpeed(leader));
02079                                 mech_speed(autopilot->mynum, mech, buffer);
02080                         }
02081                 }
02082 
02083                 AUTOEVENT(autopilot, EVENT_AUTOFOLLOW, auto_dumbfollow_event,
02084                                   AUTOPILOT_FOLLOW_TICK, 0);
02085                 return;
02086         }
02087 
02088         figure_out_range_and_bearing(mech, tx, ty, &range, &bearing);
02089         speed_up_if_neccessary(autopilot, mech, tx, ty, -1);
02090 
02091         if(MechSpeed(leader) < MP1)
02092                 slow_down_if_neccessary(autopilot, mech, range + 1, bearing, tx, ty);
02093 
02094         update_wanted_heading(autopilot, mech, bearing);
02095 
02096         AUTOEVENT(autopilot, EVENT_AUTOFOLLOW, auto_dumbfollow_event,
02097                           AUTOPILOT_FOLLOW_TICK, 0);
02098 }
02099 
02100 /*
02101  * Command the AI to leave a hangar or base
02102  */
02103 void auto_leave_event(MUXEVENT * muxevent)
02104 {
02105 
02106         AUTO *autopilot = (AUTO *) muxevent->data;
02107         MECH *mech = autopilot->mymech;
02108         MAP *map;
02109 
02110         int dir;
02111         int reset_mapindex = (int) muxevent->data2;
02112         char *argument;
02113         char error_buf[MBUF_SIZE];
02114 
02115         if(!IsMech(mech->mynum) || !IsAuto(autopilot->mynum))
02116                 return;
02117 
02118         /* Are we in the mech we're supposed to be in */
02119         if(Location(autopilot->mynum) != autopilot->mymechnum)
02120                 return;
02121 
02122         /* Our mech is destroyed */
02123         if(Destroyed(mech))
02124                 return;
02125 
02126         /* Check to make sure the first command in the queue is this one */
02127         if(auto_get_command_enum(autopilot, 1) != GOAL_LEAVEBASE)
02128                 return;
02129 
02130         /* Get the Map */
02131         if(!(map = getMap(autopilot->mapindex))) {
02132 
02133                 /* Bad Map */
02134                 snprintf(error_buf, MBUF_SIZE, "Internal AI Error - Attempting to"
02135                                  " leavebase with AI #%d but AI is not on a valid"
02136                                  " Map (#%d).", autopilot->mynum, autopilot->mapindex);
02137                 SendAI(error_buf);
02138 
02139                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
02140                 return;
02141 
02142         }
02143 
02144         /* Make sure mech is started */
02145         if(!Started(mech)) {
02146 
02147                 /* Startup */
02148                 if(!Starting(mech))
02149                         auto_command_startup(autopilot, mech);
02150 
02151                 /* Run this command after startup */
02152                 AUTOEVENT(autopilot, EVENT_AUTOLEAVE, auto_leave_event,
02153                                   AUTOPILOT_STARTUP_TICK, reset_mapindex);
02154                 return;
02155         }
02156 
02157         /* Ok not standing so lets do that first */
02158         if(MechType(mech) == CLASS_MECH && Fallen(mech) &&
02159            !(CountDestroyedLegs(mech) > 0)) {
02160 
02161                 if(!Standing(mech))
02162                         mech_stand(autopilot->mynum, mech, "");
02163 
02164                 /* Ok lets run this command again */
02165                 AUTOEVENT(autopilot, EVENT_AUTOLEAVE, auto_leave_event,
02166                                   AUTOPILOT_NC_DELAY, reset_mapindex);
02167                 return;
02168         }
02169 
02172         /* Do we need to reset the mapindex value ? */
02173         if(reset_mapindex) {
02174                 autopilot->mapindex = mech->mapindex;
02175         }
02176 
02177         /* Get the argument - direction */
02178         if(!(argument = auto_get_command_arg(autopilot, 1, 1))) {
02179 
02180                 /* Ok bad argument - means the command is messed up
02181                  * so should go to next one */
02182                 snprintf(error_buf, MBUF_SIZE, "Internal AI Error - Attempting to"
02183                                  " leavebase with AI #%d but was given bad argument"
02184                                  " defaulting to direction = 0", autopilot->mynum);
02185                 SendAI(error_buf);
02186 
02187                 dir = 0;
02188 
02189         } else if(Readnum(dir, argument)) {
02190 
02191                 snprintf(error_buf, MBUF_SIZE, "Internal AI Error - Attempting to"
02192                                  " leavebase with AI #%d but was given bad argument '%s'"
02193                                  " defaulting to direction = 0", autopilot->mynum, argument);
02194                 SendAI(error_buf);
02195 
02196                 dir = 0;
02197 
02198         }
02199         free(argument);
02200 
02201         if(mech->mapindex != autopilot->mapindex) {
02202 
02203                 /* We're elsewhere, pal! */
02204                 autopilot->mapindex = mech->mapindex;
02205                 ai_set_speed(mech, autopilot, 0);
02206                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
02207                 return;
02208         }
02209 
02210         /* Still not out yet so keep trying */
02211         speed_up_if_neccessary(autopilot, mech, -1, -1, dir);
02212         update_wanted_heading(autopilot, mech, dir);
02213         AUTOEVENT(autopilot, EVENT_AUTOLEAVE, auto_leave_event,
02214                           AUTOPILOT_LEAVE_TICK, 0);
02215 }
02216 
02217 /*
02218  * Function to get the AI to enter a base hex given
02219  * a certain direction (n w s e)
02220  */
02221 void auto_enter_event(MUXEVENT * muxevent)
02222 {
02223 
02224         AUTO *autopilot = (AUTO *) muxevent->data;
02225         MECH *mech = autopilot->mymech;
02226         MAP *map;
02227         mapobj *map_object;
02228         int num;
02229         int reset_mapindex = (int) muxevent->data2;
02230 
02231         char *argument;
02232         char dir[2];
02233         char error_buf[MBUF_SIZE];
02234 
02235         if(!IsMech(mech->mynum) || !IsAuto(autopilot->mynum))
02236                 return;
02237 
02238         /* Are we in the mech we're supposed to be in */
02239         if(Location(autopilot->mynum) != autopilot->mymechnum)
02240                 return;
02241 
02242         /* Our mech is destroyed */
02243         if(Destroyed(mech))
02244                 return;
02245 
02246         /* Check to make sure the first command in the queue is this one */
02247         if(auto_get_command_enum(autopilot, 1) != GOAL_ENTERBASE)
02248                 return;
02249 
02250         /* Get the Map */
02251         if(!(map = getMap(autopilot->mapindex))) {
02252 
02253                 /* Bad Map */
02254                 snprintf(error_buf, MBUF_SIZE, "Internal AI Error - Attempting to"
02255                                  " enterbase with AI #%d but AI is not on a valid"
02256                                  " Map (#%d).", autopilot->mynum, autopilot->mapindex);
02257                 SendAI(error_buf);
02258 
02259                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
02260                 return;
02261 
02262         }
02263 
02264         /* Is there anything even to enter here */
02265         if(!(map_object = find_entrance_by_xy(map, MechX(mech), MechY(mech)))) {
02266 
02267                 /* Nothing in this hex */
02268                 snprintf(error_buf, MBUF_SIZE, "Internal AI Error - Attempting to"
02269                                  " enterbase with AI #%d but there is nothing at %d, %d"
02270                                  " to enter", autopilot->mynum, MechX(mech), MechY(mech));
02271                 SendAI(error_buf);
02272                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
02273                 return;
02274         }
02275 
02276         /* Reset the mapindex if this is the first run of the event */
02277         if(reset_mapindex) {
02278                 autopilot->mapindex = mech->mapindex;
02279         }
02280 
02281         /* Make sure mech is started */
02282         if(!Started(mech)) {
02283 
02284                 /* Startup */
02285                 if(!Starting(mech))
02286                         auto_command_startup(autopilot, mech);
02287 
02288                 /* Run this command after startup */
02289                 AUTOEVENT(autopilot, EVENT_AUTOENTERBASE,
02290                                   auto_enter_event, AUTOPILOT_STARTUP_TICK, 0);
02291                 return;
02292         }
02293 
02294         /* Ok not standing so lets do that first */
02295         if(MechType(mech) == CLASS_MECH && Fallen(mech) &&
02296            !(CountDestroyedLegs(mech) > 0)) {
02297 
02298                 if(!Standing(mech))
02299                         mech_stand(autopilot->mynum, mech, "");
02300 
02301                 /* Ok lets run this command again */
02302                 AUTOEVENT(autopilot, EVENT_AUTOENTERBASE,
02303                                   auto_enter_event, AUTOPILOT_NC_DELAY, 0);
02304                 return;
02305         }
02306 
02307         /* Get enter direction */
02308         if(!(argument = auto_get_command_arg(autopilot, 1, 1))) {
02309 
02310                 /* Ok bad argument - means the command is messed up
02311                  * so should go to next one */
02312                 snprintf(error_buf, MBUF_SIZE, "Internal AI Error - Attempting to"
02313                                  " enterbase with AI #%d but was given bad argument -"
02314                                  " going to next command", autopilot->mynum);
02315                 SendAI(error_buf);
02316                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
02317                 return;
02318         }
02319 
02320         /* Check the first letter of the 'only' argument
02321          * this tells us what direction to enter */
02322         switch (argument[0]) {
02323 
02324         case 'n':
02325         case 'N':
02326                 strcpy(dir, "n");
02327                 break;
02328         case 's':
02329         case 'S':
02330                 strcpy(dir, "s");
02331                 break;
02332         case 'w':
02333         case 'W':
02334                 strcpy(dir, "w");
02335                 break;
02336         case 'e':
02337         case 'E':
02338                 strcpy(dir, "e");
02339                 break;
02340         default:
02341                 strcpy(dir, "");
02342 
02343         }
02344         free(argument);
02345 
02346         /* New map so we're done */
02347         if(mech->mapindex != autopilot->mapindex) {
02348 
02349                 autopilot->mapindex = mech->mapindex;
02350                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
02351                 return;
02352         }
02353 
02354         if(MechDesiredSpeed(mech) != 0.0)
02355                 ai_set_speed(mech, autopilot, 0);
02356 
02357         if((MechSpeed(mech) == 0.0) && !EnteringHangar(mech)) {
02358                 mech_enterbase(GOD, mech, dir);
02359         }
02360 
02361         /* Run this event again if we're not in yet */
02362         AUTOEVENT(autopilot, EVENT_AUTOENTERBASE, auto_enter_event,
02363                           AUTOPILOT_NC_DELAY, 0);
02364 }
02365 
02366 /*
02367  * Roam master command
02368  * Works like autogun where it takes 1 argument then looks
02369  * for pieces
02370  */
02371 void auto_command_roam(AUTO * autopilot, MECH * mech)
02372 {
02373 
02374         char *argument;
02375         char error_buf[MBUF_SIZE];
02376         char *args[4];
02377         int argc;
02378         int i;
02379         int anchor_hex_x;
02380         int anchor_hex_y;
02381         int anchor_distance;
02382 
02383         MAP *map;
02384 
02385         /* Read in the argument */
02386         argument = auto_get_command_arg(autopilot, 1, 1);
02387 
02388         /* Parse the argument */
02389         argc = proper_explodearguments(argument, args, 4);
02390 
02391         /* Free the argument */
02392         free(argument);
02393 
02394         /* Now we check to see how many arguments it found */
02395         if(argc == 1) {
02396 
02397                 /* Wander the map aimlessly */
02398                 if(strcmp(args[0], "map") == 0) {
02399 
02400                         /* Set flags */
02401                         autopilot->roam_type = AUTO_ROAM_MAP;
02402 
02403                         /* Fire off event */
02404                         AUTOEVENT(autopilot, EVENT_AUTO_ROAM, auto_astar_roam_event,
02405                                           AUTO_ROAM_TICK, 1);
02406 
02407                 } else {
02408 
02409                         /* Invalid command */
02410                         snprintf(error_buf, MBUF_SIZE, "AI Error - AI #%d given bad"
02411                                          " argument for roam command", autopilot->mynum);
02412                         SendAI(error_buf);
02413 
02414                         auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
02415 
02416                 }
02417 
02418         } else if(argc == 4) {
02419 
02420                 /* Stay within a certain radius */
02421                 if(strcmp(args[0], "radius") == 0) {
02422 
02423                         /* Need to grab distance and start hex */
02424                         if(Readnum(anchor_hex_x, args[1])) {
02425 
02426                                 snprintf(error_buf, MBUF_SIZE, "AI Error - AI #%d given bad"
02427                                                  " argument (anchor_hex_x) for roam command",
02428                                                  autopilot->mynum);
02429                                 SendAI(error_buf);
02430 
02431                                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
02432 
02433                                 /* Free Args */
02434                                 for(i = 0; i < 4; i++) {
02435                                         if(args[i])
02436                                                 free(args[i]);
02437                                 }
02438 
02439                                 return;
02440                         }
02441 
02442                         if(Readnum(anchor_hex_y, args[2])) {
02443 
02444                                 snprintf(error_buf, MBUF_SIZE, "AI Error - AI #%d given bad"
02445                                                  " argument (anchor_hex_y) for roam command",
02446                                                  autopilot->mynum);
02447                                 SendAI(error_buf);
02448 
02449                                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
02450 
02451                                 /* Free Args */
02452                                 for(i = 0; i < 4; i++) {
02453                                         if(args[i])
02454                                                 free(args[i]);
02455                                 }
02456 
02457                                 return;
02458                         }
02459 
02460                         /* Need to grab distance and start hex */
02461                         if(Readnum(anchor_distance, args[3])) {
02462 
02463                                 snprintf(error_buf, MBUF_SIZE, "AI Error - AI #%d given bad"
02464                                                  " argument (anchor_distance) for roam command",
02465                                                  autopilot->mynum);
02466                                 SendAI(error_buf);
02467 
02468                                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
02469 
02470                                 /* Free Args */
02471                                 for(i = 0; i < 4; i++) {
02472                                         if(args[i])
02473                                                 free(args[i]);
02474                                 }
02475 
02476                                 return;
02477                         }
02478 
02479                         /* Make sure values are sane */
02480 
02481                         /* Get the Map */
02482                         if(!(map = getMap(autopilot->mapindex))) {
02483 
02484                                 /* Bad Map */
02485                                 snprintf(error_buf, MBUF_SIZE,
02486                                                  "Internal AI Error - Attempting to"
02487                                                  " roam with AI #%d but AI is not on a valid"
02488                                                  " Map (#%d).", autopilot->mynum,
02489                                                  autopilot->mapindex);
02490                                 SendAI(error_buf);
02491 
02492                                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
02493 
02494                                 /* Free Args */
02495                                 for(i = 0; i < 4; i++) {
02496                                         if(args[i])
02497                                                 free(args[i]);
02498                                 }
02499 
02500                                 return;
02501 
02502                         }
02503 
02504                         /* Check to make sure the hexes are inside the map and the distance
02505                          * is not beyond our limit */
02506                         if(anchor_hex_x < 0 || anchor_hex_y < 0 ||
02507                            anchor_hex_x >= map->map_width ||
02508                            anchor_hex_y >= map->map_height ||
02509                            anchor_distance > AUTO_ROAM_MAX_RADIUS) {
02510 
02511                                 snprintf(error_buf, MBUF_SIZE, "AI Error - AI #%d given bad"
02512                                                  " argument (bad anchor hex or bad anchor distance)"
02513                                                  " %d,%d : %d hexes for roam command",
02514                                                  autopilot->mynum, anchor_hex_x, anchor_hex_y,
02515                                                  anchor_distance);
02516                                 SendAI(error_buf);
02517 
02518                                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
02519 
02520                                 /* Free Args */
02521                                 for(i = 0; i < 4; i++) {
02522                                         if(args[i])
02523                                                 free(args[i]);
02524                                 }
02525 
02526                                 return;
02527                         }
02528 
02529                         /* Set values */
02530                         autopilot->roam_type = AUTO_ROAM_SPOT;
02531                         autopilot->roam_anchor_hex_x = anchor_hex_x;
02532                         autopilot->roam_anchor_hex_y = anchor_hex_y;
02533                         autopilot->roam_anchor_distance = anchor_distance;
02534 
02535                         /* Fire off event */
02536                         AUTOEVENT(autopilot, EVENT_AUTO_ROAM, auto_astar_roam_event,
02537                                           AUTO_ROAM_TICK, 1);
02538 
02539                 } else {
02540 
02541                         /* Invalid command */
02542                         snprintf(error_buf, MBUF_SIZE, "AI Error - AI #%d given bad"
02543                                          " argument for roam command", autopilot->mynum);
02544                         SendAI(error_buf);
02545 
02546                         auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
02547 
02548                 }
02549 
02550         } else {
02551 
02552                 /* Invalid command */
02553                 snprintf(error_buf, MBUF_SIZE, "AI Error - AI #%d given bad"
02554                                  " argument for roam command", autopilot->mynum);
02555                 SendAI(error_buf);
02556 
02557                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
02558 
02559         }
02560 
02561         /* Free Args */
02562         for(i = 0; i < 4; i++) {
02563                 if(args[i])
02564                         free(args[i]);
02565         }
02566 
02567 }
02568 
02569 /*
02570  * Generate a random hex to roam to
02571  */
02572 void auto_roam_generate_target_hex(AUTO * autopilot, MECH * mech, MAP * map,
02573                                                                    int attempt)
02574 {
02575 
02576         short start_hex_x = 0;
02577         short start_hex_y = 0;
02578         short target_hex_x = 0;
02579         short target_hex_y = 0;
02580         float x1, y1, x2, y2;
02581         float range;
02582         int bearing;
02583         int max_range = 0;
02584         int counter;
02585 
02586         /* First tho we pick a hex differently based on which roam mode */
02587         if(autopilot->roam_type == AUTO_ROAM_MAP) {
02588 
02589                 start_hex_x = MechX(mech);
02590                 start_hex_y = MechY(mech);
02591                 max_range = AUTO_ROAM_MAX_MAP_DISTANCE;
02592 
02593         } else if(autopilot->roam_type == AUTO_ROAM_SPOT) {
02594 
02595                 start_hex_x = autopilot->roam_anchor_hex_x;
02596                 start_hex_y = autopilot->roam_anchor_hex_y;
02597                 max_range = autopilot->roam_anchor_distance;
02598 
02599         } else {
02600 
02602         }
02603 
02604         /* Adjust roam distance based on number of times we've called this
02605          * function */
02606         max_range = max_range / (2 ^ attempt);
02607 
02608         counter = 0;
02609 
02610         while (counter < AUTO_ROAM_MAX_ITERATIONS) {
02611 
02612                 /* So we're not caught in some endless loop */
02613                 counter++;
02614 
02615                 /* Generate range */
02616                 if(max_range < 1) {
02617                         range = 1.0;
02618                 } else {
02619                         range = (float) Number(1, max_range);
02620                 }
02621 
02622                 /* Generate random bearing */
02623                 bearing = Number(0, 359);
02624 
02625                 /* Map coord to Real */
02626                 MapCoordToRealCoord(start_hex_x, start_hex_y, &x1, &y1);
02627 
02628                 /* Calc new hex */
02629                 FindXY(x1, y1, bearing, range, &x2, &y2);
02630 
02631                 /* Real coord to Map */
02632                 RealCoordToMapCoord(&target_hex_x, &target_hex_y, x2, y2);
02633 
02634                 /* Make sure the hex is sane */
02635                 if(target_hex_x < 0 || target_hex_y < 0 ||
02636                    target_hex_x >= map->map_width || target_hex_y >= map->map_height)
02637                         continue;
02638 
02639                 switch (GetTerrain(map, target_hex_x, target_hex_y)) {
02640                 case LIGHT_FOREST:
02641                         if((MechType(mech) == CLASS_VEH_GROUND) &&
02642                            (MechMove(mech) != MOVE_TRACK))
02643                                 continue;
02644 
02645                         break;
02646 
02647                 case HEAVY_FOREST:
02648                         if(MechType(mech) == CLASS_VEH_GROUND)
02649                                 continue;
02650 
02651                         break;
02652 
02653                 case WATER:
02654                         if(MechMove(mech) != MOVE_HOVER)
02655                                 continue;
02656 
02657                         break;
02658 
02659                 }                                               /* End of switch */
02660 
02661                 /* Ok the hex is more or less sane so lets return and see if we can
02662                  * find a path to it */
02663                 autopilot->roam_target_hex_x = target_hex_x;
02664                 autopilot->roam_target_hex_y = target_hex_y;
02665                 break;
02666 
02667         }                                                       /* End of while loop */
02668 
02669 }
02670 
02671 /*
02672  * Event for roaming
02673  */
02674 void auto_astar_roam_event(MUXEVENT * muxevent)
02675 {
02676 
02677         AUTO *autopilot = (AUTO *) muxevent->data;
02678         int tx, ty;
02679         MECH *mech = autopilot->mymech;
02680         MAP *map;
02681         float range;
02682         int bearing;
02683         int roam_hex_attempt;
02684         int generate_path = (int) muxevent->data2;
02685 
02686         astar_node *temp_astar_node;
02687 
02688         char error_buf[MBUF_SIZE];
02689 
02690         /* Make sure the mech is a mech and the autopilot is an autopilot */
02691         if(!IsMech(mech->mynum) || !IsAuto(autopilot->mynum))
02692                 return;
02693 
02694         /* Are we in the mech we're supposed to be in */
02695         if(Location(autopilot->mynum) != autopilot->mymechnum)
02696                 return;
02697 
02698         /* Our mech is destroyed */
02699         if(Destroyed(mech))
02700                 return;
02701 
02702         /* Check to make sure the first command in the queue is this one */
02703         if(auto_get_command_enum(autopilot, 1) != GOAL_ROAM)
02704                 return;
02705 
02706         /* Get the Map */
02707         if(!(map = getMap(autopilot->mapindex))) {
02708 
02709                 /* Bad Map */
02710                 snprintf(error_buf, MBUF_SIZE, "Internal AI Error - Attempting to"
02711                                  " roam with AI #%d but AI is not on a valid"
02712                                  " Map (#%d).", autopilot->mynum, autopilot->mapindex);
02713                 SendAI(error_buf);
02714 
02715                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
02716                 return;
02717 
02718         }
02719 
02720         /* Make sure mech is started and standing */
02721         if(!Started(mech)) {
02722 
02723                 /* Startup */
02724                 if(!Starting(mech))
02725                         auto_command_startup(autopilot, mech);
02726 
02727                 /* Run this command after startup */
02728                 AUTOEVENT(autopilot, EVENT_AUTO_ROAM, auto_astar_roam_event,
02729                                   AUTOPILOT_STARTUP_TICK, generate_path);
02730                 return;
02731         }
02732 
02733         /* Ok not standing so lets do that first */
02734         if(MechType(mech) == CLASS_MECH && Fallen(mech) &&
02735            !(CountDestroyedLegs(mech) > 0)) {
02736 
02737                 if(!Standing(mech))
02738                         mech_stand(autopilot->mynum, mech, "");
02739 
02740                 /* Ok lets run this command again */
02741                 AUTOEVENT(autopilot, EVENT_AUTO_ROAM, auto_astar_roam_event,
02742                                   AUTOPILOT_NC_DELAY, generate_path);
02743                 return;
02744         }
02745 
02748         /* Do we need to generate a target hex */
02749         if(generate_path || autopilot->roam_update_tick >= AUTO_ROAM_NEW_HEX_TICK) {
02750 
02751                 /* Reset counter */
02752                 roam_hex_attempt = 0;
02753 
02754                 while (roam_hex_attempt < AUTO_ROAM_MAX_ITERATIONS) {
02755 
02756                         /* Generate Target Hex and then try and generate path to it */
02757 
02758                         /* Target hex */
02759                         auto_roam_generate_target_hex(autopilot, mech, map,
02760                                                                                   roam_hex_attempt);
02761 
02762                         /* Path */
02763                         if((autopilot->roam_target_hex_x != -1) &&
02764                            (autopilot->roam_target_hex_y != -1) &&
02765                            auto_astar_generate_path(autopilot, mech,
02766                                                                                 autopilot->roam_target_hex_x,
02767                                                                                 autopilot->roam_target_hex_y)) {
02768 
02769                                 /* Found a path */
02770                                 break;
02771 
02772                         }
02773 
02774                         roam_hex_attempt++;
02775 
02776                 }                                               /* End of looking for target hex */
02777 
02778                 /* Check the path */
02779                 if(!(autopilot->astar_path)
02780                    || (dllist_size(autopilot->astar_path) <= 0)) {
02781 
02782                         /* Put Roam to bed and try again */
02783                         AUTOEVENT(autopilot, EVENT_AUTO_ROAM, auto_astar_roam_event,
02784                                           AUTO_ROAM_TICK, 1);
02785                         return;
02786                 }
02787 
02788                 /* Reset the Roam ticker */
02789                 autopilot->roam_update_tick = 0;
02790 
02791         }
02792 
02793         /* Make sure list is ok */
02794         if(!(autopilot->astar_path) || (dllist_size(autopilot->astar_path) <= 0)) {
02795 
02796                 snprintf(error_buf, MBUF_SIZE,
02797                                  "Internal AI Error - Attempting to roam"
02798                                  " Astar path for AI #%d - but the path is not there",
02799                                  autopilot->mynum);
02800                 SendAI(error_buf);
02801 
02802                 auto_destroy_astar_path(autopilot);
02803                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
02804                 return;
02805 
02806         }
02807 
02808         /* Move along the path */
02809 
02810         /* Get the current hex target */
02811         temp_astar_node =
02812                 (astar_node *) dllist_get_node(autopilot->astar_path, 1);
02813 
02814         if(!(temp_astar_node)) {
02815 
02816                 snprintf(error_buf, MBUF_SIZE, "Internal AI Error - Attemping to roam"
02817                                  " Astar path for AI #%d - but the current astar node does not"
02818                                  " exist", autopilot->mynum);
02819                 SendAI(error_buf);
02820 
02821                 auto_destroy_astar_path(autopilot);
02822                 auto_goto_next_command(autopilot, AUTOPILOT_NC_DELAY);
02823                 return;
02824 
02825         }
02826 
02827         /* Are we in the current target hex */
02828         if((MechX(mech) == temp_astar_node->x) &&
02829            (MechY(mech) == temp_astar_node->y)) {
02830 
02831                 /* Is this the last hex */
02832                 if(dllist_size(autopilot->astar_path) == 1) {
02833 
02834                         /* Done! */
02835                         ai_set_speed(mech, autopilot, 0);
02836 
02837                         /* Destroy the path and run roam again */
02838                         auto_destroy_astar_path(autopilot);
02839                         AUTOEVENT(autopilot, EVENT_AUTO_ROAM, auto_astar_roam_event,
02840                                           AUTO_ROAM_TICK, 1);
02841                         return;
02842 
02843                 } else {
02844 
02845                         /* Delete the node and goto the next one */
02846                         temp_astar_node =
02847                                 (astar_node *) dllist_remove_node_at_pos(autopilot->
02848                                                                                                                  astar_path, 1);
02849                         free(temp_astar_node);
02850 
02851                         /* Update the tick counter */
02852                         autopilot->roam_update_tick++;
02853 
02854                         /* Call this event again */
02855                         AUTOEVENT(autopilot, EVENT_AUTO_ROAM, auto_astar_roam_event,
02856                                           AUTO_ROAM_TICK, 0);
02857                         return;
02858 
02859                 }
02860 
02861         }
02862 
02863         /* Set our current goal - not the end goal tho - unless this is
02864          * the end hex but whatever */
02865         tx = temp_astar_node->x;
02866         ty = temp_astar_node->y;
02867 
02868         /* Move towards our next hex */
02869         figure_out_range_and_bearing(mech, tx, ty, &range, &bearing);
02870         speed_up_if_neccessary(autopilot, mech, tx, ty, bearing);
02871         slow_down_if_neccessary(autopilot, mech, range, bearing, tx, ty);
02872         update_wanted_heading(autopilot, mech, bearing);
02873 
02874         /* Update the tick counter */
02875         autopilot->roam_update_tick++;
02876 
02877         /* Cycle it again */
02878         AUTOEVENT(autopilot, EVENT_AUTO_ROAM, auto_astar_roam_event,
02879                           AUTO_ROAM_TICK, 0);
02880 }

Generated on Mon May 28 04:25:20 2007 for BattletechMUX by  doxygen 1.4.7