btmux/autom4te.cache/
btmux/doc/.svn/
btmux/event/.svn/
btmux/game/.svn/
btmux/game/bin/.svn/
btmux/game/data/.svn/
btmux/game/logs/.svn/
btmux/game/maps/
btmux/game/maps/.svn/
btmux/game/maps/.svn/prop-base/
btmux/game/maps/.svn/props/
btmux/game/maps/.svn/text-base/
btmux/game/maps/.svn/wcprops/
btmux/game/mechs/
btmux/game/mechs/.svn/
btmux/game/mechs/.svn/prop-base/
btmux/game/mechs/.svn/props/
btmux/game/mechs/.svn/text-base/
btmux/game/mechs/.svn/wcprops/
btmux/game/text/.svn/
btmux/include/.svn/
btmux/misc/
btmux/misc/.svn/
btmux/misc/.svn/prop-base/
btmux/misc/.svn/props/
btmux/misc/.svn/text-base/
btmux/misc/.svn/wcprops/
btmux/python/
btmux/python/.svn/
btmux/python/.svn/prop-base/
btmux/python/.svn/props/
btmux/python/.svn/text-base/
btmux/python/.svn/wcprops/
btmux/src/.svn/prop-base/
btmux/src/.svn/props/
btmux/src/.svn/text-base/
btmux/src/.svn/wcprops/
btmux/src/hcode/.svn/
btmux/src/hcode/btech/
btmux/src/hcode/btech/.svn/
btmux/src/hcode/btech/.svn/prop-base/
btmux/src/hcode/btech/.svn/props/
btmux/src/hcode/btech/.svn/text-base/
btmux/src/hcode/btech/.svn/wcprops/
btmux/src/hcode/include/.svn/
/*
 * $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;

    }

}