/* * $Id: autopilot_command.c,v 1.4 2005/08/10 14:09:34 av1-op Exp $ * * Author: Markus Stenberg <fingon@iki.fi> * * Copyright (c) 1997 Markus Stenberg * Copyright (c) 1998-2002 Thomas Wouters * Copyright (c) 2000-2002 Cord Awtry * All rights reserved * * Created: Tue Sep 23 20:33:33 1997 fingon * Last modified: Sat Jun 6 21:47:38 1998 fingon * */ /* Most of the BattleSheep(tm) code is here.. */ #include <math.h> #include "mech.h" #include "autopilot.h" #include "spath.h" #include "mech.notify.h" #include "p.mech.utils.h" #include "p.mech.sensor.h" #include "p.mech.los.h" #include "p.mech.startup.h" #include "p.mech.maps.h" #include "p.ds.bay.h" #include "p.mech.maps.h" #include "p.bsuit.h" #include "p.glue.h" void sendchannelstuff(MECH * mech, int freq, char *msg); /*! \todo {Should really do away with this some how but i'm being lazy right now} */ #define Clear(a) \ auto_disengage(a->mynum, a, ""); \ auto_delcommand(a->mynum, a, "-1"); \ if (a->target >= -1) { \ if (AssignedTarget(a) && a->target != -1) { \ snprintf(buffer, SBUF_SIZE, "autogun target %d", a->target); \ } else { \ snprintf(buffer, SBUF_SIZE, "autogun on"); \ } \ auto_addcommand(a->mynum, autopilot, buffer); \ } \ #define BACMD(name) char * name (AUTO *autopilot, MECH *mech, char **args, int argc, int chn) #define ACMD(name) static BACMD(name) /* * Master list of AI - radio commands */ struct { char *sho; char *name; int args; int silent; void (*fun)(AUTO *autopilot, MECH *mech, char **args, int argc, char *mesg); } auto_cmds[] = { { "auto", "autogun", 1, 0, auto_radio_command_autogun}, { #if 0 "att", "attackleg", 1, 0, auto_attackleg}, { "chanf", "chanfreq", 2, 0, auto_setchanfreq}, { "chanm", "chanmode", 2, 0, auto_setchanmode}, { #endif "chase", "chasetarg", 1, 0, auto_radio_command_chasetarg}, { #if 0 "cm", "cmode", 2, 0, auto_cmode}, { #endif "dfo", "dfollow", 1, 0, auto_radio_command_dfollow}, { "dgo", "dgoto", 2, 0, auto_radio_command_dgoto}, { #if 0 "dr", "drally", 2, 0, auto_drally}, { "dr", "drally", 3, 0, auto_drally}, { #endif "drop", "dropoff", 0, 0, auto_radio_command_dropoff}, { "emb", "embark", 1, 0, auto_radio_command_embark}, { "en", "enterbase", 0, 0, auto_radio_command_enterbase}, { "en", "enterbase", 1, 0, auto_radio_command_enterbase}, { #if 0 "en", "enterbay", 0, 0, auto_enterbay}, { "en", "enterbay", 1, 0, auto_enterbay}, { #endif "fo", "follow", 1, 0, auto_radio_command_follow}, { #if 0 "fr", "freq", 1, 0, auto_freq}, { #endif "go", "goto", 2, 0, auto_radio_command_goto}, { "he", "heading", 1, 0, auto_radio_command_heading}, { "he", "help", 0, 1, auto_radio_command_help}, { "hi", "hide", 0, 0, auto_radio_command_hide}, { "jump", "jumpjet", 1, 0, auto_radio_command_jumpjet}, { "jump", "jumpjet", 2, 0, auto_radio_command_jumpjet}, { "le", "leavebase", 1, 0, auto_radio_command_leavebase}, { #if 0 "nog", "nogun", 0, 0, auto_nogun}, { "not", "notarget", 0, 0, auto_notarget}, { #endif "ogo", "ogoto", 2, 0, auto_radio_command_ogoto}, { "pick", "pickup", 1, 0, auto_radio_command_pickup}, { "pos", "position", 2, 0, auto_radio_command_position}, { "pr", "prone", 0, 0, auto_radio_command_prone}, { #if 0 "ra", "rally", 2, 0, auto_rally}, { "ra", "rally", 3, 0, auto_rally}, { #endif "re", "report", 0, 1, auto_radio_command_report}, { "reset", "reset", 0, 0, auto_radio_command_reset}, { #if 0 "roam", "roammode", 1, 0, auto_roammode }, { #endif "se", "sensor", 2, 0, auto_radio_command_sensor}, { "se", "sensor", 0, 0, auto_radio_command_sensor}, { "sh", "shutdown", 0, 0, auto_radio_command_shutdown}, { "sp", "speed", 1, 0, auto_radio_command_speed}, { "st", "stand", 0, 0, auto_radio_command_stand}, { "st", "startup", 0, 0, auto_radio_command_startup}, { "st", "startup", 1, 0, auto_radio_command_startup}, { "st", "stop", 0, 0, auto_radio_command_stop}, { "sw", "sweight", 2, 1, auto_radio_command_sweight}, { #if 0 "swa", "swarm", 1, 0, auto_swarm}, { "swarmc", "swarmcharge", 1, 0, auto_swarmcharge }, { "swarmm", "swarmmode", 1, 0, auto_swarmmode }, { #endif "ta", "target", 1, 0, auto_radio_command_target}, { #if 0 "ta", "target", 2, 0, auto_target}, { #endif NULL, NULL, 0, 0, NULL} }; /* * The autogun radio interface */ void auto_radio_command_autogun(AUTO *autopilot, MECH *mech, char **args, int argc, char *mesg) { if (strcmp(args[1], "on") == 0) { autopilot->target = -1; autopilot->target_score = 0; autopilot->target_update_tick = AUTO_GUN_UPDATE_TICK; /* Reset the Assigned target flag */ if (AssignedTarget(autopilot)) { UnassignTarget(autopilot); } if (Gunning(autopilot)) { DoStopGun(autopilot); } DoStartGun(autopilot); snprintf(mesg, LBUF_SIZE, "shooting at whatever I want"); return; } else if (strcmp(args[1], "off") == 0) { /* Reset the AI */ autopilot->target = -2; autopilot->target_score = 0; autopilot->target_update_tick = 0; /* Reset this flag since we don't want to be shooting anything */ if (AssignedTarget(autopilot)) { UnassignTarget(autopilot); } if (Gunning(autopilot)) DoStopGun(autopilot); snprintf(mesg, LBUF_SIZE, "powering down weapons"); return; } snprintf(mesg, LBUF_SIZE, "!Invalid Input for autogun:" " use 'on' or 'off'"); } /* * Tell the AI to chase whatever its targeting */ void auto_radio_command_chasetarg(AUTO *autopilot, MECH *mech, char **args, int argc, char *mesg) { if (strcmp(args[1], "on") == 0) { auto_set_chasetarget_mode(autopilot, AUTO_CHASETARGET_ON); snprintf(mesg, LBUF_SIZE, "Chase Target Mode is Activated"); return; } else if (strcmp(args[1], "off") == 0) { auto_set_chasetarget_mode(autopilot, AUTO_CHASETARGET_OFF); snprintf(mesg, LBUF_SIZE, "Chase Target Mode is Deactivated"); return; } snprintf(mesg, LBUF_SIZE, "!Invalid Input for chasetarg: use 'on' or 'off'"); } /* * Radio command to force AI to [dumbly] follow a given target */ void auto_radio_command_dfollow(AUTO *autopilot, MECH *mech, char **args, int argc, char *mesg) { dbref targetref; char buffer[SBUF_SIZE]; targetref = FindTargetDBREFFromMapNumber(mech, args[1]); if (targetref <= 0) { snprintf(mesg, LBUF_SIZE, "!Invalid target to follow"); return; } Clear(autopilot); snprintf(buffer, SBUF_SIZE, "dumbfollow %d", targetref); auto_addcommand(autopilot->mynum, autopilot, buffer); auto_engage(autopilot->mynum, autopilot, ""); snprintf(mesg, LBUF_SIZE, "following %s [dumbly] (%d degrees, %d away)", args[1], autopilot->ofsx, autopilot->ofsy); } /* * Radio command to force AI to [dumbly] goto a given hex */ void auto_radio_command_dgoto(AUTO *autopilot, MECH *mech, char **args, int argc, char *mesg) { int x, y; char buffer[SBUF_SIZE]; if (Readnum(x, args[1])) { snprintf(mesg, LBUF_SIZE, "!First number not an integer"); return; } if (Readnum(y, args[2])) { snprintf(mesg, LBUF_SIZE, "!First number not an integer"); return; } Clear(autopilot); snprintf(buffer, SBUF_SIZE, "dumbgoto %d %d", x, y); auto_addcommand(autopilot->mynum, autopilot, buffer); auto_engage(autopilot->mynum, autopilot, ""); snprintf(mesg, LBUF_SIZE, "going [dumbly] to %d,%d", x, y); } /* * Radio command to force AI to drop whatever its carrying */ void auto_radio_command_dropoff(AUTO *autopilot, MECH *mech, char **args, int argc, char *mesg) { char buffer[SBUF_SIZE]; Clear(autopilot); snprintf(buffer, SBUF_SIZE, "dropoff"); auto_addcommand(autopilot->mynum, autopilot, buffer); auto_engage(autopilot->mynum, autopilot, ""); snprintf(mesg, LBUF_SIZE, "dropping off"); } /* * Radio command to force AI to embark a carrier */ void auto_radio_command_embark(AUTO* autopilot, MECH *mech, char **args, int argc, char *mesg) { dbref targetref; char buffer[SBUF_SIZE]; targetref = FindTargetDBREFFromMapNumber(mech, args[1]); if (targetref <= 0) { snprintf(mesg, LBUF_SIZE, "!Invalid target to embark"); return; } Clear(autopilot); snprintf(buffer, SBUF_SIZE, "embark %d", targetref); auto_addcommand(autopilot->mynum, autopilot, buffer); auto_engage(autopilot->mynum, autopilot, ""); snprintf(mesg, LBUF_SIZE, "embarking %s", args[1]); return; } /* * Radio command to force AI to enterbase */ void auto_radio_command_enterbase(AUTO *autopilot, MECH *mech, char **args, int argc, char *mesg) { char buffer[SBUF_SIZE]; if (argc - 1) { snprintf(buffer, SBUF_SIZE, "enterbase %s", args[1]); snprintf(mesg, LBUF_SIZE, "entering base (%s side)", args[1]); } else { strncpy(buffer, "enterbase n", SBUF_SIZE); snprintf(mesg, LBUF_SIZE, "entering base"); } Clear(autopilot); auto_addcommand(autopilot->mynum, autopilot, buffer); auto_engage(autopilot->mynum, autopilot, ""); } /* * New smart follow system based on A*'s goto */ void auto_radio_command_follow(AUTO *autopilot, MECH *mech, char **args, int argc, char *mesg) { char buffer[SBUF_SIZE]; dbref targetref; targetref = FindTargetDBREFFromMapNumber(mech, args[1]); if (targetref <= 0) { snprintf(mesg, LBUF_SIZE, "!Invalid target to follow"); return; } Clear(autopilot); snprintf(buffer, SBUF_SIZE, "follow %d", targetref); auto_addcommand(autopilot->mynum, autopilot, buffer); auto_engage(autopilot->mynum, autopilot, ""); snprintf(mesg, LBUF_SIZE, "following %s (%d degrees, %d away)", args[1], autopilot->ofsx, autopilot->ofsy); } /* * Smart goto system based on Astar path finding */ void auto_radio_command_goto(AUTO *autopilot, MECH *mech, char **args, int argc, char *mesg) { int x, y; char buffer[SBUF_SIZE]; if (Readnum(x, args[1])) { snprintf(mesg, LBUF_SIZE, "!First number not integer"); return; } if (Readnum(y, args[2])) { snprintf(mesg, LBUF_SIZE, "!Second number not integer"); return; } if (MechX(mech) == x && MechY(mech) == y) { snprintf(mesg, LBUF_SIZE, "!Already in that hex"); return; } Clear(autopilot); snprintf(buffer, SBUF_SIZE, "goto %d %d", x, y); auto_addcommand(autopilot->mynum, autopilot, buffer); auto_engage(autopilot->mynum, autopilot, ""); snprintf(mesg, LBUF_SIZE, "going to %d,%d", x, y); } /* * Radio command to alter an AI's heading */ void auto_radio_command_heading(AUTO *autopilot, MECH *mech, char **args, int argc, char *mesg) { int heading; char buffer[SBUF_SIZE]; if (Readnum(heading, args[1])) { snprintf(mesg, LBUF_SIZE, "!Number not integer"); return; } Clear(autopilot); auto_engage(autopilot->mynum, autopilot, ""); snprintf(buffer, SBUF_SIZE, "%d", heading); mech_heading(autopilot->mynum, mech, buffer); strcpy(buffer, "0"); mech_speed(autopilot->mynum, mech, buffer); snprintf(buffer, LBUF_SIZE, "stopped and heading changed to %d", heading); } /* * Help message, lists the various commands for the AI */ void auto_radio_command_help(AUTO *autopilot, MECH *mech, char **args, int argc, char *mesg) { int i; /*! \todo {Add a short form of this command} */ snprintf(mesg, LBUF_SIZE, "The following commands are possible:"); for (i = 0; auto_cmds[i].name; i++) { if (i > 0 && !strcmp(auto_cmds[i].name, auto_cmds[i-1].name)) continue; strncat(mesg, " ", LBUF_SIZE); strncat(mesg, auto_cmds[i].name, LBUF_SIZE); } auto_reply(mech, mesg); } /* * Radio command to force AI to try and hide itself */ void auto_radio_command_hide(AUTO *autopilot, MECH *mech, char **args, int argc, char *mesg) { if ((HasCamo(mech)) ? 0 : MechType(mech) != CLASS_BSUIT && MechType(mech) != CLASS_MW) { snprintf(mesg, LBUF_SIZE, "!Last I checked I was kind of big for that"); return; } if (!(MechRTerrain(mech) == HEAVY_FOREST || MechRTerrain(mech) == LIGHT_FOREST || MechRTerrain(mech) == ROUGH || MechRTerrain(mech) == MOUNTAINS || (MechType(mech) == CLASS_BSUIT ? MechRTerrain(mech) == BUILDING : 0))) { snprintf(mesg, LBUF_SIZE, "!Invalid Terrain"); return; } bsuit_hide(autopilot->mynum, mech, ""); snprintf(mesg, LBUF_SIZE, "Begining to hide"); } /* * Radio command to force AI to jump either on a target or * in a given direction range */ void auto_radio_command_jumpjet(AUTO *autopilot, MECH *mech, char **args, int argc, char *mesg) { dbref target; char buffer[SBUF_SIZE]; int bear, rng; if (!abs(MechJumpSpeed(mech))) { snprintf(mesg, LBUF_SIZE, "!I don't do hiphop and jump around"); return; } if ((argc - 1) == 1) { if ((target = FindTargetDBREFFromMapNumber(mech, args[1])) <= 0) { snprintf(mesg, LBUF_SIZE, "!Unable to see such a target"); return; } strcpy(buffer, args[1]); mech_jump(autopilot->mynum, mech, buffer); snprintf(mesg, LBUF_SIZE, "jumping on [%s]", args[1]); return; } else { if (Readnum(bear, args[1])) { snprintf(mesg, LBUF_SIZE, "!Invalid bearing"); return; } if (Readnum(rng, args[2])) { snprintf(mesg, LBUF_SIZE, "!Invalid range"); return; } snprintf(buffer, SBUF_SIZE, "%s %s", args[1], args[2]); mech_jump(autopilot->mynum, mech, buffer); snprintf(mesg, LBUF_SIZE, "jump %s degrees %s hexes", args[1], args[2]); return; } } /* * Radio command to force AI to leavebase */ void auto_radio_command_leavebase(AUTO *autopilot, MECH *mech, char **args, int argc, char *mesg) { char buffer[SBUF_SIZE]; int direction; if (Readnum(direction, args[1])) { snprintf(mesg, LBUF_SIZE, "!Invalid value for direction"); return; } /* Make sure chasetarget doesn't interfere with this */ if (ChasingTarget(autopilot)) { StopChasingTarget(autopilot); } Clear(autopilot); snprintf(buffer, SBUF_SIZE, "leavebase %d", direction); auto_addcommand(autopilot->mynum, autopilot, buffer); auto_engage(autopilot->mynum, autopilot, ""); snprintf(mesg, LBUF_SIZE, "leaving base at %d heading", direction); } /* * Old goto system - will phase out */ void auto_radio_command_ogoto(AUTO *autopilot, MECH *mech, char **args, int argc, char *mesg) { int x, y; char buffer[SBUF_SIZE]; if (Readnum(x, args[1])) { snprintf(mesg, LBUF_SIZE, "!First number not integer"); return; } if (Readnum(y, args[2])) { snprintf(mesg, LBUF_SIZE, "!Second number not integer"); return; } Clear(autopilot); snprintf(buffer, SBUF_SIZE, "oldgoto %d %d", x, y); auto_addcommand(autopilot->mynum, autopilot, buffer); auto_engage(autopilot->mynum, autopilot, ""); snprintf(mesg, LBUF_SIZE, "going [old version] to %d,%d", x, y); } /* * Radio command to force AI to pickup a target */ void auto_radio_command_pickup(AUTO *autopilot, MECH *mech, char **args, int argc, char *mesg) { dbref targetref; char buffer[SBUF_SIZE]; targetref = FindTargetDBREFFromMapNumber(mech, args[1]); if (targetref <= 0) { snprintf(mesg, LBUF_SIZE, "!Invalid target to pickup"); return; } /* Make sure chasetarget doesn't interfere with this */ if (ChasingTarget(autopilot)) { StopChasingTarget(autopilot); } Clear(autopilot); snprintf(buffer, SBUF_SIZE, "pickup %d", targetref); auto_addcommand(autopilot->mynum, autopilot, buffer); auto_engage(autopilot->mynum, autopilot, ""); snprintf(mesg, LBUF_SIZE, "picking up %s", args[1]); } /* * Radio command to make AI take up a given position (dir & range) from * their current target (hex or unit) */ void auto_radio_command_position(AUTO *autopilot, MECH *mech, char **args, int argc, char *mesg) { int x, y; /*! \todo {Add in some checks for validity of the arguments} */ if (Readnum(x, args[1])) { snprintf(mesg, LBUF_SIZE, "!Invalid first int"); return; } if (Readnum(y, args[2])) { snprintf(mesg, LBUF_SIZE, "!Invalide second int"); return; } autopilot->ofsx = x; autopilot->ofsy = y; snprintf(mesg, LBUF_SIZE, "following %d degrees, %d away", x, y); } /* * Radio command to force AI to go prone */ void auto_radio_command_prone(AUTO *autopilot, MECH *mech, char **args, int argc, char *mesg) { mech_drop(autopilot->mynum, mech, ""); snprintf(mesg, LBUF_SIZE, "hitting the deck"); } /* * Radio command so the AI can report its status */ /*! \todo {Add something that tells more info then this} */ void auto_radio_command_report(AUTO *autopilot, MECH *mech, char **args, int argc, char *mesg) { char buffer[MBUF_SIZE]; MECH *target; /* Is the AI moving or something */ if (Jumping(mech)) strcpy(buffer, "Jumping"); else if (Fallen(mech)) strcpy(buffer, "Prone"); else if (IsRunning(MechSpeed(mech), MMaxSpeed(mech))) strcpy(buffer, "Running"); else if (MechSpeed(mech) > 1.0) strcpy(buffer, "Walking"); else strcpy(buffer, "Standing"); snprintf(mesg, LBUF_SIZE, "%s at %d, %d", buffer, MechX(mech), MechY(mech)); /* Which way is the AI going */ if (MechSpeed(mech) > 1.0) { snprintf(buffer, MBUF_SIZE, ", headed %d speed %.2f", MechFacing(mech), MechSpeed(mech)); strncat(mesg, buffer, LBUF_SIZE); } else { snprintf(buffer, MBUF_SIZE, ", headed %d", MechFacing(mech)); strncat(mesg, buffer, LBUF_SIZE); } /* Is the AI targeting something */ if (MechTarget(mech) != -1) { target = getMech(MechTarget(mech)); if (target) { snprintf(buffer, MBUF_SIZE, ", targeting %s %s", GetMechToMechID(mech, target), InLineOfSight(mech, target, MechX(target), MechY(target), FaMechRange(mech, target)) ? "" : "(not in LOS)"); strncat(mesg, buffer, LBUF_SIZE); } } /* Send the mesg to the reply system, this is a silent command */ auto_reply(mech, mesg); } /* * Radio command to reset the AI's internal flags what not */ void auto_radio_command_reset(AUTO *autopilot, MECH *mech, char **args, int argc, char *mesg) { char buffer[SBUF_SIZE]; auto_disengage(autopilot->mynum, autopilot, ""); auto_delcommand(autopilot->mynum, autopilot, "-1"); auto_init(autopilot, mech); auto_engage(autopilot->mynum, autopilot, ""); snprintf(mesg, LBUF_SIZE, "all internal events and flags reset!"); } /* * Radio command to alter or let the AI alter * its sensors */ void auto_radio_command_sensor(AUTO *autopilot, MECH *mech, char **args, int argc, char *mesg) { char buf[SBUF_SIZE]; if (argc) { /* Make sure no sensor event running */ muxevent_remove_type_data(EVENT_AUTO_SENSOR, autopilot); /* Set the user specified sensors */ snprintf(buf, SBUF_SIZE, "%s %s", args[1], args[2]); mech_sensor(autopilot->mynum, mech, buf); autopilot->flags |= AUTOPILOT_LSENS; snprintf(mesg, LBUF_SIZE, "updated my sensors"); return; } /* Let AI decide */ autopilot->flags &= ~AUTOPILOT_LSENS; UpdateAutoSensor(autopilot, 0); snprintf(mesg, LBUF_SIZE, "using my own judgement with sensors"); return; } /* * Radio command to force AI to shutdown */ void auto_radio_command_shutdown(AUTO *autopilot, MECH *mech, char **args, int argc, char *mesg) { mech_shutdown(autopilot->mynum, mech, ""); snprintf(mesg, LBUF_SIZE, "shutting down"); } /* * Radio command to alter the speed of an AI (% of speed) */ void auto_radio_command_speed(AUTO *autopilot, MECH *mech, char **args, int argc, char *mesg) { int speed = 100; if (Readnum(speed, args[1])) { snprintf(mesg, LBUF_SIZE, "!Invalid value - not a number"); return; } if (speed < 1 || speed > 100) { snprintf(mesg, LBUF_SIZE, "!Invalid speed"); return; } autopilot->speed = speed; snprintf(mesg, LBUF_SIZE, "setting speed to %d %%", speed); } /* * Radio Command to force AI to stand */ void auto_radio_command_stand(AUTO *autopilot, MECH *mech, char **args, int argc, char *mesg) { mech_stand(autopilot->mynum, mech, ""); snprintf(mesg, LBUF_SIZE, "standing up"); } /* * Radio command to force AI to startup */ void auto_radio_command_startup(AUTO *autopilot, MECH *mech, char **args, int argc, char *mesg) { if (argc > 1) { if (!strncasecmp(args[1], "override", strlen(args[1]))) { mech_startup(autopilot->mynum, mech, "override"); snprintf(mesg, LBUF_SIZE, "emergency override startup triggered"); return; } } mech_startup(autopilot->mynum, mech, ""); snprintf(mesg, LBUF_SIZE, "starting up"); } /* * Radio command to stop the AI */ void auto_radio_command_stop(AUTO *autopilot, MECH *mech, char **args, int argc, char *mesg) { char buffer[SBUF_SIZE]; strcpy(buffer, "0"); /* Turn chasetarget off */ auto_set_chasetarget_mode(autopilot, AUTO_CHASETARGET_OFF); Clear(autopilot); auto_engage(autopilot->mynum, autopilot, ""); mech_speed(autopilot->mynum, mech, buffer); snprintf(mesg, LBUF_SIZE, "halting"); } /* * Command for the old goto, will phase it out */ void auto_radio_command_sweight(AUTO *autopilot, MECH *mech, char **args, int argc, char *mesg) { int x, y; if (Readnum(x, args[1])) { snprintf(mesg, LBUF_SIZE, "!Invalid first int"); return; } if (Readnum(y, args[2])) { snprintf(mesg, LBUF_SIZE, "!Invalide second int"); return; } x = MAX(1, x); y = MAX(1, y); autopilot->auto_goweight = x; autopilot->auto_fweight = y; snprintf(mesg, LBUF_SIZE, "sweight'ed to %d:%d. (go:fight)", x, y); return; } /* * Tell the AI to target a specific unit */ void auto_radio_command_target(AUTO *autopilot, MECH *mech, char **args, int argc, char *mesg) { dbref targetref; if (!strcmp(args[1], "-")) { /* Basicly doing the same as 'autogun on' */ autopilot->target = -1; autopilot->target_score = 0; autopilot->target_update_tick = AUTO_GUN_UPDATE_TICK; if (AssignedTarget(autopilot)) { UnassignTarget(autopilot); } if (Gunning(autopilot)) { DoStopGun(autopilot); } DoStartGun(autopilot); snprintf(mesg, LBUF_SIZE, "shooting at whatever I want"); return; } else { targetref = FindTargetDBREFFromMapNumber(mech, args[1]); if (targetref <= 0) { snprintf(mesg, LBUF_SIZE, "!Unable to see such a target"); return; } } autopilot->target = targetref; autopilot->target_score = 0; autopilot->target_update_tick = 0; /* Let the AI know its an assigned target */ if(!AssignedTarget(autopilot)) { AssignTarget(autopilot); } if (Gunning(autopilot)) { DoStopGun(autopilot); } DoStartGun(autopilot); snprintf(mesg, LBUF_SIZE, "aiming for [%s] (and ignoring everyone else)", args[1]); } #if 0 ACMD(auto_swarm) { dbref targetref; if (!mech || MechType(mech) != CLASS_BSUIT) return "!Not a bsuit"; targetref = FindTargetDBREFFromMapNumber(mech, args[0]); if (targetref <= 0) return "!Invalid target to swarm"; Clear(a); auto_addcommand(a->mynum, a, tprintf("swarm %d", targetref)); auto_engage(a->mynum, a, ""); return tprintf("swarming %s.", args[0]); } #endif #if 0 ACMD(auto_attackleg) { dbref targetref; if (!mech || MechType(mech) != CLASS_BSUIT) return "!Not a bsuit"; targetref = FindTargetDBREFFromMapNumber(mech, args[0]); if (targetref <= 0) return "!Invalid target to attackleg"; Clear(a); auto_addcommand(a->mynum, a, tprintf("attackleg %d", targetref)); auto_engage(a->mynum, a, ""); return tprintf("attacklegging %s.", args[0]); } #endif #if 0 ACMD(auto_notarget) { a->targ = -1; if (Gunning(a)) { DoStopGun(a); DoStartGun(a); } return "shooting at anything that moves"; } #endif #if 0 ACMD(auto_nogun) { a->targ = -2; if (Gunning(a)) DoStopGun(a); return "powering down weapons"; } #endif #if 0 ACMD(auto_rally) { char xb[6], yb[6]; int x, y, h; if (Readnum(x, args[0])) return "!Invalid X coord"; if (Readnum(y, args[1])) return "!Invalid Y coord"; if (argc < 3) h = MechFacing(mech); else if (Readnum(h, args[2])) return "!Invalid heading"; /* Base things on the <h = heading> */ x = x + a->ofsy * cos(TWOPIOVER360 * (270 + (a->ofsx + h))); y = y + a->ofsy * sin(TWOPIOVER360 * (270 + (a->ofsx + h))); sprintf(xb, "%d", x); sprintf(yb, "%d", y); args[0] = xb; args[1] = yb; return auto_goto(a, mech, args, 2, chn); } #endif #if 0 ACMD(auto_drally) { char xb[6], yb[6]; int x, y, h; if (Readnum(x, args[0])) return "!Invalid X coord"; if (Readnum(y, args[1])) return "!Invalid Y coord"; if (argc < 3) h = MechFacing(mech); else if (Readnum(h, args[2])) return "!Invalid heading"; /* Base things on the <h = heading> */ x = x + a->ofsy * cos(TWOPIOVER360 * (270 + (a->ofsx + h))); y = y + a->ofsy * sin(TWOPIOVER360 * (270 + (a->ofsx + h))); sprintf(xb, "%d", x); sprintf(yb, "%d", y); args[0] = xb; args[1] = yb; return auto_dgoto(a, mech, args, 2, chn); } #endif #if 0 ACMD(auto_roammode) { if (strcmp(args[0], "on") == 0) { Clear(a); auto_addcommand(a->mynum, a, tprintf("roammode 1")); auto_engage(a->mynum, a, ""); return "Roam mode is ON"; } else if (strcmp(args[0], "off") == 0) { Clear(a); auto_addcommand(a->mynum, a, tprintf("roammode 0")); auto_engage(a->mynum, a, ""); return "Roam mode is OFF"; } return "!Invalid input use on or off"; } #endif #if 0 ACMD(auto_swarmmode) { if (MechType(mech) != CLASS_BSUIT) return "!I am not a battlesuit"; if (strcmp(args[0], "on") == 0) { a->flags |= AUTOPILOT_SWARMCHARGE; return "Swarm Mode is ON"; } else if (strcmp(args[0], "off") == 0) { a->flags &= ~AUTOPILOT_SWARMCHARGE; return "Swarm Mode is OFF"; } return "!Invalid input use on or off"; } #endif #if 0 ACMD(auto_swarmcharge) { dbref targetref; if (MechType(mech) != CLASS_BSUIT) return "!I am not a battlesuit"; if (strcmp(args[0], "cancel") == 0) { a->flags &= ~AUTOPILOT_SWARMCHARGE; return "Canceling swarm charge"; } targetref = FindTargetDBREFFromMapNumber(mech, args[0]); if (targetref <= 0) return "!Invalid target to swarmcharge"; Clear(a); auto_addcommand(a->mynum, a, tprintf("dumbfollow %d", targetref)); auto_engage(a->mynum, a, ""); a->flags |= AUTOPILOT_SWARMCHARGE; return tprintf("swarmcharging %s (%d degrees, %d away)", args[0], a->ofsx, a->ofsy); } #endif #if 0 ACMD(auto_freq) { int freq; if (Readnum(freq, args[0])) return "!Invalid freq"; mech_set_channelfreq(a->mynum, mech, tprintf("a=%s", args[0])); return "channel changed"; } #endif #if 0 ACMD(auto_setchanfreq) { mech_set_channelfreq(a->mynum, mech, tprintf("%s=%s", args[0], args[1])); return tprintf("set channelfreq %s=%s", args[0], args[1]); } #endif #if 0 ACMD(auto_setchanmode) { mech_set_channelmode(a->mynum, mech, tprintf("%s=%s", args[0], args[1])); return tprintf("set channelmode %s=%s", args[0], args[1]); } #endif #if 0 ACMD(auto_enterbay) { mech_enterbay(a->mynum, mech, argc ? tprintf("%s", args[0]) : tprintf("")); return argc ? tprintf("entering bay (of %s)", args[0]) : "entering bay"; } #endif #if 0 ACMD(auto_cmode) { int mod, ran; static char buf[MBUF_SIZE]; if (Readnum(mod, args[0])) return "!Invalid mode [0-2]"; if (mod < 0 || mod > 2) return "!Invalid mode [0-2]"; if (Readnum(ran, args[1])) return "!Invalid range [0-999]"; if (ran < 0 || ran > 999) return "!Invalid range [0-999]"; a->auto_cdist = ran; a->auto_cmode = mod; switch (mod) { case 0: sprintf(buf, "fleeing, at least to range %d {from all foes}", ran); break; case 1: sprintf(buf, "trying to maintain range %d {from all foes}", ran); break; case 2: sprintf(buf, "charging to range %d {from all foes}", ran); break; } return buf; } #endif /* * Event to get AI to radio a message */ void auto_reply_event(MUXEVENT *muxevent) { MECH *mech = (MECH *) muxevent->data; char *buf = (char *) muxevent->data2; MAP *map; /* Make sure its a mech */ if (!IsMech(mech->mynum)) { free(buf); return; } /* If valid object */ if (mech) if ((map = (getMap(mech->mapindex)))) sendchannelstuff(mech, 0, buf); free(buf); } /* * Force the AI to reply over radio */ void auto_reply(MECH *mech, char *buf) { char *reply; /* No zero freq messages */ if (!mech->freq[0]) return; /* Make sure there is an autopilot */ if (MechAuto(mech) <= 0) return; /* Make sure valid objects */ if (!(FindObjectsData(MechAuto(mech))) || !Good_obj(MechAuto(mech)) || Location(MechAuto(mech)) != mech->mynum) { MechAuto(mech) = -1; return; } /* Copy the buffer */ reply = strdup(buf); if (reply) { MECHEVENT(mech, EVENT_AUTO_REPLY, auto_reply_event, Number(1, 2), reply); } else { SendAI("Interal AI Error: Attempting to radio reply but unable to copy string"); } } /* * Parse an AI radio command */ void auto_parse_command(AUTO *autopilot, MECH *mech, int chn, char *buffer) { int argc, cmd; char *args[2]; char *command_args[AUTOPILOT_MAX_ARGS]; char mech_id[3]; char message[LBUF_SIZE]; char reply[LBUF_SIZE]; int i; /* Basic checks */ if (!autopilot || !mech) return; if (Destroyed(mech)) return; /* Get the args - just need the first one */ if (proper_explodearguments(buffer, args, 2) < 2) { /* free args */ for(i = 0; i < 2; i++) { if(args[i]) free(args[i]); } return; } /* Check to see if the command was given to this AI */ if (strcmp(args[0], "all")) { mech_id[0] = MechID(mech)[0]; mech_id[1] = MechID(mech)[1]; mech_id[2] = '\0'; if (strcasecmp(mech_id, args[0])) { /* free args */ for(i = 0; i < 2; i++) { if(args[i]) free(args[i]); } return; } } /* Parse the command */ cmd = -1; argc = proper_explodearguments(args[1], command_args, AUTOPILOT_MAX_ARGS); /* Loop through the various possible commands looking for ours */ for (i = 0; auto_cmds[i].sho; i++) { if (!strncmp(auto_cmds[i].sho, command_args[0], strlen(auto_cmds[i].sho))) if (!strncmp(auto_cmds[i].name, command_args[0], strlen(command_args[0]))) { if (argc == (auto_cmds[i].args + 1)) { cmd = i; break; } } } /* Did we find a command */ if (cmd < 0) { snprintf(message, LBUF_SIZE, "Unable to comprehend the command."); auto_reply(mech, message); /* free args */ for(i = 0; i < 2; i++) { if(args[i]) free(args[i]); } for (i = 0; i < AUTOPILOT_MAX_ARGS; i++) { if (command_args[i]) free(command_args[i]); } return; } /* Zero the buffer */ memset(message, 0, sizeof(message)); memset(reply, 0, sizeof(reply)); /* Call the radio command function */ (*(auto_cmds[cmd].fun)) (autopilot, mech, command_args, argc, message); /* If its a silent command there is no reply */ if (auto_cmds[cmd].silent) { /* Free args and exit */ for(i = 0; i < 2; i++) { if(args[i]) free(args[i]); } for (i = 0; i < AUTOPILOT_MAX_ARGS; i++) { if (command_args[i]) free(command_args[i]); } return; } /* Check to see if a message was returned */ if (*message) { /* Check if there was an error message * otherwise add a front and back to the message */ if (message[0] == '!') { snprintf(reply, LBUF_SIZE, "ERROR: %s!", message + 1); } else { switch (Number(0, 20)) { case 0: case 1: case 2: case 4: snprintf(reply, LBUF_SIZE, "%s%s%s", "Affirmative, ", message, "."); break; case 5: snprintf(reply, LBUF_SIZE, "%s%s%s", "Nod, ", message, "."); break; case 6: snprintf(reply, LBUF_SIZE, "%s%s%s", "Fine, ", message, "."); break; case 7: snprintf(reply, LBUF_SIZE, "%s%s%s", "Aye aye, Captain, ", message, "!"); break; case 8: case 9: case 10: snprintf(reply, LBUF_SIZE, "%s%s%s", "Da, boss, ", message, "!"); break; case 11: case 12: snprintf(reply, LBUF_SIZE, "%s%s%s", "Ok, ", message, "."); break; case 13: snprintf(reply, LBUF_SIZE, "%s%s%s", "Okay, okay, ", message, ", happy now?"); break; case 14: snprintf(reply, LBUF_SIZE, "%s%s%s", "Okidoki, ", message, "!"); break; case 15: case 16: case 17: snprintf(reply, LBUF_SIZE, "%s%s%s", "Aye, ", message, "."); break; default: snprintf(reply, LBUF_SIZE, "%s%s%s", "Roger, Roger, ", message, "."); break; } /* End of switch */ } auto_reply(mech, reply); } else if (!auto_cmds[cmd].silent) { /* Command isn't silent but it didn't return a message */ snprintf(reply, LBUF_SIZE, "Ok."); auto_reply(mech, reply); } /* free args */ for(i = 0; i < 2; i++) { if(args[i]) free(args[i]); } for (i = 0; i < AUTOPILOT_MAX_ARGS; i++) { if (command_args[i]) free(command_args[i]); } }