text: 
  /*
   * $Id: autopilot_commands.c,v 1.2 2005/08/03 21:40:54 av1-op Exp $
   *
   * Author: Markus Stenberg <fingon@iki.fi>
   *
   *  Copyright (c) 1996 Markus Stenberg
   *  Copyright (c) 1998-2002 Thomas Wouters
   *  Copyright (c) 2000-2002 Cord Awtry
   *       All rights reserved
   *
   * Created: Wed Oct 30 20:42:59 1996 fingon
   * Last modified: Sat Jun  6 19:32:27 1998 fingon
   *
   */
  
  #include "mech.h"
  #include "mech.events.h"
  #include "autopilot.h"
  #include "coolmenu.h"
  #include "mycool.h"
  #include "p.mech.utils.h"
  
  extern ACOM acom[AUTO_NUM_COMMANDS + 1];
  extern char *muxevent_names[];
  
  #define AI_COMMAND_DLLIST_START     51      /* Tag for start of saved command list */
  #define AI_COMMAND_DLLIST_END       63      /* Tag for end of saved command list */
  
  #define outbyte(a) tmpb=(a); fwrite(&tmpb, 1, 1, file);
  
  #define CHESA(a,b,c,d) if ((tmpb=fwrite(a,b,c,d)) != c) \
      { fprintf (stderr, "Error writing dllist\n"); \
        fflush(stderr); exit(1); }
  
  #define CHELO(a,b,c,d) if ((tmpb=fread(a,b,c,d)) != c) \
      { fprintf (stderr, "Error loading dllist\n"); \
        fflush(stderr); exit(1); }
  
  /*
   * Creates a new command_node for the AI's
   * command list
   */
  static command_node *auto_create_command_node() {
  
      command_node *temp;
  
      temp = malloc(sizeof(command_node));
      if (temp == NULL)
          return NULL;
  
      memset(temp, 0, sizeof(command_node));
      temp->ai_command_function = NULL;
  
      return temp;
  
  }
  
  /*
   * Destroys a command_node
   */
  void auto_destroy_command_node(command_node *node) {
     
      int i;
  
      /* Free the args */
      for (i = 0; i < AUTOPILOT_MAX_ARGS; i++) {
          if (node->args[i]) {
              free(node->args[i]);
              node->args[i] = NULL;
          }
      }
  
      /* Free the node */
      free(node);
  
      return;
  
  }
  
  /*
   * Writes a command_node to the file specified by f. Used to
   * save AI command list to the hcode.db file
   */
  static void auto_write_command_node(FILE *file, command_node *node) {
  
      unsigned char size;         /* Number of Arguments to save */
      char buf[MBUF_SIZE];        /* Buffer to write the strings */
      int i;                      /* Counter */
      unsigned short tmpb;        /* Store the number of bytes written */
  
      /* Zero the Buffer */
      memset(buf, '\0', sizeof(buf));
  
      /* Write the Number of Arguments we're storing */
      size = node->argcount;
      CHESA(&size, 1, sizeof(size), file);
  
      /* Loop through the args and write them */
      for (i = 0; i <= size; i++) {
          strncpy(buf, node->args[i], MBUF_SIZE);
          CHESA(&buf, 1, sizeof(buf), file);
      }
  
      return;
  
  }
  
  /*
   * Reads the data for a command_node from a file. Used
   * to load the AI command list from hcode.db
   */
  static command_node *auto_read_command_node(FILE *file) {
  
      unsigned char size;         /* Number of Arguments to read */
      char buf[MBUF_SIZE];        /* Buffer to store the strings */
      int i;                      /* Counter */
      unsigned short tmpb;        /* Store the number of bytes read */
  
      command_node *temp_command_node;
  
      /* Allocate a command node */
      temp_command_node = auto_create_command_node();
  
      /* Zero the Buffer */
      memset(buf, '\0', sizeof(buf));
  
      /* Read the Number of Arguments we're storing */
      CHELO(&size, 1, sizeof(size), file);
      temp_command_node->argcount = size;
  
      /* Loop through the arguments and store them */
      for (i = 0; i <= size; i++) {
  
          CHELO(&buf, 1, sizeof(buf), file);
          temp_command_node->args[i] = strndup(buf, MBUF_SIZE);
  
      }
  
      /* Make sure there is a command */
      if (!temp_command_node->args[0]) {
          fprintf(stderr, "Error loading command node from file - "
                  "no command found\n");
          exit(1);
      }
  
      /* Get the command_enum and the command_function */
      for (i = 0; acom[i].name; i++) {
          if ((!strncmp(temp_command_node->args[0], acom[i].name, 
                          strlen(temp_command_node->args[0]))) &&
                  (!strncmp(acom[i].name, temp_command_node->args[0], 
                          strlen(acom[i].name))))
              break;
      }
  
      if (!acom[i].name) {
          fprintf(stderr, "Error loading command node from file - "
                  "Invalid Command\n");
          exit(1);
      }
  
      temp_command_node->command_enum = acom[i].command_enum;
      temp_command_node->ai_command_function = acom[i].ai_command_function;
  
      return temp_command_node;
  
  }
  
  /* 
   * Saves the current command list from the AI to
   * a file.  Called by SaveSpecialObjects from
   * glue.c
   */
  void auto_save_commands(FILE *file, AUTO *autopilot) {
  
      int i;                  /* Our Counter */
      unsigned char tmpb;     /* Our temp int we use when writing */
      unsigned int size;      /* The size of our command list */
  
      command_node *temp_command_node;
  
      /* Print the Start Code */
      outbyte(AI_COMMAND_DLLIST_START);
  
      /* Write the size of our list */
      size = dllist_size(autopilot->commands);
      CHESA(&size, sizeof(size), 1, file);
  
      /* Check the size of the list, if there are commands save them */
      if (dllist_size(autopilot->commands) > 0) {
  
          /* Ok there stuff here so lets write it */
          for (i = 1; i <= dllist_size(autopilot->commands); i++) {
              temp_command_node = (command_node *) dllist_get_node(autopilot->commands, i);
              auto_write_command_node(file, temp_command_node);
          }
  
      }
  
      /* Print the Stop Code */
      outbyte(AI_COMMAND_DLLIST_END);
  
      return;
  
  }
  
  /*
   * Loads an AI's saved command list from
   * a file.  Called by load_xcode in glue.c
   */
  void auto_load_commands(FILE *file, AUTO *autopilot) {
  
      int i;                  /* Our Counter */
      unsigned char tmpb;    /* Our temp int we use when reading */
      unsigned int size;      /* The size of our command list */
  
      dllist_node *temp_dllist_node;
      command_node *temp_command_node;
  
      /* Alloc a dllist to the AI for commands */
      autopilot->commands = dllist_create_list();
  
      /* If we can't even read the file don't bother
       * with the rest */
      if(feof(file))
          return;
  
      /* Loop for the beginning tag */
      fread(&tmpb, 1, 1, file);
      if (tmpb != AI_COMMAND_DLLIST_START) {
          fprintf(stderr, "Unable to locate START for reading data"
                  " for AI #%d\n", autopilot->mynum);
          fflush(stderr);
          exit(1);
      }
  
      /* Read in size of dllist */
      CHELO(&size, sizeof(size), 1, file);
  
      /* if size is bigger then zero means we have to read
       * in some command nodes */
      if (size > 0) {
  
          /* Loop through the list and add the nodes */
          for (i = 1; i <= size; i++) {
  
              temp_command_node = auto_read_command_node(file);
              temp_dllist_node = dllist_create_node(temp_command_node);
              dllist_insert_end(autopilot->commands, temp_dllist_node);
  
          }
  
      }
  
      /* Look for the end tag */
      fread(&tmpb, 1, 1, file);
      if (tmpb != AI_COMMAND_DLLIST_END) {
          fprintf(stderr, "Unable to locate END for reading data"
                  " for AI #%d\n", autopilot->mynum);
          fflush(stderr);
          exit(1);
      }
  
      return;
  
  }
  
  /* 
     The Autopilot command interface
  
     addcommand <name> [args]
     delcommand <num>
     listcommands
     engage
     disengage
     jump
  
   */
  
  /*
   * The commands that are on the XCODE Object along
   * with some helper commands for modifying the state
   * of the AI
   */
  
  /*! \todo {See if we need this function and remove it if not} */
  int auto_valid_progline(AUTO * a, int p)
  {
      int i;
  #if 0
      for (i = 0; i < a->first_free; i += (acom[a->commands[i]].argcount + 1))
          if (i == p)
              return 1;
  #endif
      return 0;
  }
  
  /*
   * Internal function to return a string that
   * displays a command from a command_node
   */
  /*! \todo {Maybe re-write this so doesn't use a static buffer} */
  static char *auto_show_command(command_node *node) {
      
      static char buf[MBUF_SIZE];
      int i;
  
      snprintf(buf, MBUF_SIZE, "%-10s", node->args[0]);
  
      /* Loop through the args and print the commands */
      for (i = 1; i < AUTOPILOT_MAX_ARGS; i++)
          if (node->args[i]) {
              strncat(buf, " ", MBUF_SIZE);
              strncat(buf, node->args[i], MBUF_SIZE);
          }
  
      return buf;
  
  }
  
  /*
   * Removes a command from the AI's command list
   */
  void auto_delcommand(dbref player, void *data, char *buffer) {
  
      int p, i;
      AUTO *autopilot = (AUTO *) data;
      int remove_all_commands = 0;
      command_node *temp_command_node;
      char error_buf[MBUF_SIZE];
  
      /* Make sure they specified an argument */
      if (!*buffer) {
          notify(player, "No argument used : Usage delcommand [num]\n");
          notify_printf(player, "Must be within the range"
                  " 1 to %d or -1 for all\n", dllist_size(autopilot->commands));
          return;
      }
  
      /* Make sure its a number */
      if (Readnum(p, buffer)) {
          notify_printf(player, "Invalid Argument : Must be within the range"
                  " 1 to %d or -1 for all\n", dllist_size(autopilot->commands));
          return;
      }
  
      /* Check if its a valid command position
       * If its -1 means remove all */
      if (p == -1) {
          remove_all_commands = 1;
      } else if ((p > dllist_size(autopilot->commands)) || (p < 1)) {
          notify_printf(player, "Invalid Argument : Must be within the range"
                  " 1 to %d or -1 for all\n", dllist_size(autopilot->commands));
          return;
      } 
  
      /*! \todo {Add in check so they don't accidently remove a running command without
       * disengaging first} */
  
      /* Now remove the node(s) */
      if (!remove_all_commands) {
  
          /* Remove the node at pos */
          temp_command_node = 
              (command_node *) dllist_remove_node_at_pos(autopilot->commands, p);
  
          if (!temp_command_node) {
              snprintf(error_buf, MBUF_SIZE, "Internal AI Error: Trying to remove"
                      " Command #%d from AI #%d but the command node doesn't exist\n",
                      p, autopilot->mynum);
              SendAI(error_buf);
          }
  
          /* Destroy the command_node */
          auto_destroy_command_node(temp_command_node);
  
          notify_printf(player, "Command #%d Successfully Removed\n", p);
  
      } else {
  
          /* Remove ALL the commands */
          while (dllist_size(autopilot->commands)) {
  
              /* Remove the first node on the list and get the data
               * from it */
              temp_command_node = (command_node *) dllist_remove(autopilot->commands,
                      dllist_head(autopilot->commands));
  
              /* Make sure the command node exists */
              if (!temp_command_node) {
  
                  snprintf(error_buf, MBUF_SIZE, "Internal AI Error: Trying to remove"
                          " the first command from AI #%d but the command node doesn't exist\n",
                          autopilot->mynum);
                  SendAI(error_buf);
  
              } else {
  
                  /* Destroy the command node */
                  auto_destroy_command_node(temp_command_node);
  
              }
  
          }
  
          notify(player, "All the commands have been removed.\n");
  
      }
  
  }
  
  /*
   * Jump to a specific command location in the AI's
   * command list
   */
  void auto_jump(dbref player, void *data, char *buffer)
  {
      int p;
      AUTO *a = (AUTO *) data;
  
      notify(player, "jump has been temporarly disabled till I can figure out"
              " how I want to change it - Dany");
  #if 0
      skipws(buffer);
      DOCHECK(!*buffer, "Argument expected!");
      DOCHECK(Readnum(p, buffer), "Invalid argument - single number expected.");
      /* Find out if it's valid position */
      DOCHECK(!auto_valid_progline(a, p),
              "Invalid : Argument out of range, or argument, not command.");
      PG(a) = p;
      notify(player, tprintf("Program Counter set to #%d.", p));
  #endif
  }
  
  /*
   * Adds a command to the AI Command List
   */
  void auto_addcommand(dbref player, void *data, char *buffer) {
      
      AUTO *autopilot = (AUTO *) data;
      char *args[AUTOPILOT_MAX_ARGS]; /* args[0] is the command the rest are 
                                         args for the command */
      char *command;                  /* temp string to get the name of the command */
      int argc;
      int i, j;
  
      command_node *temp_command_node;
      dllist_node *temp_dllist_node;
  
      /* Clear the Args */
      memset(args, 0, sizeof(char *) * AUTOPILOT_MAX_ARGS);
  
      command = first_parseattribute(buffer);
  
      /* Look at the buffer and try and get the command */
      for (i = 0; acom[i].name; i++) {
          if ((!strncmp(command, acom[i].name, strlen(command))) &&
                  (!strncmp(acom[i].name, command, strlen(acom[i].name))))
              break;
      }
  
      /* Free the command string we dont need it anymore */
      free(command);
  
      /* Make sure its a valid command */
      DOCHECK(!acom[i].name, "Invalid Command!");
  
      /* Get the arguments for the command */
      if (acom[i].argcount > 0) {
  
          /* Parse the buffer for commands
           * Its argcount + 1 because we are parsing the command + its
           * arguments */
          argc = proper_explodearguments(buffer, args, acom[i].argcount + 1);
          
          if (argc != acom[i].argcount + 1) {
     
              /* Free the args before we quit */ 
              for(j = 0; j < AUTOPILOT_MAX_ARGS; j++) {
                  if(args[j])
                      free(args[j]);
              }
              notify(player, "Not the proper number of arguments!");
              return;
  
          }
  
      } else {
  
          /* Copy the command to the first arg */
          args[0] = strdup(acom[i].name);
  
      }
  
      /* Build the command node */
      temp_command_node = auto_create_command_node();
  
      for (j = 0; j < AUTOPILOT_MAX_ARGS; j++) {
          if (args[j])
              temp_command_node->args[j] = args[j];
      }
  
      temp_command_node->argcount = acom[i].argcount;
      temp_command_node->command_enum = acom[i].command_enum;
      temp_command_node->ai_command_function = acom[i].ai_command_function;
  
      /* Add the command to the list */
      temp_dllist_node = dllist_create_node(temp_command_node); 
      dllist_insert_end(autopilot->commands, temp_dllist_node);
  
      /* Let the player know it worked */
      notify_printf(player, "Command Added: %s", auto_show_command(temp_command_node));
  
  }
  
  /*
   * Lists the various settings and commands currently on the AI
   */
  void auto_listcommands(dbref player, void *data, char *buffer) {
      
      AUTO *autopilot = (AUTO *) data;
      coolmenu *c = NULL;
      char buf[MBUF_SIZE];
      int i, count = 0;
  
      addline();
  
      snprintf(buf, MBUF_SIZE, "Autopilot data for %s", Name(autopilot->mynum));
      vsi(buf);
  
      snprintf(buf, MBUF_SIZE, "Controling unit %s", Name(Location(autopilot->mynum)));
      vsi(buf);
  
      addline();
  
      snprintf(buf, MBUF_SIZE, "MyRef: #%d  MechRef: #%d  MapIndex: #%d  "
              "FSpeed: %d %% (Flag:%d)", autopilot->mynum, autopilot->mymechnum, 
              autopilot->mapindex, autopilot->speed, autopilot->flags);
      vsi(buf);
  
      addline();
  
      if (dllist_size(autopilot->commands)) {
  
          for (i = 1; i <= dllist_size(autopilot->commands); i++) {
              snprintf(buf, MBUF_SIZE, "#%-3d %s", i,
                      auto_show_command((command_node *) dllist_get_node(autopilot->commands, i)));
              vsi(buf);
          }
  
      } else {
          vsi("No commands have been queued to date.");
      }
  
      addline();
      ShowCoolMenu(player, c);
      KillCoolMenu(c);
  }
  
  void auto_eventstats(dbref player, void *data, char *buffer) {
      
      AUTO *autopilot = (AUTO *) data;
      int i, j, total; 
  
      notify(player, "Events by type: ");
      notify(player, "-------------------------------");
  
      total = 0;
  
      for (i = FIRST_AUTO_EVENT; i <= LAST_AUTO_EVENT; i++) {
  
          if ((j = muxevent_count_type_data(i, (void *) autopilot))) {
              notify_printf(player, "%-20s%d", muxevent_names[i], j);
              total += j;
          }
              
      }
  
      if (total) {
          notify(player, "-------------------------------");
          notify_printf(player, "%d total", total);
      }
  
  }
  
  /*
   * Turn the autopilot on
   */
  static int auto_pilot_on(AUTO *autopilot) {
  
      int i, j, count = 0;
  
      for (i = FIRST_AUTO_EVENT; i <= LAST_AUTO_EVENT; i++)
          if ((j = muxevent_count_type_data(i, (void *) autopilot)))
              count += j;
  
      if (!count) {
          return autopilot->flags & (AUTOPILOT_AUTOGUN | AUTOPILOT_GUNZOMBIE |
                  AUTOPILOT_PILZOMBIE);
      }
  
      return count;
  
  }
  
  /*
   * Stop whatever the autopilot is doing
   */
  static void auto_stop_pilot(AUTO *autopilot) {
  
      int i;
  
      autopilot->flags &= ~(AUTOPILOT_AUTOGUN | AUTOPILOT_GUNZOMBIE 
              | AUTOPILOT_PILZOMBIE);
  
      for (i = FIRST_AUTO_EVENT; i <= LAST_AUTO_EVENT; i++)
          muxevent_remove_type_data(i, (void *) autopilot);
  
  }
  
  /*
   * Set the comtitle for the autopilot's unit
   */
  void auto_set_comtitle(AUTO *autopilot, MECH *mech) {
      
      char buf[LBUF_SIZE];
  
      snprintf(buf, LBUF_SIZE, "a=%s/%s", MechType_Ref(mech), MechIDS(mech, 1));
      mech_set_channeltitle(autopilot->mynum, mech, buf);
  
  }
  
  /*
   * Set default parameters for the AI
   */
  /*! \todo {Make this smarter and check some of these} */
  void auto_init(AUTO *autopilot, MECH *mech) {
  
      autopilot->ofsx = 0;            /* Positional - angle */
      autopilot->ofsy = 0;            /* Positional - distance */
      autopilot->auto_cmode = 1;      /* CHARGE! */
      autopilot->auto_cdist = 2;      /* Attempt to avoid kicking distance */
      autopilot->auto_nervous = 0;
      autopilot->auto_goweight = 44;  /* We're mainly concentrating on fighting */
      autopilot->auto_fweight = 55;
      autopilot->speed = 100;         /* Reset to full speed */
      autopilot->flags = 0;
  
      /* Target Stuff */
      autopilot->target = -2;
      autopilot->target_score = 0;
      autopilot->target_threshold = 50;
      autopilot->target_update_tick = AUTO_GUN_UPDATE_TICK;
  
      /* Follow & Chase target stuff */
      autopilot->chase_target = -10;
      autopilot->chasetarg_update_tick = AUTOPILOT_CHASETARG_UPDATE_TICK; 
      autopilot->follow_update_tick = AUTOPILOT_FOLLOW_UPDATE_TICK; 
  
  }
  
  /*
   * Setup all the flags and variables to current, then
   * start the AI's first command.
   */
  void auto_engage(dbref player, void *data, char *buffer) {
  
      AUTO *autopilot = (AUTO *) data;
      MECH *mech;
  
      autopilot->mymech = mech = getMech((autopilot->mymechnum = Location(autopilot->mynum)));
      DOCHECK(!autopilot, "Internal error! - Bad AI object!");
      DOCHECK(!mech, "Error: The autopilot isn't inside a 'mech!");
      DOCHECK(auto_pilot_on(autopilot),
          "The autopilot's already online! You have to disengage it first.");
  
      if (MechAuto(mech) <= 0)
          auto_init(autopilot, mech);
      MechAuto(mech) = autopilot->mynum;
      
      if (MechAuto(mech) > 0)
          auto_set_comtitle(autopilot, mech);
  
      autopilot->mapindex = mech->mapindex;
  
      notify(player, "Engaging autopilot...");
      AUTOEVENT(autopilot, EVENT_AUTOCOM, auto_com_event, AUTOPILOT_NC_DELAY, 0);
  
      return;
  
  }
  
  /*
   * Turn off the autopilot
   */
  void auto_disengage(dbref player, void *data, char *buffer) {
  
      AUTO *autopilot = (AUTO *) data;
  
      DOCHECK(!auto_pilot_on(autopilot),
              "The autopilot's already offline! You have to engage it first.");
  
      auto_stop_pilot(autopilot);
      notify(player, "Autopilot has been disengaged.");
  
      return;
  
  }
  
  /*
   * Remove the first command_node in the list and go to the next
   */
  void auto_goto_next_command(AUTO *autopilot, int time) {
  
      command_node *temp_command_node;
      char error_buf[MBUF_SIZE];
  
      if (dllist_size(autopilot->commands) < 0) {
          snprintf(error_buf, MBUF_SIZE, "Internal AI Error: Trying to remove"
                  " the first command from AI #%d but the command list is empty\n",
                  autopilot->mynum);
          SendAI(error_buf);
          return;
      }
  
      temp_command_node = (command_node *) dllist_remove(autopilot->commands, 
              dllist_head(autopilot->commands));
  
      if (!temp_command_node) {
          snprintf(error_buf, MBUF_SIZE, "Internal AI Error: Trying to remove"
                  " the first command from AI #%d but the command node doesn't exist\n",
                  autopilot->mynum);
          SendAI(error_buf);
          return;
      }
  
      auto_destroy_command_node(temp_command_node);
  
      /* Fire off the AUTO_COM event */
      AUTO_COM(autopilot, time);
  
  }
  
  /*
   * Get the argument for a given command position and argument number
   * Remember to free the string that this returns after use 
   */
  char *auto_get_command_arg(AUTO *autopilot, int command_number, int arg_number) {
  
      char *argument;
      command_node *temp_command_node;
      char error_buf[MBUF_SIZE];
  
      if (command_number > dllist_size(autopilot->commands)) {
          snprintf(error_buf, MBUF_SIZE, "Internal AI Error: Trying to "
                  "access Command #%d for AI #%d but it doesn't exist",
                  command_number, autopilot->mynum);
          SendAI(error_buf);
          return NULL;
      }
  
      if (arg_number >= AUTOPILOT_MAX_ARGS) {
          snprintf(error_buf, MBUF_SIZE, "Internal AI Error: Trying to "
                  "access Arg #%d for AI #%d Command #%d but its greater"
                  " then AUTOPILOT_MAX_ARGS (%d)",
                  arg_number, autopilot->mynum, command_number, AUTOPILOT_MAX_ARGS);
          SendAI(error_buf);
          return NULL;
      }
  
      temp_command_node = (command_node *) dllist_get_node(autopilot->commands, 
                  command_number);
  
      /*! \todo {Add in check incase the command node doesn't exist} */
  
      if (!temp_command_node->args[arg_number]) {
          snprintf(error_buf, MBUF_SIZE, "Internal AI Error: Trying to "
                  "access Arg #%d for AI #%d Command #%d but it doesn't exist",
                  autopilot->mynum, arg_number, command_number);
          SendAI(error_buf);
          return NULL;
      }
  
      argument = strndup(temp_command_node->args[arg_number], MBUF_SIZE);
  
      return argument;
  
  }
  
  /*
   * Returns the command_enum value for the given command
   * from the AI command list
   */
  int auto_get_command_enum(AUTO *autopilot, int command_number) {
  
      int command_enum;
      command_node *temp_command_node;
      char error_buf[MBUF_SIZE];
  
      /* Make sure there are commands */
      if (dllist_size(autopilot->commands) <= 0) {
          return -1;
      }
  
      if (command_number <= 0) {
          snprintf(error_buf, MBUF_SIZE, "Internal AI Error: Trying to "
                  "access a command (%d) for AI #%d that can't be on a list",
                  command_number, autopilot->mynum);
          SendAI(error_buf);
          return -1;
      }
  
      /* Make sure the command is on the list */
      if (command_number > dllist_size(autopilot->commands)) {
          snprintf(error_buf, MBUF_SIZE, "Internal AI Error: Trying to "
                  "access Command #%d for AI #%d but it doesn't exist",
                  autopilot->mynum, command_number);
          SendAI(error_buf);
          return -1;
      }
  
      temp_command_node = (command_node *) dllist_get_node(autopilot->commands, 
                  command_number);
  
      /*! \todo {Add in check incase the command node doesn't exist} */
  
      command_enum = temp_command_node->command_enum;
  
      /* If its a bad enum value we have a problem */
      if ((command_enum >= AUTO_NUM_COMMANDS) || (command_enum < 0)) {
          snprintf(error_buf, MBUF_SIZE, "Internal AI Error: Command ENUM for"
                  " AI #%d Command Number #%d doesn't exist\n",
                  autopilot->mynum, command_number);
          SendAI(error_buf);
          return -1;
      }
  
      return command_enum;
  
  }
  
  #define SPECIAL_FREE 0
  #define SPECIAL_ALLOC 1
              
  /*
   * Called when either creating a new autopilot - SPECIAL_ALLOC
   * or when destroying an autopilot - SPECIAL_FREE
   */
  void auto_newautopilot(dbref key, void **data, int selector) {
      
      AUTO *autopilot = *data;
      command_node *temp;
      int i;
  
      switch (selector) {
          case SPECIAL_ALLOC:
  
              /* Allocate the command list */
              autopilot->commands = dllist_create_list();
  
              /* Make sure certain things are set NULL */
              autopilot->astar_path = NULL;
              autopilot->weaplist = NULL;
  
              for (i = 0; i < AUTO_PROFILE_MAX_SIZE; i++) {
                  autopilot->profile[i] = NULL;
              }
  
              /* And some things not set null */
              autopilot->speed = 100;
  
              break;
  
          case SPECIAL_FREE:
  
              /* Go through the list and remove any leftover nodes */
              while (dllist_size(autopilot->commands)) {
  
                  /* Remove the first node on the list and get the data
                   * from it */
                  temp = (command_node *) dllist_remove(autopilot->commands,
                          dllist_head(autopilot->commands));
  
                  /* Destroy the command node */
                  auto_destroy_command_node(temp);
  
              }
  
              /* Destroy the list */
              dllist_destroy_list(autopilot->commands);
              autopilot->commands = NULL;
  
              /* Destroy any astar path list thats on the AI */
              auto_destroy_astar_path(autopilot);
  
              /* Destroy profile array */
              for (i = 0; i < AUTO_PROFILE_MAX_SIZE; i++) {
                  if (autopilot->profile[i]) {
                      rb_destroy(autopilot->profile[i]);
                  }
                  autopilot->profile[i] = NULL;
              }
  
              /* Destroy weaponlist */
              auto_destroy_weaplist(autopilot);
  
              break;
  
      }
  
  }
  