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: 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);
    }
}