/* * $Id: mech.notify.c,v 1.6 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 * Copyright (c) 1999-2005 Kevin Stevens * All rights reserved * * Last modified: Tue Oct 6 17:17:03 1998 fingon * */ #include <stdio.h> #include <stdlib.h> #include <math.h> #include <sys/file.h> #include "mech.h" #include "mech.events.h" #include "autopilot.h" #include "failures.h" #include "p.mech.los.h" #include "p.mine.h" #include "p.mech.utils.h" #include "p.mech.build.h" #include "p.mech.startup.h" #include "p.autopilot_command.h" #include "p.btechstats.h" #include "p.mech.sensor.h" #include "p.map.obj.h" #include "p.bsuit.h" void sendchannelstuff(MECH * mech, int freq, char *msg); const char *GetAmmoDesc_Model_Mode(int model, int mode) { if (mode & LBX_MODE) return " Shotgun"; if (mode & ARTEMIS_MODE) return " Artemis IV"; if (mode & NARC_MODE) return (MechWeapons[model].special & NARC) ? " Explosive" : " Narc compatible"; if (mode & INARC_EXPLO_MODE) return " iExplosive"; if (mode & INARC_HAYWIRE_MODE) return " Haywire"; if (mode & INARC_ECM_MODE) return " ECM"; if (mode & INARC_NEMESIS_MODE) return " Nemesis"; if (mode & SWARM_MODE) return " Swarm"; if (mode & SWARM1_MODE) return " Swarm1"; if (mode & INFERNO_MODE) return " Inferno"; if (mode & CLUSTER_MODE) return " Cluster"; if (mode & SMOKE_MODE) return " Smoke"; if (mode & MINE_MODE) return " Mine"; if (mode & AC_AP_MODE) return " ArmorPiercing"; if (mode & AC_FLECHETTE_MODE) return " Flechette"; if (mode & AC_INCENDIARY_MODE) return " Incendiary"; if (mode & AC_PRECISION_MODE) return " Precision"; if (mode & STINGER_MODE) return " Stinger"; return ""; } char GetWeaponAmmoModeLetter_Model_Mode(int model, int mode) { if (!(mode & AMMO_MODES)) return ' '; if (mode & CLUSTER_MODE) return 'C'; if (mode & SMOKE_MODE) return 'S'; if (mode & MINE_MODE) return 'M'; if (mode & LBX_MODE) return 'L'; if (mode & ARTEMIS_MODE) return 'A'; if (mode & NARC_MODE) return (MechWeapons[model].special & NARC) ? 'E' : 'N'; if (mode & INARC_EXPLO_MODE) return 'X'; if (mode & INARC_HAYWIRE_MODE) return 'Y'; if (mode & INARC_ECM_MODE) return 'E'; if (mode & INARC_NEMESIS_MODE) return 'Z'; if (mode & INFERNO_MODE) return 'I'; if (mode & SWARM_MODE) return 'W'; if (mode & SWARM1_MODE) return '1'; if (mode & AC_AP_MODE) return 'R'; if (mode & AC_FLECHETTE_MODE) return 'F'; if (mode & AC_INCENDIARY_MODE) return 'D'; if (mode & AC_PRECISION_MODE) return 'P'; if (mode & STINGER_MODE) return 'T'; return ' '; } char GetWeaponFireModeLetter_Model_Mode(int model, int mode) { if (!(mode & FIRE_MODES)) return ' '; if (mode & HOTLOAD_MODE) return 'H'; if (mode & ULTRA_MODE) return 'U'; if (mode & RFAC_MODE) return 'F'; if (mode & GATTLING_MODE) return 'G'; if (mode & HEAT_MODE) return 'H'; if (mode & RAC_TWOSHOT_MODE) return '2'; if (mode & RAC_FOURSHOT_MODE) return '4'; if (mode & RAC_SIXSHOT_MODE) return '6'; return ' '; } char GetWeaponAmmoModeLetter(MECH * mech, int loop, int crit) { return GetWeaponAmmoModeLetter_Model_Mode(Weapon2I(GetPartType(mech, loop, crit)), GetPartAmmoMode(mech, loop, crit)); } char GetWeaponFireModeLetter(MECH * mech, int loop, int crit) { return GetWeaponFireModeLetter_Model_Mode(Weapon2I(GetPartType(mech, loop, crit)), GetPartFireMode(mech, loop, crit)); } const char *GetMoveTypeID(int movetype) { static char buf[20]; switch (movetype) { case MOVE_QUAD: strcpy(buf, "QUAD"); break; case MOVE_BIPED: strcpy(buf, "BIPED"); break; case MOVE_TRACK: strcpy(buf, "TRACKED"); break; case MOVE_WHEEL: strcpy(buf, "WHEELED"); break; case MOVE_HOVER: strcpy(buf, "HOVER"); break; case MOVE_VTOL: strcpy(buf, "VTOL"); break; case MOVE_FLY: strcpy(buf, "FLY"); break; case MOVE_HULL: strcpy(buf, "HULL"); break; case MOVE_SUB: strcpy(buf, "SUBMARINE"); break; case MOVE_FOIL: strcpy(buf, "HYDROFOIL"); break; default: strcpy(buf, "Unknown"); break; } return buf; } struct { char *onmsg; char *offmsg; int flag; int infolvl; } temp_flag_info_struct[] = { { "DESTROYED", NULL, DESTROYED, 1}, { NULL, "SHUTDOWN", STARTED, 1}, { "Torso is 60 degrees right", NULL, TORSO_RIGHT, 0}, { "Torso is 60 degrees left", NULL, TORSO_LEFT, 0}, { NULL, NULL, 0} }; struct { int team; char *ccode; } obs_team_color[] = { { 1, "%cw" }, { 2, "%cc" }, { 3, "%cm" }, { 4, "%cb" }, { 5, "%cy" }, { 6, "%cg" }, { 7, "%cr" }, { 8, "%ch%cx" }, { 9, "%ch%cw" }, { 10, "%ch%cc" }, { 11, "%ch%cm" }, { 12, "%ch%cb" }, { 13, "%ch%cy" }, { 14, "%ch%cg" }, { 15, "%ch%cr" }, { 0, "%ch%cw" } }; void Mech_ShowFlags(dbref player, MECH * mech, int spaces, int level) { char buf[MBUF_SIZE]; int i; for (i = 0; i < spaces; i++) buf[i] = ' '; buf[spaces] = 0; if (MechStatus(mech) & COMBAT_SAFE) { strcpy(buf + spaces, "%cb%chCOMBAT SAFE%cn"); notify(player, buf); } if (Fallen(mech)) { switch (MechMove(mech)) { case MOVE_BIPED: strcpy(buf + spaces, "%cr%chFALLEN%cn"); break; case MOVE_QUAD: strcpy(buf + spaces, "%cr%chFALLEN%cn"); break; case MOVE_TRACK: strcpy(buf + spaces, "%cr%chTRACK DESTROYED%cn"); break; case MOVE_WHEEL: strcpy(buf + spaces, "%cr%chAXLE DESTROYED%cn"); break; case MOVE_HOVER: strcpy(buf + spaces, "%cr%chLIFT FAN DESTROYED%cn"); break; case MOVE_VTOL: strcpy(buf + spaces, "%cr%chROTOR DESTROYED%cn"); break; case MOVE_FLY: strcpy(buf + spaces, "%cr%chENGINE DESTROYED%cn"); break; case MOVE_HULL: strcpy(buf + spaces, "%cr%chENGINE ROOM DESTROYED%cn"); break; case MOVE_SUB: strcpy(buf + spaces, "%cr%chENGINE ROOM DESTROYED%cn"); break; case MOVE_FOIL: strcpy(buf + spaces, "%cr%chFOIL DESTROYED%cn"); break; } notify(player, buf); } if (IsHulldown(mech)) { strcpy(buf + spaces, "%cg%chHULLDOWN%cn"); notify(player, buf); } if (MechDugIn(mech)) { strcpy(buf + spaces, "%cg%chDUG IN%cn"); notify(player, buf); } if (Digging(mech)) { strcpy(buf + spaces, "%cgDIGGING IN%cn"); notify(player, buf); } if (Staggering(mech)) { strcpy(buf + spaces, "%cr%chSTAGGERING%cn"); notify(player, buf); } if (MechCritStatus(mech) & SLITE_DEST) { strcpy(buf + spaces, "%cr%chSEARCHLIGHT DESTROYED%cn"); notify(player, buf); } if (MechLites(mech)) { strcpy(buf + spaces, "%cg%chSEARCHLIGHT ON%cn"); notify(player, buf); } else if (MechLit(mech)) { strcpy(buf + spaces, "%cg%chILLUMINATED%cn"); notify(player, buf); } if (Burning(mech) || Jellied(mech)) { strcpy(buf + spaces, "%cr%chON FIRE%cn"); notify(player, buf); } if (MechCritStatus(mech) & HIDDEN) { strcpy(buf + spaces, tprintf("%%ch%%cgHIDDEN%%c")); notify(player, buf); } if (IsMechSwarmed(mech)) { strcpy(buf + spaces, "%cr%chSWARMED BY ENEMY SUITS%cn"); notify(player, buf); } if (IsMechMounted(mech)) { strcpy(buf + spaces, "%cr%chMOUNTED BY FRIENDLY SUITS%cn"); notify(player, buf); } if (MechSwarmTarget(mech) > 0) { if (getMech(MechSwarmTarget(mech))) { if (MechTeam(getMech(MechSwarmTarget(mech))) == MechTeam(mech)) strcpy(buf + spaces, "%cg%chMOUNTED ON FRIENDLY UNIT%cn"); else strcpy(buf + spaces, "%cg%chSWARMING ENEMY UNIT%cn"); notify(player, buf); } } #ifdef BT_MOVEMENT_MODES if (MechStatus2(mech) & DODGING) { strcpy(buf + spaces, tprintf("%%ch%%crDODGING%%c")); notify(player, buf); } if (MechStatus2(mech) & EVADING) { strcpy(buf + spaces, tprintf("%%ch%%crEVADING%%c")); notify(player, buf); } if (MechStatus2(mech) & SPRINTING) { strcpy(buf + spaces, tprintf("%%ch%%crSPRINTING%%c")); notify(player, buf); } if (MoveModeChange(mech)) { strcpy(buf + spaces, tprintf("%%ch%%cyCHANGING MOVEMENT MODE%%c")); notify(player, buf); } if (SideSlipping(mech)) { strcpy(buf + spaces, tprintf("%%ch%%cySIDESLIPPING%%c")); notify(player,buf); } if (MechCritStatus(mech) & CREW_STUNNED || MechCritStatus(mech) & MECH_STUNNED) { strcpy(buf + spaces, "%ch%crSTUNNED%c"); notify(player, buf); } #endif if (level == 0) { /* our own 'status' */ if (ECMProtected(mech)) { strcpy(buf + spaces, "%cg%chPROTECTED BY ECM%cn"); notify(player, buf); } if (AngelECMProtected(mech)) { strcpy(buf + spaces, "%cg%chPROTECTED BY ANGEL ECM%cn"); notify(player, buf); } if (ECMDisturbed(mech)) { strcpy(buf + spaces, "%cy%chAFFECTED BY ECM%cn"); notify(player, buf); } if (AngelECMDisturbed(mech)) { strcpy(buf + spaces, "%cy%chAFFECTED BY ANGEL ECM%cn"); notify(player, buf); } if (ECMCountered(mech)) { strcpy(buf + spaces, "%cy%chCOUNTERED BY ECCM%cn"); notify(player, buf); } if (StealthArmorActive(mech)) { strcpy(buf + spaces, "%cg%chSTEALTH ARMOR ACTIVE%cn"); notify(player, buf); } if (NullSigSysActive(mech)) { strcpy(buf + spaces, "%cg%chNULL SIGNATURE SYSTEM ACTIVE%cn"); notify(player, buf); } if (checkAllSections(mech, NARC_ATTACHED)) { strcpy(buf + spaces, "%cy%chNARC POD ATTACHED%cn"); notify(player, buf); } if (checkAllSections(mech, INARC_HOMING_ATTACHED)) { strcpy(buf + spaces, "%cy%chINARC HOMING POD ATTACHED%cn"); notify(player, buf); } if (checkAllSections(mech, INARC_HAYWIRE_ATTACHED)) { strcpy(buf + spaces, "%cy%chINARC HAYWIRE POD ATTACHED%cn"); notify(player, buf); } if (checkAllSections(mech, INARC_ECM_ATTACHED)) { strcpy(buf + spaces, "%cy%chINARC ECM POD ATTACHED%cn"); notify(player, buf); } if (Extinguishing(mech)) { strcpy(buf + spaces, "%cy%chEXTINGUISHING FIRE%cn"); notify(player, buf); } if (MechStatus2(mech) & AUTOTURN_TURRET) { strcpy(buf + spaces, "%cg%chTURRET AUTO-TURN ENGAGED%cn"); notify(player, buf); } if (MechSections(mech)[RARM].specials & CARRYING_CLUB) { strcpy(buf + spaces, "%cg%chCARRYING CLUB - RIGHT ARM%cn"); notify(player, buf); } if (MechSections(mech)[LARM].specials & CARRYING_CLUB) { strcpy(buf + spaces, "%cg%chCARRYING CLUB - LEFT ARM%cn"); notify(player, buf); } } for (i = 0; temp_flag_info_struct[i].flag; i++) if (temp_flag_info_struct[i].infolvl >= level) { if (MechStatus(mech) & temp_flag_info_struct[i].flag) { if (temp_flag_info_struct[i].onmsg) { strcpy(buf + spaces, temp_flag_info_struct[i].onmsg); notify(player, buf); } } else { if (temp_flag_info_struct[i].offmsg) { strcpy(buf + spaces, temp_flag_info_struct[i].offmsg); notify(player, buf); } } } } const char *GetArcID(MECH *mech, int arc) { static char buf[20]; int mechlike = (MechType(mech) == CLASS_MECH || MechType(mech) == CLASS_MW || MechType(mech) == CLASS_BSUIT); if (arc & FORWARDARC) strcpy(buf, "Forward"); else if (arc & RSIDEARC) strcpy(buf, mechlike ? "Right Arm" : "Right Side"); else if (arc & LSIDEARC) strcpy(buf, mechlike ? "Left Arm" : "Left Side"); else if (arc & REARARC) strcpy(buf, "Rear"); else strcpy(buf, "NO"); return buf; } const char *GetMechToMechID_base(MECH * see, MECH * mech, int inlos) { char *mname; static char ids[SBUF_SIZE]; if (!Good_obj(mech->mynum)) return ""; if (!inlos) mname = "something"; else mname = silly_atr_get(mech->mynum, A_MECHNAME); snprintf(ids, SBUF_SIZE, "%s [%s]", mname, MechIDS(mech, inlos && MechTeam(see) == MechTeam(mech))); ids[SBUF_SIZE-1] = '\0'; return ids; } const char *GetMechToMechID(MECH * see, MECH * mech) { char *mname; int team; static char ids[SBUF_SIZE]; if (!Good_obj(mech->mynum)) return ""; if (!InLineOfSight_NB(see, mech, 0, 0, 0)) { mname = "something"; team = 0; } else { mname = silly_atr_get(mech->mynum, A_MECHNAME); team = (MechTeam(see) == MechTeam(mech)); } snprintf(ids, SBUF_SIZE, "%s [%s]", mname, MechIDS(mech, team)); ids[SBUF_SIZE-1] = '\0'; return ids; } const char *GetMechID(MECH * mech) { char *mname; static char ids[SBUF_SIZE]; if (!Good_obj(mech->mynum)) return ""; mname = silly_atr_get(mech->mynum, A_MECHNAME); snprintf(ids, SBUF_SIZE, "%s [%s]", mname, MechIDS(mech, 0)); ids[SBUF_SIZE-1] = '\0'; return ids; } void mech_set_channelfreq(dbref player, void *data, char *buffer) { int chn = -1; int freq; MECH *mech = (MECH *) data; MECH *t; MAP *map = getMap(mech->mapindex); int i, j; /* UH, this is code that _pretends_ it works :-) */ cch(MECH_MAP); skipws(buffer); DOCHECK(!*buffer, "Invalid input!"); chn = toupper(*buffer) - 'A'; DOCHECK(chn < 0 || chn >= MFreqs(mech), "Invalid channel-letter!"); buffer++; skipws(buffer); DOCHECK(!*buffer, "Invalid input!"); DOCHECK(*buffer != '=', "Missing =!"); buffer++; skipws(buffer); DOCHECK(!*buffer, "Invalid input!"); freq = atoi(buffer); DOCHECK(!freq && strcmp(buffer, "0"), "Invalid frequency!"); DOCHECK(freq < 0, "Are you trying to kid me?"); DOCHECK(freq > 999999, "Invalid frequency - range is from 0 to 999999."); notify(player, tprintf("Channel %c set to %d.", 'A' + chn, freq)); mech->freq[chn] = freq; /* Code added from Exile to check for possible cheat freq acquring. * When a player sets a freq, it loops through all the mechs on the * map that do not belong to the same team and checks their freqs * against the one set. If it matches it emits message */ if (freq > 0) { for (i = 0; i < map->first_free; i++) { if (!(t = FindObjectsData(map->mechsOnMap[i]))) continue; if (t == mech) continue; if (MechTeam(t) == MechTeam(mech)) continue; for (j = 0; j < MFreqs(t); j++) { if (t->freq[j] == freq && !(t->freqmodes[j] & FREQ_SCAN)) SendFreqs(tprintf("ALERT: Possible abuse by #%d (Team %d)" " setting freq %d matching #%d (Team %d)!", mech->mynum, MechTeam(mech), freq, t->mynum, MechTeam(t))); } } } } void mech_set_channeltitle(dbref player, void *data, char *buffer) { int chn = -1; MECH *mech = (MECH *) data; cch(MECH_MAP); skipws(buffer); DOCHECK(!*buffer, "Invalid input!"); chn = toupper(*buffer) - 'A'; DOCHECK(chn < 0 || chn >= MFreqs(mech), "Invalid channel-letter!"); buffer++; skipws(buffer); DOCHECK(!*buffer, "Invalid input!"); DOCHECK(*buffer != '=', "Missing =!"); buffer++; skipws(buffer); if (!*buffer) { mech->chantitle[chn][0] = 0; notify(player, tprintf("Channel %c title cleared.", 'A' + chn)); return; } strncpy(mech->chantitle[chn], buffer, CHTITLELEN); mech->chantitle[chn][CHTITLELEN] = 0; notify(player, tprintf("Channel %c title set to set to %s.", 'A' + chn, buffer)); } /* 1234567890123456 */ const char radio_colorstr[] = "xrgybmcwXRGYBMCW"; static char *ccode(MECH * m, int i, int obs, int team) { int t = m->freqmodes[i] / FREQ_REST; static char buf[6]; int ii; if (!obs) { if (!t) { strcpy(buf, ""); return buf; }; if (t < 9) { sprintf(buf, "%%c%c", radio_colorstr[t - 1]); return buf; } sprintf(buf, "%%ch%%c%c", ToLower(radio_colorstr[t - 1])); } else { for (ii = 0; ii < 15; ii++) { if (team == obs_team_color[ii].team) sprintf(buf, "%s", obs_team_color[ii].ccode); } if (buf == NULL) sprintf(buf, "%s", obs_team_color[0].ccode); } return buf; } void mech_set_channelmode(dbref player, void *data, char *buffer) { int chn = -1, nm = 0, i; MECH *mech = (MECH *) data; char buf[SBUF_SIZE]; cch(MECH_MAP); skipws(buffer); DOCHECK(!*buffer, "Invalid input!"); chn = toupper(*buffer) - 'A'; DOCHECK(chn < 0 || chn >= MFreqs(mech), "Invalid channel-letter!"); buffer++; skipws(buffer); DOCHECK(!*buffer, "Invalid input!"); DOCHECK(*buffer != '=', "Missing =!"); buffer++; skipws(buffer); if (!buffer || !*buffer) { mech->freqmodes[chn] = 0; notify(player, tprintf("Channel %c <send> mode set to analog.", 'A' + chn)); return; } while (buffer && *buffer) { switch (*buffer) { case 'D': case 'd': DOCHECK(MechRadioInfo(mech) & RADIO_NODIGITAL, "Your radio can't handle digital frequencies!"); nm |= FREQ_DIGITAL; break; case 'I': case 'i': DOCHECK(!(MechRadioInfo(mech) & RADIO_INFO), "This unit is unable to use info functionality."); nm |= FREQ_INFO; break; case 'U': case 'u': nm |= FREQ_MUTE; break; case 'E': case 'e': DOCHECK(!(MechRadioInfo(mech) & RADIO_RELAY), "This unit is unable to relay."); nm |= FREQ_RELAY; break; case 'S': case 's': DOCHECK(!(MechRadioInfo(mech) & RADIO_SCAN), "This unit is unable to scan."); nm |= FREQ_SCAN; break; default: for (i = 0; radio_colorstr[i]; i++) if (*buffer == radio_colorstr[i]) { nm = nm % FREQ_REST + FREQ_REST * (i + 1); break; } if (!radio_colorstr[i]) buffer = NULL; break; } if (buffer) buffer++; } DOCHECK(!(nm & FREQ_DIGITAL) && (nm & FREQ_RELAY), "Error: Need digital transfer for relay to work."); DOCHECK(!(nm & FREQ_DIGITAL) && (nm & FREQ_INFO), "Error: Need digital transfer for transfer info to work."); mech->freqmodes[chn] = nm; i = 0; if (nm & FREQ_INFO) buf[i++] = 'I'; if (nm & FREQ_MUTE) buf[i++] = 'U'; if (nm & FREQ_RELAY) buf[i++] = 'E'; if (nm & FREQ_SCAN) buf[i++] = 'S'; if (!i) buf[i++] = '-'; if (nm / FREQ_REST) { sprintf(buf + i, "/color:%c", radio_colorstr[nm / FREQ_REST - 1]); i = strlen(buf); } buf[i] = 0; notify(player, tprintf("Channel %c <send> mode set to %s (flags:%s).", 'A' + chn, nm & FREQ_DIGITAL ? "digital" : "analog", buf)); } void mech_list_freqs(dbref player, void *data, char *buffer) { int i; MECH *mech = (MECH *) data; /* UH, this is code that _pretends_ it works :-) */ notify(player, "# -- Mode -- Frequency -- Comtitle"); for (i = 0; i < MFreqs(mech); i++) notify(player, tprintf("%c %c%c%c%c %-9d %s", 'A' + i, mech->freqmodes[i] & FREQ_DIGITAL ? 'D' : 'A', mech->freqmodes[i] & FREQ_RELAY ? 'R' : '-', mech->freqmodes[i] & FREQ_MUTE ? 'M' : '-', mech->freqmodes[i] & FREQ_SCAN ? 'S' : mech-> freqmodes[i] >= FREQ_REST ? radio_colorstr[mech->freqmodes[i] / FREQ_REST - 1] : mech->freqmodes[i] & FREQ_INFO ? 'I' : '-', mech->freq[i], mech->chantitle[i])); } void mech_sendchannel(dbref player, void *data, char *buffer) { /* Basically, this is sorta routine 'sendchannel <letter>=message' code */ MECH *mech = (MECH *) data; int fail = 0; int argc; int chn = 0; char *args[3]; int i; cch(MECH_USUALS); DOCHECK(Destroyed(mech) || !MechRadioRange(mech), "Your communication gear is inoperative."); DOCHECK(CrewStunned(mech), "You are too stunned to use the radio!"); if ((argc = proper_parseattributes(buffer, args, 3)) != 3) fail = 1; if (!fail && strlen(args[0]) > 1) fail = 1; if (!fail && args[0][0] >= 'a' && args[0][0] <= 'z') chn = args[0][0] - 'a'; if (!fail && args[0][0] >= 'A' && args[0][0] <= 'Z') chn = args[0][0] - 'Z'; if (!fail && (chn >= MFreqs(mech) || chn < 0)) fail = 1; if (!fail) for (i = 0; args[2][i]; i++) { if ((BOUNDED(32, args[2][i], 255)) != args[2][i]) { notify(player, "Invalid: No control characters in radio messages, please."); for(i = 0; i < 3; i++) { if(args[i]) free(args[i]); } return; } } if (fail) { notify(player, "Invalid format! Usage: sendchannel <letter>=<string>"); for(i = 0; i < 3; i++) { if(args[i]) free(args[i]); } return; } if (mech->freq[chn] == 0 && In_Character(mech->mapindex)) { send_channel("ZeroFrequencies", "Player #%d (%s) in mech #%d (channel %c) " "on map #%d 0-freqs \"%s\"", player, Name(player), mech->mynum, chn+'A', mech->mapindex, args[2]); } sendchannelstuff(mech, chn, args[2]); for(i = 0; i < 3; i++) { if(args[i]) free(args[i]); } explode_mines(mech, mech->freq[chn]); } #define number(x,y) (rand()%(y-x+1)+x) static void do_scramble(char *buffo, int ch, int bth) { int i; for (i = 0; buffo[i]; i++) { if (number(1, 100) > ch && Roll() < (bth + 5)) { if (number(1, 2) == 1) buffo[i] -= number(1, 10); else buffo[i] += number(1, 10); } buffo[i] = (unsigned char) BOUNDED(33, buffo[i], 255); } } #define my_modify(n,fact) (100 - (100 - (n)) / (fact)) static int comm_num_to_conn; static int comm_is[MAX_MECHS_PER_MAP][MAX_MECHS_PER_MAP]; static int comm_done[MAX_MECHS_PER_MAP]; static MECH *comm_mech[MAX_MECHS_PER_MAP]; static int comm_best; static int comm_best_path[MAX_MECHS_PER_MAP]; static int comm_path[MAX_MECHS_PER_MAP]; void ScrambleMessage(char *buffo, int range, int sendrange, int recvrrange, char *handle, char *msg, int bth, int *isxp, int under_ecm, int digmode) { int mr, i; char *header = NULL; char buf[LBUF_SIZE]; *isxp = 0; if (digmode > 1 && comm_best > 1) { int bearing; strncpy(buf, "{R-path:", LBUF_SIZE); for (i = 1; i < comm_best; i++) { if (i > 1) strcat(buf, "/"); bearing = FindBearing(MechFX(comm_mech[comm_best_path[i]]), MechFY(comm_mech[comm_best_path[i]]), MechFX(comm_mech[comm_best_path[i - 1]]), MechFY(comm_mech[comm_best_path[i - 1]])); snprintf(buf + strlen(buf), LBUF_SIZE, "[%c%c]-h:%.3d", MechID(comm_mech[comm_best_path[i]])[0], MechID(comm_mech[comm_best_path[i]])[1], bearing); } strcat(buf, "} "); header = buf; } if (handle && *handle) snprintf(buffo, LBUF_SIZE, "%s<%s> %s", header ? header : "", handle, msg); else snprintf(buffo, LBUF_SIZE, "%s%s", header ? header : "", msg); if ((!digmode && (range >= sendrange || range >= recvrrange)) || under_ecm) { if (!digmode) { mr = MAX(recvrrange, (sendrange + recvrrange) / 2); if (sendrange < range) { do_scramble(buffo, (100 * sendrange) / MAX(1, range), bth); *isxp = 1; } if (mr < range) { do_scramble(buffo, my_modify((100 * mr) / MAX(1, range), 2), bth); *isxp = 1; } } if (under_ecm && range >= 1) { do_scramble(buffo, Number(30, 50), bth); *isxp = 1; } } } int common_checks(dbref player, MECH * mech, int flag) { MAP *mech_map; if (!mech) return 0; if ((flag & MECH_CONSISTENT) && !CheckData(player, mech)) return 0; if (!Wizard(player)) { /* ----------------------------- */ /* INSERT UNSUPPORTED TYPES HERE */ /* ----------------------------- */ if (MechType(mech) == CLASS_AERO) return 0; /* ----------------------------- */ } /* if (MechAuto(mech) > 0) if (isPlayer(MechPilot(mech))) MechAuto(mech) = -1; */ MechLastUse(mech) = 0; if (flag & MECH_STARTED) { DOCHECK0(Destroyed(mech), "You are destroyed!"); DOCHECK0(!(MechStatus(mech) & STARTED), "Reactor is not online!"); } if (flag & MECH_PILOT) { DOCHECK0(Blinded(mech), "You are momentarily blinded!"); } if (flag & MECH_PILOT_CON) DOCHECK0(Uncon(mech) && (!Started(mech) || player == MechPilot(mech)), "You are unconscious....zzzzzzz"); if (flag & MECH_PILOTONLY) DOCHECK0(!Wizard(player) && In_Character(mech->mynum) && MechPilot(mech) != player, "Now now, only the pilot can push that button."); if (flag & MECH_MAP) { DOCHECK0(mech->mapindex < 0, "You are on no map!"); mech_map = getMap(mech->mapindex); if (!mech_map) { notify(player, "You are on an invalid map! Map index reset!"); mech_shutdown(player, (void *) mech, ""); mech->mapindex = -1; return 0; } } return 1; } static int iter_prevent; void recursive_commlink(int i, int dep) { int j; if (iter_prevent++ >= 10000) return; if (dep >= comm_best) return; comm_path[dep] = i; for (j = 1; j < comm_num_to_conn; j++) if (comm_is[i][j] && !comm_done[j]) { if (j == (comm_num_to_conn - 1)) { int k; comm_best = dep; for (k = 0; k < comm_best; k++) comm_best_path[k] = comm_path[k]; } else { comm_done[j] = 1; recursive_commlink(j, dep + 1); comm_done[j] = 0; } } } void nonrecursive_commlink(int i) { int dep = 0, j; int comm_loop[MAX_MECHS_PER_MAP]; int iter_c = 0; int maxdepth = 0; /* May _still_ contain fatal bug ; Ghod knows (I don't) */ comm_loop[0] = 1; comm_path[0] = i; while (dep >= 0) { i = comm_path[dep]; for (j = comm_loop[dep]; j < comm_num_to_conn; j++) if (comm_is[i][j] && !comm_done[j]) { if (j == (comm_num_to_conn - 1)) { int k; comm_best = dep + 1; for (k = 0; k < comm_best; k++) comm_best_path[k] = comm_path[k]; j = comm_num_to_conn; break; } else if ((dep + 1) < comm_best) { comm_done[j] = 1; comm_loop[dep++] = j + 1; comm_loop[dep] = 1; comm_path[dep] = j; if (dep > maxdepth) maxdepth = dep; break; } } if (j == comm_num_to_conn) { if (dep > 0) comm_done[comm_loop[--dep] - 1] = 0; else dep--; /* We're finished! */ } if (iter_c++ == 100000) { SendError(tprintf ("#%d: Infinite loop in relay code (?) ; using backup recursive code (num_mechs:%d, maxdepth:%d, nowdepth:%d)", comm_mech[0]->mynum, comm_num_to_conn, maxdepth, dep)); comm_best = 9999; for (i = 0; i < comm_num_to_conn; i++) comm_done[i] = 0; iter_prevent = 0; recursive_commlink(0, 0); return; } } } int findCommLink(MAP * map, MECH * from, MECH * to, int freq) { int i, j; MECH *t; comm_num_to_conn = 0; comm_mech[comm_num_to_conn++] = from; for (i = 0; i < map->first_free; i++) { if (!(t = FindObjectsData(map->mechsOnMap[i]))) continue; if (t == from || t == to) continue; if (MechTeam(from) != MechTeam(t)) continue; if ((MechMove(t) != MOVE_NONE && !Started(t)) || (MechMove(t) == MOVE_NONE && Destroyed(t))) continue; if (!(MechRadioInfo(t) & RADIO_RELAY)) continue; for (j = 0; j < MFreqs(t); j++) if (t->freq[j] == freq) if (t->freqmodes[j] & FREQ_RELAY) { comm_mech[comm_num_to_conn++] = t; continue; } } comm_mech[comm_num_to_conn++] = to; if (comm_num_to_conn == 2) return 0; /* Quickie kludge for the 'standard' case */ for (i = 0; i < comm_num_to_conn; i++) { comm_done[i] = 0; comm_is[i][i] = 0; for (j = i + 1; j < comm_num_to_conn; j++) { float range = FlMechRange(map, comm_mech[i], comm_mech[j]); comm_is[i][j] = (range <= MechRadioRange(comm_mech[i])); comm_is[j][i] = (range <= MechRadioRange(comm_mech[j])); } } comm_best = 9999; /* recursive_commlink(0, 0); */ nonrecursive_commlink(0); /* better _pray_ this works */ return comm_best != 9999; } /* The code that does the actual sending of radio messages whenever * someone speaks on a given frequency */ void sendchannelstuff(MECH * mech, int freq, char *msg) { /* The _smart_ code :-) */ int loop, range, bearing, i, isxp; MECH *tempMech; MAP *mech_map = getMap(mech->mapindex); char buf[LBUF_SIZE]; char buf2[LBUF_SIZE]; char buf3[LBUF_SIZE]; int sfail_type, sfail_mod; int rfail_type, rfail_mod; int obs = 0 ; char ai_buf[LBUF_SIZE]; /* Removed the Radio Failing stuff cause it annoys me - Dany CheckGenericFail(mech, -2, &sfail_type, &sfail_mod); */ if (!MechRadioRange(mech)) return; /* Loop through all the units on the map */ for (loop = 0; loop < mech_map->first_free; loop++) { if (mech_map->mechsOnMap[loop] != 2) { // XXX: The test below is indicative of very bad bookkeeping. Suggesting // that a dbref may be indicated as "on the map" without being on the map. // I believe this to be a serious problem. if (!(tempMech = (MECH *) FindObjectsData(mech_map->mechsOnMap[loop]))) continue; if (Destroyed(tempMech)) continue; obs = (MechCritStatus(tempMech) & OBSERVATORIC); range = FaMechRange(mech, tempMech); bearing = FindBearing(MechFX(tempMech), MechFY(tempMech), MechFX(mech), MechFY(mech)); for (i = 0; i < MFreqs(tempMech); i++) { if (tempMech->freq[i] == mech->freq[freq]) { if ((tempMech->freqmodes[i] & FREQ_MUTE) || ((mech->freqmodes[freq] & FREQ_DIGITAL) && (MechRadioInfo(tempMech) & RADIO_NODIGITAL))) continue; break; } } if (i >= MFreqs(tempMech)) { /* Possible scanner check */ if (!(mech->freqmodes[freq] & FREQ_DIGITAL)) if ((MechRadioInfo(tempMech) & RADIO_SCAN) && mech->freq[freq]) { int tnc = 0; for (i = 0; i < MFreqs(tempMech); i++) if (tempMech->freqmodes[i] & FREQ_SCAN) { int l = strlen(msg), t; int mod, diff; int pr; /* Possible skill check here? Nah. */ /* Chance of detection: 1 in MIN(80,l) out of 100 */ if (Number(1, 100) > MIN(80, l)) continue; if (!tnc++) mech_notify(tempMech, MECHALL, "You notice a " "unknown transmission your scanner.. "); if (tempMech->freq[i] < mech->freq[freq]) { diff = mech->freq[freq] - tempMech->freq[i]; mod = 1; } else { diff = tempMech->freq[i] - mech->freq[freq]; mod = -1; } t = MAX(1, Number(1, MIN(99, l)) * diff / 100); pr = t * 100 / diff; mech_notify(tempMech, MECHALL, tprintf("Your systems " "manage to zero on it %s on channel %c.", pr < 30 ? "somewhat" : pr < 60 ? "fairly well" : pr < 95 ? "precisely" : "exactly", i + 'A')); tempMech->freq[i] += mod * t; } } continue; } strncpy(buf2, msg, LBUF_SIZE); /* This is where we check to see if the mech has an AI and * then we give the radio commands to the AI */ if (MechAuto(tempMech) > 0 && tempMech->freq[i]) { AUTO *a = (AUTO *) FindObjectsData(MechAuto(tempMech)); /* First check to make sure the AI is still there */ if (!a) { /* No AI there so reset the AI value on the mech */ MechAuto(tempMech) = -1; } else if (a && Location(a->mynum) != tempMech->mynum) { /* Check to see if the AI is still in the same mech */ snprintf(ai_buf, LBUF_SIZE, "Autopilot #%d (Location: #%d) " "reported on Mech #%d but not in the proper location", a->mynum, Location(a->mynum), tempMech->mynum); SendAI(ai_buf); } else if (a && !ECMDisturbed(tempMech)) { /* Ok send the command to the AI provided its not ECM'd */ strncpy(buf3, msg, LBUF_SIZE); auto_parse_command(a, tempMech, i, buf3); } } /* Removed the Radio fail stuff because it annoys me - Dany CheckGenericFail(tempMech, -2, &rfail_type, &rfail_mod); */ if (!MechRadioRange(tempMech)) continue; if (mech->freqmodes[freq] & FREQ_DIGITAL) { if (range > MechRadioRange(mech)) { if (!findCommLink(mech_map, mech, tempMech, mech->freq[freq])) continue; } else comm_best = 1; if (tempMech != mech) { if (AnyECMDisturbed(mech)) continue; else if (AnyECMDisturbed(tempMech)) continue; } ScrambleMessage(buf3, range, MechRadioRange(mech), MechRadioRange(mech), mech->chantitle[freq], buf2, MechComm(tempMech), &isxp, 0, (tempMech->freqmodes[i] & FREQ_INFO) ? 2 : 1); if (comm_best >= 2) bearing = FindBearing(MechFX(tempMech), MechFY(tempMech), MechFX(comm_mech[comm_best_path[comm_best - 1]]), MechFY(comm_mech[comm_best_path[comm_best - 1]])); if (!obs) snprintf(buf, LBUF_SIZE, "%s[%c:%.3d] %s%%c", ccode(tempMech, i, obs, MechTeam(mech)), (char) ('A' + i), bearing, buf3); else { snprintf(buf, LBUF_SIZE, "%s[%c:%d] <%s> %s%%c", ccode(tempMech, i, obs, MechTeam(mech)), (char) ('A' + i), bearing, silly_atr_get(mech->mynum, A_FACTION), buf3); } } else { ScrambleMessage(buf3, range, MechRadioRange(mech), MechRadioRange(tempMech), mech->chantitle[freq], buf2, MechComm(tempMech), &isxp, (AnyECMDisturbed(mech) || AnyECMDisturbed(tempMech) /* || sfail_type == FAIL_STATIC || rfail_type == FAIL_STATIC */ ) && mech != tempMech, 0); if (!obs) snprintf(buf, LBUF_SIZE, "%s(%c:%.3d) %s%%c", ccode(tempMech, i, obs, MechTeam(mech)), (char) ('A' + i), bearing, buf3); else { snprintf(buf, LBUF_SIZE, "%s(%c:%d) <%s> %s%%c", ccode(tempMech, i, obs, MechTeam(mech)), (char) ('A' + i), bearing, silly_atr_get(mech->mynum, A_FACTION), buf3); } } mech_notify(tempMech, MECHALL, buf); if (isxp && In_Character(tempMech->mynum)) if ((MechCommLast(tempMech) + 60) < muxevent_tick) { AccumulateCommXP(MechPilot(tempMech), tempMech); MechCommLast(tempMech) = muxevent_tick; } } } /* End of looping through all the units on the map */ } void mech_radio(dbref player, void *data, char *buffer) { int argc; int fail = 0; char *args[3]; int i; MECH *mech = (MECH *) data; dbref target; MECH *tempMech; /* radio <id>=message */ /* Quick clone :-) */ /* This is silly, but who cares. */ cch(MECH_USUAL); DOCHECK(MechIsObservator(mech), "You can't radio anyone."); if ((argc = proper_parseattributes(buffer, args, 3)) != 3) fail = 1; if (!fail && (!args[1] || args[1][0] != '=' || args[1][1] != 0)) fail = 1; if (!fail && (!args[0] || args[0][0] == 0 || args[0][1] == 0 || args[0][2] != 0)) fail = 1; if (!fail) { target = FindTargetDBREFFromMapNumber(mech, args[0]); tempMech = getMech(target); DOCHECK(!tempMech || !InLineOfSight(mech, tempMech, MechX(tempMech), MechY(tempMech), FlMechRange(map, mech, tempMech)), "Target is not in line of sight!"); mech_notify(mech, MECHSTARTED, tprintf("You radio %s with, '%s'", GetMechToMechID(mech, tempMech), args[2])); mech_notify(tempMech, MECHSTARTED, tprintf("%s radios you with, '%s'", GetMechToMechID(tempMech, mech), args[2])); auto_reply(tempMech, tprintf("%s radio'ed me '%s'", GetMechToMechID(tempMech, mech), args[2])); } DOCHECK(fail, "Invalid format! Usage: radio <letter><letter>=<message>"); for(i = 0; i < 3; i++) { if(args[i]) free(args[i]); } } int MapLimitedBroadcast2d(MAP *map, float x, float y, float range, char *message) { int loop, count = 0; MECH *mech; for(loop = 0; loop < map->first_free; loop++) { if(map->mechsOnMap[loop] < 0) continue; mech = getMech(map->mechsOnMap[loop]); if(mech && FindXYRange(x, y, MechFX(mech), MechFY(mech)) <= range) { mech_notify(mech, MECHSTARTED, message); count++; } } return count; } int MapLimitedBroadcast3d(MAP *map, float x, float y, float z, float range, char *message) { int loop, count=0; MECH *mech; for(loop = 0; loop < map->first_free; loop++) { if(map->mechsOnMap[loop] == -1) continue; mech = getMech(map->mechsOnMap[loop]); if(mech && FindRange(x, y, z, MechFX(mech), MechFY(mech), MechFZ(mech)) <= range) { count++; mech_notify(mech, MECHSTARTED, message); } } return count; } void MechBroadcast(MECH * mech, MECH * target, MAP * mech_map, char *buffer) { int loop; MECH *tempMech; if (target) { for (loop = 0; loop < mech_map->first_free; loop++) { if (mech_map->mechsOnMap[loop] != mech->mynum && mech_map->mechsOnMap[loop] != -1 && mech_map->mechsOnMap[loop] != target->mynum) { tempMech = (MECH *) FindObjectsData(mech_map->mechsOnMap[loop]); if (tempMech) mech_notify(tempMech, MECHSTARTED, buffer); } } } else { for (loop = 0; loop < mech_map->first_free; loop++) { if (mech_map->mechsOnMap[loop] != mech->mynum && mech_map->mechsOnMap[loop] != -1) { tempMech = (MECH *) FindObjectsData(mech_map->mechsOnMap[loop]); if (tempMech) mech_notify(tempMech, MECHSTARTED, buffer); } } } } void MechLOSBroadcast(MECH * mech, char *message) { /* Sends msg to everyone except the mech */ int i; MECH *tempMech; MAP *mech_map = getMap(mech->mapindex); char buf[LBUF_SIZE]; possibly_see_mech(mech); if (!mech_map) return; for (i = 0; i < mech_map->first_free; i++) if (mech_map->mechsOnMap[i] != -1 && mech_map->mechsOnMap[i] != mech->mynum) if ((tempMech = getMech(mech_map->mechsOnMap[i]))) if (InLineOfSight(tempMech, mech, MechX(mech), MechY(mech), FlMechRange(mech_map, tempMech, mech))) { sprintf(buf, "%s%s%s", GetMechToMechID(tempMech, mech), *message != '\'' ? " " : "", message); mech_notify(tempMech, MECHSTARTED, buf); } } int MechSeesHexF(MECH * mech, MAP * map, float x, float y, int ix, int iy) { return (InLineOfSight(mech, NULL, ix, iy, FindRange(MechFX(mech), MechFY(mech), MechFZ(mech), x, y, ZSCALE * Elevation(map, ix, iy)))); } int MechSeesHex(MECH * mech, MAP * map, int x, int y) { float fx, fy; MapCoordToRealCoord(x, y, &fx, &fy); return MechSeesHexF(mech, map, fx, fy, x, y); } void HexLOSBroadcast(MAP * mech_map, int x, int y, char *message) { int i; MECH *tempMech; float fx, fy; /* substitution: $h = !alarming ('your hex', '%d,%d') $H = alarming ('YOUR HEX', '%d,%d (%.2f away)') */ if (!mech_map) return; MapCoordToRealCoord(x, y, &fx, &fy); for (i = 0; i < mech_map->first_free; i++) if (mech_map->mechsOnMap[i] != -1) if ((tempMech = getMech(mech_map->mechsOnMap[i]))) if (MechSeesHexF(tempMech, mech_map, fx, fy, x, y)) { char tbuf[LBUF_SIZE]; char *c, *d = tbuf; int done; for (c = message; *c; c++) { done = 0; if (*c == '$') { if (*(c + 1) == 'h' || *(c + 1) == 'H') { c++; if (*c == 'h') { if (x == MechX(tempMech) && y == MechY(tempMech)) strcpy(d, "your hex"); else sprintf(d, "%d,%d", x, y); while (*d) d++; } else { /* Dangerous */ if (x == MechX(tempMech) && y == MechY(tempMech)) strcpy(d, "%ch%crYOUR HEX%cn"); else sprintf(d, "%%ch%%cy%d,%d%%cn", x, y); while (*d) d++; } done = 1; } } if (!done) *(d++) = *c; } /* Apparently, it's necessary to remove trailing $'s ?? */ if (*(d-1) == '$') d--; *d = '\0'; mech_notify(tempMech, MECHSTARTED, tbuf); } } void MechLOSBroadcasti(MECH * mech, MECH * target, char *message) { /* Sends msg to everyone except the mech */ int i, a, b; char oddbuff[LBUF_SIZE]; char oddbuff2[LBUF_SIZE]; MECH *tempMech; MAP *mech_map = getMap(mech->mapindex); if (!mech_map) return; possibly_see_mech(mech); possibly_see_mech(target); for (i = 0; i < mech_map->first_free; i++) if (mech_map->mechsOnMap[i] != -1 && mech_map->mechsOnMap[i] != mech->mynum && mech_map->mechsOnMap[i] != target->mynum) if ((tempMech = getMech(mech_map->mechsOnMap[i]))) { a = InLineOfSight(tempMech, mech, MechX(mech), MechY(mech), FlMechRange(mech_map, tempMech, mech)); b = InLineOfSight(tempMech, target, MechX(target), MechY(target), FlMechRange(mech_map, tempMech, target)); if (a || b) { sprintf(oddbuff, message, b ? GetMechToMechID(tempMech, target) : "someone"); sprintf(oddbuff2, "%s%s%s", a ? GetMechToMechID(tempMech, mech) : "Someone", *oddbuff != '\'' ? " " : "", oddbuff); mech_notify(tempMech, MECHSTARTED, oddbuff2); } } } void MapBroadcast(MAP * map, char *message) { /* Sends msg to everyone except the mech */ int i; MECH *tempMech; for (i = 0; i < map->first_free; i++) if (map->mechsOnMap[i] != -1) if ((tempMech = getMech(map->mechsOnMap[i]))) mech_notify(tempMech, MECHSTARTED, message); } void MechFireBroadcast(MECH * mech, MECH * target, int x, int y, MAP * mech_map, char *weapname, int IsHit) { int loop, attacker, defender; float fx, fy, fz; int mapx, mapy; MECH *tempMech; char buff[50]; possibly_see_mech(mech); if (target) { possibly_see_mech(target); mapx = MechX(target); mapy = MechY(target); fx = MechFX(target); fy = MechFY(target); fz = MechFZ(target); for (loop = 0; loop < mech_map->first_free; loop++) if (mech_map->mechsOnMap[loop] != mech->mynum && mech_map->mechsOnMap[loop] != -1 && mech_map->mechsOnMap[loop] != target->mynum) { attacker = 0; defender = 0; tempMech = (MECH *) FindObjectsData(mech_map->mechsOnMap[loop]); if (!tempMech) continue; if (InLineOfSight(tempMech, mech, MechX(mech), MechY(mech), FlMechRange(mech_map, tempMech, mech))) attacker = 1; if (target) { if (InLineOfSight(tempMech, target, mapx, mapy, FlMechRange(mech_map, tempMech, target))) defender = 1; } else if (InLineOfSight(tempMech, target, mapx, mapy, FindRange(MechFX(tempMech), MechFY(tempMech), MechFZ(tempMech), fx, fy, fz))) defender = 1; if (!attacker && !defender) continue; if (defender) sprintf(buff, "%s", GetMechToMechID(tempMech, target)); if (attacker) { if (defender) mech_notify(tempMech, MECHSTARTED, tprintf("%s %s %s with a %s", GetMechToMechID(tempMech, mech), IsHit ? "hits" : "misses", buff, weapname)); else mech_notify(tempMech, MECHSTARTED, tprintf("%s fires a %s at something!", GetMechToMechID(tempMech, mech), weapname)); } else mech_notify(tempMech, MECHSTARTED, tprintf("Something %s %s with a %s", IsHit ? "hits" : "misses", buff, weapname)); } } else { mapx = x; mapy = y; MapCoordToRealCoord(x, y, &fx, &fy); fz = ZSCALE * Elevation(mech_map, x, y); sprintf(buff, "hex %d %d!", mapx, mapy); for (loop = 0; loop < mech_map->first_free; loop++) if (mech_map->mechsOnMap[loop] != mech->mynum && mech_map->mechsOnMap[loop] != -1) { attacker = 0; defender = 0; tempMech = (MECH *) FindObjectsData(mech_map->mechsOnMap[loop]); if (!tempMech) continue; if (InLineOfSight(tempMech, mech, MechX(mech), MechY(mech), FlMechRange(mech_map, tempMech, mech))) attacker = 1; if (target) { if (InLineOfSight(tempMech, target, mapx, mapy, FlMechRange(mech_map, tempMech, target))) defender = 1; } else if (InLineOfSight(tempMech, target, mapx, mapy, FindRange(MechFX(tempMech), MechFY(tempMech), MechFZ(tempMech), fx, fy, fz))) defender = 1; if (!attacker && !defender) continue; if (attacker) { if (defender) /* att + def */ mech_notify(tempMech, MECHSTARTED, tprintf("%s fires a %s at %s", GetMechToMechID(tempMech, mech), weapname, buff)); else /* att */ mech_notify(tempMech, MECHSTARTED, tprintf("%s fires a %s at something!", GetMechToMechID(tempMech, mech), weapname)); } else /* def */ mech_notify(tempMech, MECHSTARTED, tprintf("Something fires a %s at %s", weapname, buff)); } } } extern int arc_override; void mech_notify(MECH * mech, int type, char *buffer) { int i; if (Uncon(mech)) return; if (Blinded(mech)) return; if (mech->mynum < 0) return; /* Let's do colorization too, just in case. */ if (type == MECHPILOT) { if (GotPilot(mech)) notify(MechPilot(mech), buffer); else mech_notify(mech, MECHALL, buffer); } else if ((type == MECHALL && !Destroyed(mech)) || (type == MECHSTARTED && Started(mech))) { notify_except(mech->mynum, NOSLAVE, mech->mynum, buffer); if (arc_override) for (i = 0; i < NUM_TURRETS; i++) if (AeroTurret(mech, i) > 0) notify_except(AeroTurret(mech, i), NOSLAVE, AeroTurret(mech, i), buffer); } } void mech_printf(MECH * mech, int type, char *format, ...) { char buffer[LBUF_SIZE]; int i; va_list ap; if (Uncon(mech)) return; if (Blinded(mech)) return; if (mech->mynum < 0) return; /* Let's do colorization too, just in case. */ va_start(ap, format); vsnprintf(buffer, LBUF_SIZE, format, ap); va_end(ap); if (type == MECHPILOT) { if (GotPilot(mech)) notify(MechPilot(mech), buffer); else mech_notify(mech, MECHALL, buffer); } else if ((type == MECHALL && !Destroyed(mech)) || (type == MECHSTARTED && Started(mech))) { notify_except(mech->mynum, NOSLAVE, mech->mynum, buffer); if (arc_override) for (i = 0; i < NUM_TURRETS; i++) if (AeroTurret(mech, i) > 0) notify_except(AeroTurret(mech, i), NOSLAVE, AeroTurret(mech, i), buffer); } }