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: hudinfo.c,v 1.2 2005/06/24 04:39:07 av1-op Exp $
 *
 * Copyright (c) 2002 Thomas Wouters <thomas@xs4all.net>
 *
 * HUDINFO support.
 */

#include <string.h>
#include <math.h>

#include "config.h"
#include "externs.h"
#include "interface.h"

#include "muxevent.h"
#include "mech.h"
#include "map.h"
#include "map.los.h"
#include "p.mech.utils.h"
#include "p.mech.contacts.h"
#include "failures.h"
#include "p.mech.build.h"
#include "p.mech.notify.h"
#include "p.mech.update.h"
#include "p.mech.move.h"
#include "p.mech.los.h"
#include "p.mech.status.h"

extern void auto_reply(MECH * mech, char *buf);

#ifdef HUDINFO_SUPPORT

#include "hudinfo.h"

void fake_hudinfo(dbref player, dbref cause, int key, char *arg)
{
    notify(player, "HUDINFO does not work from scode or macros.");
}

HASHTAB hudinfo_cmdtab;

void init_hudinfo(void)
{
    HUDCMD *cmd;

    hashinit(&hudinfo_cmdtab, 20 * HASH_FACTOR);

    for (cmd = hudinfo_cmds; cmd->cmd; cmd++)
	hashadd(cmd->cmd, (int *) cmd, &hudinfo_cmdtab);
}

static MECH *getMech_forPlayer(dbref player)
{
    dbref inv, tmp;
    MECH *mech = NULL;

    if (Hardcode(player) && !Zombie(player))
	mech = getMech(player);

    if (!mech) {
	tmp = Location(player);
	if (Hardcode(tmp) && !Zombie(tmp))
	    mech = getMech(tmp);
    }

    if (!mech) {
	SAFE_DOLIST(inv, tmp, Contents(player)) {
	    if (Hardcode(inv) && !Zombie(inv))
		mech = getMech(inv);
	    if (mech)
		break;
	}
    }
    return mech;
}

void do_hudinfo(DESC * d, char *arg)
{
    char *subcmd;
    HUDCMD *cmd;
    MECH *mech = NULL;

    while (*arg && isspace(*arg))
	arg++;

    if (!*arg) {
	hudinfo_notify(d, NULL, NULL, "#HUD hudinfo version "
	    HUD_PROTO_VERSION);
	return;
    }

    if (strncmp(arg, "key=", 4) == 0) {
	arg += 4;
	if (!arg || strlen(arg) > 20) {
	    hudinfo_notify(d, "KEY", "E", "Invalid key");
	    return;
	}
	for (subcmd = arg; *subcmd; subcmd++) {
	    if (!isalnum(*subcmd)) {
		hudinfo_notify(d, "KEY", "E", "Invalid key");
		return;
	    }
	}
	strcpy(d->hudkey, arg);
	hudinfo_notify(d, "KEY", "R", "Key set");
	return;
    }

    if (!d->hudkey[0]) {
	hudinfo_notify(d, "???", "E", "No session key set");
	return;
    }

    subcmd = arg;

    while (*arg && !isspace(*arg)) {
	if (!isalnum(*arg)) {
	    hudinfo_notify(d, "???", "E", "Invalid subcommand");
	    return;
	}
	arg++;
    }

    if (*arg) {
	*arg++ = '\0';
    }

    while (*arg && isspace(*arg))
	arg++;

    cmd = (HUDCMD *) hashfind(subcmd, &hudinfo_cmdtab);
    if (!cmd) {
	hudinfo_notify(d, "???", "E",
	    tprintf("%s: subcommand not found", subcmd));
	return;
    }

    if (cmd->flag & HUDCMD_HASARG) {
	if (!*arg) {
	    hudinfo_notify(d, cmd->msgclass, "E", "Not enough arguments");
	    return;
	}
    } else if (*arg) {
	hudinfo_notify(d, cmd->msgclass, "E",
	    "Command takes no arguments");
	return;
    }


    if (cmd->flag & HUDCMD_NEEDMECH) {
	mech = getMech_forPlayer(d->player);
	if (!mech) {
	    hudinfo_notify(d, cmd->msgclass, "E",
		"Not in a BattleTech unit");
	    return;
	}
	if ((cmd->flag & HUDCMD_NONDEST) && Destroyed(mech)) {
	    hudinfo_notify(d, cmd->msgclass, "E", "You are destroyed!");
	    return;
	}
	if ((cmd->flag & HUDCMD_STARTED) && !Started(mech)) {
	    hudinfo_notify(d, cmd->msgclass, "E", "Reactor is not online");
	    return;
	}
	if ((cmd->flag & HUDCMD_AWAKE) &&
	    (MechStatus(mech) & (BLINDED | UNCONSCIOUS))) {
	    hudinfo_notify(d, cmd->msgclass, "E",
		"You are unconscious....zzzzzzz");
	    return;
	}
    }

    cmd->handler(d, mech, cmd->msgclass, arg);
    return;
}

static void FindRangeAndBearingToCenter(MECH * mech, float *rtc, int *btc)
{
    float fx, fy;

    MapCoordToRealCoord(MechX(mech), MechY(mech), &fx, &fy);
    *rtc = FindHexRange(fx, fy, MechFX(mech), MechFY(mech));
    *btc = FindBearing(MechFX(mech), MechFY(mech), fx, fy);
}

static void hud_generalstatus(DESC * d, MECH * mech, char *msgclass,
    char *args)
{
    static char response[LBUF_SIZE];
    char fuel[15];
    char tstat[5];
    char jumpx[8], jumpy[8];
    int btc;
    float rtc;

    if (FlyingT(mech) && !AeroFreeFuel(mech))
	sprintf(fuel, "%d", AeroFuel(mech));
    else
	strcpy(fuel, "-");

    if (MechHasTurret(mech))
	sprintf(tstat, "%d",
	    AcceptableDegree(MechTurretFacing(mech)) - 180);
    else if ((MechType(mech) == CLASS_MECH && !MechIsQuad(mech)) ||
	MechType(mech) == CLASS_MW)
	sprintf(tstat, "%d",
	    MechStatus(mech) & TORSO_LEFT ? -60 : MechStatus(mech) &
	    TORSO_RIGHT ? 60 : 0);
    else
	strcpy(tstat, "-");

    if (Jumping(mech)) {
    	snprintf(jumpx, 8, "%d", MechGoingX(mech));
    	snprintf(jumpy, 8, "%d", MechGoingY(mech));
    } else {
    	strcpy(jumpx, "-");
    	strcpy(jumpy, "-");
    };

    FindRangeAndBearingToCenter(mech, &rtc, &btc);

    sprintf(response,
	"%s,%d,%d,%d,%d,%d,%.2f,%.2f,%d,%d,%s,%.2f,%.2f,%.3f,%d,%s,%s,%s,%s",
	MechIDS(mech, 0), MechX(mech), MechY(mech), MechZ(mech),
	MechFacing(mech), MechDesiredFacing(mech),
	MechSpeed(mech), MechDesiredSpeed(mech),
	(int) (10 * MechPlusHeat(mech)),
	(int) (10. * MechActiveNumsinks(mech)),
	fuel, MechVerticalSpeed(mech), MechVerticalSpeed(mech),
	rtc, btc, tstat, getStatusString(mech, 2), jumpx, jumpy);

    hudinfo_notify(d, msgclass, "R", response);
}

static char *hud_getweaponstatus(MECH * mech, int sect, int crit, int data)
{
    static char wstatus[12];

    if (PartIsBroken(mech, sect, crit))
	return "*";
    if (PartIsDisabled(mech, sect, crit))
	return "D";
    switch (PartTempNuke(mech, sect, crit)) {
    case FAIL_JAMMED:
	return "J";
    case FAIL_SHORTED:
	return "S";
    case FAIL_DUD:
	return "d";
    case FAIL_EMPTY:
	return "E";
    case FAIL_AMMOJAMMED:
	return "A";
    case FAIL_DESTROYED:
	return "*";
    }
    if (GetPartFireMode(mech, sect, crit) & IS_JETTISONED_MODE)
	return "j";
    if (data) {
	sprintf(wstatus, "%d", data / WEAPON_TICK);
	return wstatus;
    }
    return "R";
}

static char *hud_getfiremode(MECH * mech, int sect, int crit, int type)
{
    int mode = GetPartFireMode(mech, sect, crit);
    static char wmode[30];
    char *p = wmode;

    if (mode & RAC_TWOSHOT_MODE)
	*p++ = '2';
    if (mode & RAC_FOURSHOT_MODE)
	*p++ = '4';
    if (mode & RAC_SIXSHOT_MODE)
	*p++ = '6';
    if (mode & WILL_JETTISON_MODE)
	*p++ = 'B';
    if (mode & GATTLING_MODE)
	*p++ = 'G';
    if (mode & HOTLOAD_MODE)
	*p++ = 'H';
    if (mode & RFAC_MODE)
	*p++ = 'R';
    if ((mode & ON_TC) && !(MechCritStatus(mech) & TC_DESTROYED))
	*p++ = 'T';
    if (mode & ULTRA_MODE)
	*p++ = 'U';
    if (mode & HEAT_MODE)
	*p++ = 'h';

    if (mode & (OS_USED | ROCKET_FIRED))
	*p++ = 'o';
    else if ((mode & OS_MODE) || (MechWeapons[type].special & ROCKET))
	*p++ = 'O';

    if (MechWeapons[type].special & INARC)
	*p++ = 'I';
    if (MechWeapons[type].special & NARC)
	*p++ = 'N';
    if (MechWeapons[type].special & STREAK)
	*p++ = 'S';

    if (MechWeapons[type].special & AMS) {
	if (MechStatus(mech) & AMS_ENABLED)
	    *p++ = 'A';
	else
	    *p++ = 'a';
    }

    /* XXX Do enhanced damage */

    if (p == wmode)
    	*p++ = '-';

    *p = '\0';
    return wmode;
}

static char *hud_getammomode(MECH * mech, int mode)
{
    static char amode[20];
    char *p = amode;

    if (mode & SWARM1_MODE)
	*p++ = '1';
    if (mode & ARTEMIS_MODE)
	*p++ = 'A';
    if (mode & CLUSTER_MODE)
	*p++ = 'C';
    if (mode & INARC_ECM_MODE)
	*p++ = 'E';
    if (mode & AC_FLECHETTE_MODE)
	*p++ = 'F';
    if (mode & INARC_HAYWIRE_MODE)
	*p++ = 'H';
    if (mode & INFERNO_MODE)
	*p++ = 'I';
    if (mode & LBX_MODE)
	*p++ = 'L';
    if (mode & MINE_MODE)
	*p++ = 'M';
    if (mode & NARC_MODE)
	*p++ = 'N';
    if (mode & AC_PRECISION_MODE)
	*p++ = 'P';
    if (mode & SWARM_MODE)
	*p++ = 'S';
    if (mode & AC_AP_MODE)
	*p++ = 'a';
    if (mode & INARC_EXPLO_MODE)
	*p++ = 'X';
    if (mode & AC_INCENDIARY_MODE)
	*p++ = 'e';
    if (mode & SMOKE_MODE)
	*p++ = 's';

    if (p == amode)
	*p++ = '-';
    *p = '\0';
    return amode;
}

static void hud_weapons(DESC * d, MECH * mech, char *msgclass, char *args)
{
    int sect, weapcount, i, weapnum = -1;
    unsigned char weaparray[MAX_WEAPS_SECTION];
    unsigned char weapdata[MAX_WEAPS_SECTION];
    int critical[MAX_WEAPS_SECTION];
    char response[LBUF_SIZE];

    UpdateRecycling(mech);

    for (sect = 0; sect < NUM_SECTIONS; sect++) {
        weapcount = FindWeapons(mech, sect, weaparray, weapdata, critical);
        if (weapcount <= 0)
            continue;
        for (i = 0; i < weapcount; i++) {
            weapnum++;
            sprintf(response, "%d,%d,%d,%s%s,%s,%s,%s",
                    weapnum,
                    weaparray[i],
                    GetPartBrand(mech, sect, critical[i]),
                    ShortArmorSectionString(MechType(mech), MechMove(mech),
                        sect), GetPartFireMode(mech, sect,
                            critical[i]) & REAR_MOUNT ? "r" : "",
                    hud_getweaponstatus(mech, sect, critical[i], weapdata[i]),
                    hud_getfiremode(mech, sect, critical[i], weaparray[i]),
                    hud_getammomode(mech, GetPartAmmoMode(mech, sect,
                            critical[i])));
            hudinfo_notify(d, msgclass, "L", response);
        }
    }
    hudinfo_notify(d, msgclass, "D", "Done");
}


static int get_weaponmodes(int weapindx, char *firemodes, char *ammomodes,
    char *damagetype)
{
    int spec = MechWeapons[weapindx].special;

    if (spec & PCOMBAT)
	return 0;

    switch (MechWeapons[weapindx].type) {
    case TMISSILE:
	strcat(damagetype, "M");
	if (spec & AMS) {
	    strcat(damagetype, "d");
	    strcat(firemodes, "Aa");
	    break;
	}
	if (spec & INARC) {
	    strcat(firemodes, "I");
	    strcat(ammomodes, "EHe");
	    break;
	}
	if (spec & NARC) {
	    strcat(firemodes, "N");
	    break;
	}
	if (spec & IDF) {	/* LRM */
	    strcat(ammomodes, "1ACMNSs");
	    strcat(damagetype, "g");
	    strcat(firemodes, "Hi");
	} else if (spec & MRM)	/* MRM */
	    strcat(damagetype, "g");
	else			/* SRM/SR_DFM */
	    strcat(ammomodes, "AIN");
	if (spec & DFM)
	    strcat(damagetype, "D");
	if (spec & ELRM)
	    strcat(damagetype, "e");
	if (spec & STREAK)
	    strcat(firemodes, "S");
	break;
    case TAMMO:
	if (spec & GAUSS) {
	    strcat(damagetype, "G");
	    if (spec & HVYGAUSS)
		strcat(damagetype, "H");
	    break;
	}
	strcat(damagetype, "B");

	if (spec & CASELESS)
	    strcat(damagetype, "C");
	if (spec & HYPER)
	    strcat(damagetype, "Y");
	if (spec & RAC)
	    strcat(firemodes, "246");
	if (spec & GMG)
	    strcat(firemodes, "G");
	if (spec & RFAC) {
	    strcat(firemodes, "R");
	    strcat(ammomodes, "FPai");
	}
	if (spec & LBX)
	    strcat(ammomodes, "L");
	if (spec & ULTRA)
	    strcat(firemodes, "U");
	break;
    case TARTILLERY:
	strcat(damagetype, "Ag");
	strcat(firemodes, "Hi");
	strcat(ammomodes, "CMs");
	break;
    case TBEAM:
	strcat(damagetype, "E");
	if (spec & HVYW)
	    strcat(damagetype, "h");
	if (spec & PULSE)
	    strcat(damagetype, "p");
	if (spec & CHEAT)
	    strcat(firemodes, "h");
	if (spec & A_POD)
	    strcat(damagetype, "a");
	break;
    }
    if (spec & NOSPA)
	ammomodes[0] = '\0';
    return 1;
}

static void hud_weaponlist(DESC * d, MECH * mech, char *msgclass,
    char *args)
{
    int i;
    char firemodes[30] = "";
    char ammomodes[20] = "";
    char damagetype[10] = "";
    char response[LBUF_SIZE];
    struct weapon_struct *w;

    for (i = 0; i < num_def_weapons; i++) {
	firemodes[0] = ammomodes[0] = damagetype[0] = '\0';
	if (!get_weaponmodes(i, firemodes, ammomodes, damagetype))
	    continue;

	if (strlen(firemodes) == 0)
	    strcat(firemodes, "-");
	if (strlen(ammomodes) == 0)
	    strcat(ammomodes, "-");

	w = &MechWeapons[i];
	sprintf(response,
	    "%d,%s,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%s,%s,%s,%d", i,
	    w->name, w->min, w->shortrange, w->medrange, w->longrange,
	    w->min_water, w->shortrange_water, w->medrange_water,
	    w->longrange_water, w->criticals, w->weight, w->damage, w->vrt,
	    firemodes, ammomodes, damagetype, w->heat * 10);
	hudinfo_notify(d, msgclass, "L", response);
    }

    hudinfo_notify(d, msgclass, "D", "Done");
}

static void hud_limbstatus(DESC * d, MECH * mech, char *msgclass,
    char *args)
{

    int locs[] = { RLEG, LLEG, RARM, LARM };
    int todo = 3;

    UpdateRecycling(mech);

    if (MechType(mech) == CLASS_MECH) {
	for (; todo >= 0; todo--) {
	    char *sect = ShortArmorSectionString(MechType(mech),
		MechMove(mech), locs[todo]);
	    char status[10];

	    if (SectIsDestroyed(mech, locs[todo]))
		strcpy(status, "*");
	    else if (MechSections(mech)[locs[todo]].recycle > 0)
		sprintf(status, "%d",
		    MechSections(mech)[locs[todo]].recycle / WEAPON_TICK);
	    else
		strcpy(status, "R");

	    hudinfo_notify(d, msgclass, "L", tprintf("%s,%s", sect,
		    status));
	}
    }
    hudinfo_notify(d, msgclass, "D", "Done");
}

static void hud_ammostatus(DESC * d, MECH * mech, char *msgclass,
    char *args)
{
    unsigned char weapnums[8 * MAX_WEAPS_SECTION];
    unsigned short curamm[8 * MAX_WEAPS_SECTION];
    unsigned short maxamm[8 * MAX_WEAPS_SECTION];
    unsigned int ammomode[8 * MAX_WEAPS_SECTION];
    int i, ammonum;
    char response[LBUF_SIZE];

    ammonum = FindAmmunition(mech, weapnums, curamm, maxamm, ammomode);

    for (i = 0; i < ammonum; i++) {
	sprintf(response, "%d,%d,%s,%d,%d", i, weapnums[i],
	    hud_getammomode(mech, ammomode[i]), curamm[i], maxamm[i]);
	hudinfo_notify(d, msgclass, "L", response);
    }
    hudinfo_notify(d, msgclass, "D", "Done");
}

static char hud_typechar(MECH * mech)
{

    if (MechMove(mech) == MOVE_NONE)
	return 'i';

    switch (MechType(mech)) {
    case CLASS_MECH:
	if (MechMove(mech) == MOVE_QUAD)
	    return 'Q';
	return 'B';
    case CLASS_VEH_GROUND:
    case CLASS_VEH_NAVAL:
	switch (MechMove(mech)) {
	case MOVE_TRACK:
	    return 'T';
	case MOVE_WHEEL:
	    return 'W';
	case MOVE_HOVER:
	    return 'H';
	case MOVE_HULL:
	    return 'N';
	case MOVE_FOIL:
	    return 'Y';
	case MOVE_SUB:
	    return 'U';
	default:
	    SendError(tprintf("Unknown movement type on vehicle #%d: %d",
		    mech->mynum, MechMove(mech)));
	    return '?';
	}
    case CLASS_VTOL:
	return 'V';
    case CLASS_AERO:
	return 'F';
    case CLASS_DS:
	return 'A';
    case CLASS_SPHEROID_DS:
	return 'D';
    case CLASS_MW:
	return 'I';
    case CLASS_BSUIT:
	return 'S';
    }
    SendError(tprintf("Unknown unit type on unit #%d: %d (move %d)",
	    mech->mynum, MechType(mech), MechMove(mech)));
    return '?';
}

static float MaxSettableSpeed(MECH * mech)
{
    int maxspeed = MMaxSpeed(mech);

    if (MechMove(mech) == MOVE_VTOL)
	maxspeed = sqrt((float) maxspeed * maxspeed -
	    MechVerticalSpeed(mech) * MechVerticalSpeed(mech));

    maxspeed = maxspeed > 0.0 ? maxspeed : 0.0;

    if ((MechSpecials(mech) & TRIPLE_MYOMER_TECH) && MechHeat(mech) >= 9.)
	maxspeed = ceil((rint((maxspeed / 1.5) / MP1) + 1) * 1.5) * MP1;
    return maxspeed;
}

static float MaxVerticalSpeed(MECH * mech)
{
    int maxspeed = MMaxSpeed(mech);

    if (MechMove(mech) != MOVE_VTOL)
	return 0.0;

    maxspeed = sqrt((float) maxspeed * maxspeed -
	MechDesiredSpeed(mech) * MechDesiredSpeed(mech));
    return maxspeed;
}

static char *hud_advtech(MECH * mech)
{
    static char advtech[30];
    char *p = advtech;
    int spec = MechSpecials(mech);

    if (spec & ECM_TECH)
	*p++ = 'E';
    if (spec & BEAGLE_PROBE_TECH)
	*p++ = 'B';
    if (spec & MASC_TECH)
	*p++ = 'M';
    if (spec & AA_TECH)
	*p++ = 'R';
    if (spec & SLITE_TECH)
	*p++ = 'S';
    if (spec & TRIPLE_MYOMER_TECH)
	*p++ = 't';

    spec = MechSpecials2(mech);
    if (spec & ANGEL_ECM_TECH)
	*p++ = 'A';
    if (spec & NULLSIGSYS_TECH)
	*p++ = 'N';
    if (spec & BLOODHOUND_PROBE_TECH)
	*p++ = 'b';
    if (spec & STEALTH_ARMOR_TECH)
	*p++ = 's';

    spec = MechInfantrySpecials(mech);
    if (spec & FC_INFILTRATORII_STEALTH_TECH) {
	*p++ = 'I';
	*p++ = 'P';
    }
    if (spec & CAN_JETTISON_TECH)
	*p++ = 'J';
    if (spec & DC_KAGE_STEALTH_TECH)
	*p++ = 'K';
    if (spec & INF_ANTILEG_TECH)
	*p++ = 'L';
    if (spec & INF_SWARM_TECH)
	*p++ = 'W';
    if (spec & FWL_ACHILEUS_STEALTH_TECH)
	*p++ = 'a';
    if (spec & INF_MOUNT_TECH)
	*p++ = 'f';
    if (spec & FC_INFILTRATOR_STEALTH_TECH)
	*p++ = 'i';
    if (spec & MUST_JETTISON_TECH)
	*p++ = 'j';
    if (spec & CS_PURIFIER_STEALTH_TECH)
	*p++ = 'p';

    if (HasC3i(mech))
	*p++ = 'C';
    if (HasTAG(mech))
	*p++ = 'T';
    if (HasC3s(mech))
	*p++ = 'c';
    if (HasC3m(mech))
	*p++ = 'm';

    if (p == advtech)
        *p++ = '-';

    *p = '\0';
    return advtech;
}

static void hud_templateinfo(DESC * d, MECH * mech, char *msgclass,
    char *args)
{
    char response[LBUF_SIZE];
    char fuel[20];

    if (FlyingT(mech) && AeroFuelOrig(mech))
	sprintf(fuel, "%d", AeroFuelOrig(mech));
    else
	strcpy(fuel, "-");

    sprintf(response, "%c,%s,%s,%.3f,%.3f,%.3f,%.3f,%s,%d,%s",
	hud_typechar(mech), MechType_Ref(mech), MechType_Name(mech),
	WalkingSpeed(MaxSettableSpeed(mech)), MaxSettableSpeed(mech), 
	-WalkingSpeed(MaxSettableSpeed(mech)),
	MaxVerticalSpeed(mech), fuel, MechRealNumsinks(mech),
	hud_advtech(mech));
    hudinfo_notify(d, msgclass, "R", response);
}

static void hud_templatearmor(DESC * d, MECH * mech, char *msgclass,
    char *args)
{
    char response[LBUF_SIZE];
    int sect;

    for (sect = 0; sect < NUM_SECTIONS; sect++) {
	if (GetSectOInt(mech, sect)) {
	    sprintf(response, "%s,%d,%d,%d",
		ShortArmorSectionString(MechType(mech), MechMove(mech),
		    sect), GetSectOArmor(mech, sect), GetSectORArmor(mech,
		    sect), GetSectOInt(mech, sect));
	    hudinfo_notify(d, msgclass, "L", response);
	}
    }
    hudinfo_notify(d, msgclass, "D", "Done");
}

static void hud_armorstatus(DESC * d, MECH * mech, char *msgclass,
    char *args)
{
    char response[LBUF_SIZE];
    int sect;

    for (sect = 0; sect < NUM_SECTIONS; sect++) {
	if (GetSectOInt(mech, sect)) {
	    sprintf(response, "%s,%d,%d,%d",
		ShortArmorSectionString(MechType(mech), MechMove(mech),
		    sect), GetSectArmor(mech, sect), GetSectRArmor(mech,
		    sect), GetSectInt(mech, sect));
	    hudinfo_notify(d, msgclass, "L", response);
	}
    }
    hudinfo_notify(d, msgclass, "D", "Done");
}

static char *hud_arcstring(int arc)
{
    static char arcstr[5];
    char *p = arcstr;

    if (arc & FORWARDARC)
	*p++ = '*';
    if (arc & LSIDEARC)
	*p++ = 'l';
    if (arc & RSIDEARC)
	*p++ = 'r';
    if (arc & REARARC)
	*p++ = 'v';
    if (arc & TURRETARC)
	*p++ = 't';

    if (p == arcstr)
	*p++ = '-';

    *p = '\0';
    return arcstr;
}

static char *hud_sensorstring(MECH * mech, int losflag)
{
    if ((losflag & MECHLOSFLAG_SEESP) && (losflag & MECHLOSFLAG_SEESS))
	return "PS";
    if (losflag & MECHLOSFLAG_SEESP)
	return "P";
    if (losflag & MECHLOSFLAG_SEESS)
	return "S";
    return "-";
}

static void hud_contacts(DESC * d, MECH * mech, char *msgclass, char *args)
{
    char response[LBUF_SIZE];
    MECH *other;
    MAP *map = getMap(mech->mapindex);
    int i, losflag, bearing, btc, weaponarc, x, y;
    float range, rtc;
    char jumph[12];
    char *mechname, *constat;

    if (!map) {
	hudinfo_notify(d, msgclass, "E", "You are on no map");
	return;
    }

    for (i = 0; i < map->first_free; i++) {
	if (map->mechsOnMap[i] == mech->mynum || map->mechsOnMap[i] == -1)
	    continue;

	other = (MECH *) FindObjectsData(map->mechsOnMap[i]);
	if (!other || !Good_obj(other->mynum))
	    continue;

	range = FlMechRange(map, mech, other);
	x = MechX(other);
	y = MechY(other);
	losflag = InLineOfSight(mech, other, x, y, range);
	if (!losflag)
	    continue;
	bearing = FindBearing(MechFX(mech), MechFY(mech), MechFX(other),
	    MechFY(other));
	weaponarc = InWeaponArc(mech, MechFX(other), MechFY(other));

	if (Jumping(other))
	    sprintf(jumph, "%d", MechJumpHeading(other));
	else
	    strcpy(jumph, "-");

	FindRangeAndBearingToCenter(other, &rtc, &btc);

	if (!InLineOfSight_NB(mech, other, MechX(other), MechY(other),
		0.0))
	    mechname = "something";
	else
	    mechname = silly_atr_get(other->mynum, A_MECHNAME);

	if (!mechname || !*mechname)
	    mechname = "-";

	constat = getStatusString(other, !MechSeemsFriend(mech, other));
	if (strlen(constat) == 0)
	    constat = "-";

	sprintf(response,
	    "%s,%s,%s,%c,%s,%d,%d,%d,%.3f,%d,%.3f,%.3f,%d,%s,%.3f,%d,%d,%.0f,%s",
	    MechIDS(other, MechSeemsFriend(mech, other)),
	    hud_arcstring(weaponarc), hud_sensorstring(mech, losflag),
	    hud_typechar(other), mechname, MechX(other),
	    MechY(other), MechZ(other), range, bearing, MechSpeed(other),
	    MechVerticalSpeed(other), MechVFacing(other), jumph, rtc, btc,
	    MechTons(other), MechHeat(other), constat);
	hudinfo_notify(d, msgclass, "L", response);
    }
    hudinfo_notify(d, msgclass, "D", "Done");
}

static char * building_status(MAP * map, int locked)
{
    static char buildingstatus[7];
    char *p = buildingstatus;

    if (BuildIsCS(map))
	*p++ = 'C';

    if (locked)
	*p++ = 'E';
    else
	*p++ = 'F';

    if (BuildIsHidden(map))
	*p++ = 'H';

    if (BuildIsSafe(map) || (locked && BuildIsCS(map)))
	*p++ = 'X';
    else if (locked)
	*p++ = 'x';

    if (p == buildingstatus)
        *p++ = '-';

    *p = '\0';

    return buildingstatus;
}

static void hud_building_contacts(DESC * d, MECH * mech, char *msgclass,
				  char *args)
{
    char response[LBUF_SIZE];
    MAP * map = getMap(mech->mapindex);
    MAP * building_map;
    char * building_name;
    mapobj * building;
    float fx, fy, range;
    int z, losflag, locked, bearing, weaponarc;
    
    if (!map) {
        hudinfo_notify(d, msgclass, "E", "You are on no map");
        return;
    }

    for (building = first_mapobj(map, TYPE_BUILD); building;
	 building = next_mapobj(building)) {

	MapCoordToRealCoord(building->x, building->y, &fx, &fy);
	z = Elevation(map, building->x, building->y) + 1;
	range = FindRange(MechFX(mech), MechFY(mech), MechFZ(mech), fx, fy,
			  ZSCALE * z);

	if (!building->obj)
	    continue;

	building_map = getMap(building->obj);
	if (!building_map)
	    continue;

	losflag = InLineOfSight(mech, NULL, building->x, building->y, range);
	if (!losflag || (losflag & MECHLOSFLAG_BLOCK))
	    continue;

	if (BuildIsInvis(building_map))
	    continue;

	locked = !can_pass_lock(mech->mynum, building->obj, A_LENTER);
	if (locked && BuildIsHidden(building_map))
	    continue;

	bearing = FindBearing(MechFX(mech), MechFY(mech), fx, fy);
	weaponarc = InWeaponArc(mech, fx, fy);
	building_name = silly_atr_get(building->obj, A_MECHNAME);
	if (!building_name || !*building_name)
	    building_name = strip_ansi(Name(building->obj));

	if (!building_name || !*building_name)
	    building_name = "-";

	sprintf(response, "%s,%s,%d,%d,%d,%f,%d,%d,%d,%s",
		hud_arcstring(weaponarc), building_name, building->x,
		building->y, z, range, bearing, building_map->cf,
		building_map->cfmax, building_status(building_map, locked));
	hudinfo_notify(d, msgclass, "L", response);
    }
    hudinfo_notify(d, msgclass, "D", "Done");

};

static char hud_damstr[] = "OoxX*?";
static char hud_damagechar(MECH * mech, int sect, int type)
{
    int dummy;

    switch (type) {
    case 1:
	if (GetSectOArmor(mech, sect))
	    return hud_damstr[ArmorEvaluateSerious(mech, sect, 1, &dummy)];
	return '-';
    case 2:
	if (GetSectOInt(mech, sect))
	    return hud_damstr[ArmorEvaluateSerious(mech, sect, 2, &dummy)];
	return '-';
    case 4:
	if (GetSectORArmor(mech, sect))
	    return hud_damstr[ArmorEvaluateSerious(mech, sect, 4, &dummy)];
	return '-';
    }
    return '?';
}

static MECH *hud_scantarget(DESC * d, MECH * mech, char *msgclass,
    char *args)
{
    MECH *targ;
    float range;

    if (!MechScanRange(mech)) {
	hudinfo_notify(d, msgclass, "E",
	    "Your system seems to be inoperational");
	return NULL;
    }

    if (strlen(args) != 2 ||
	!(targ = getMech(FindTargetDBREFFromMapNumber(mech, args)))) {
	hudinfo_notify(d, msgclass, "E", "No such target");
	return NULL;
    }

    range = FaMechRange(mech, targ);

    if (!InLineOfSight(mech, targ, MechX(targ), MechY(targ), range)) {
	hudinfo_notify(d, msgclass, "E", "No such target");
	return NULL;
    }

    if (!MechIsObservator(mech) &&
	(int) range > MechScanRange(mech)) {
	hudinfo_notify(d, msgclass, "E", "Out of range");
	return NULL;
    }

    if (MechType(targ) == CLASS_MW ||
	!InLineOfSight_NB(mech, targ, MechX(targ), MechY(targ), range)) {
	hudinfo_notify(d, msgclass, "E", "Unable to scan target");
	return NULL;
    }

    if (!MechIsObservator(mech)) {
	mech_notify(targ, MECHSTARTED,
	    tprintf("You are being scanned by %s",
		GetMechToMechID(targ, mech)));
	auto_reply(targ, tprintf("%s just scanned me.",
		GetMechToMechID(targ, mech)));
    }
    return targ;
}

static void hud_armorscan(DESC * d, MECH * mech, char *msgclass,
    char *args)
{
    char response[LBUF_SIZE];
    int sect;
    MECH *targ;

    targ = hud_scantarget(d, mech, msgclass, args);
    if (!targ)
	return;

    for (sect = 0; sect < NUM_SECTIONS; sect++) {
	if (GetSectOInt(targ, sect)) {
	    sprintf(response, "%s,%c,%c,%c",
	      ShortArmorSectionString(MechType(targ), MechMove(targ), sect),
	      hud_damagechar(targ, sect, 1), hud_damagechar(targ, sect, 4),
	      hud_damagechar(targ, sect, 2));
	    hudinfo_notify(d, msgclass, "L", response);
	}
    }
    hudinfo_notify(d, msgclass, "D", "Done");
}

static char *hud_getweapscanstatus(MECH * mech, int sect, int crit,
    int data)
{
    if (PartIsNonfunctional(mech, sect, crit))
	return "*";
    if (data)
	return "-";
    return "R";
}

static void hud_weapscan(DESC * d, MECH * mech, char *msgclass, char *args)
{
    int sect, weapcount, i, weapnum = -1;
    unsigned char weaparray[MAX_WEAPS_SECTION];
    unsigned char weapdata[MAX_WEAPS_SECTION];
    int critical[MAX_WEAPS_SECTION];
    char response[LBUF_SIZE];
    MECH *targ;

    targ = hud_scantarget(d, mech, msgclass, args);
    if (!targ)
	return;

    UpdateRecycling(targ);

    for (sect = 0; sect < NUM_SECTIONS; sect++) {
	if (SectIsDestroyed(targ, sect))
	    continue;
	weapcount = FindWeapons(targ, sect, weaparray, weapdata, critical);
	if (weapcount <= 0)
	    continue;
	for (i = 0; i < weapcount; i++) {
	    weapnum++;
	    sprintf(response, "%d,%d,%s,%s", weapnum, weaparray[i],
		ShortArmorSectionString(MechType(targ), MechMove(targ),
		    sect), hud_getweapscanstatus(targ, sect, critical[i],
		    weapdata[i]/WEAPON_TICK));
	    hudinfo_notify(d, msgclass, "L", response);
	}
    }
    hudinfo_notify(d, msgclass, "D", "Done");
}

static void hud_tactical(DESC * d, MECH * mech, char *msgclass, char *args)
{
    MAP *map = getMap(mech->mapindex);
    char *argv[5], result[LBUF_SIZE], *p;
    char mapid[21], mapname[MBUF_SIZE];
    int argc;
    int height = 24;
    short cx = MechX(mech), cy = MechY(mech);
    int sx, sy, ex, ey, x, y, losflag, lostactical = 0;
    hexlosmap_info *losmap = NULL;

    if (!MechLRSRange(mech)) {
	hudinfo_notify(d, msgclass, "E",
	    "Your system seems to be inoperational");
	return;
    }

    if (!map) {
	hudinfo_notify(d, msgclass, "E", "You are on no map");
	return;
    }

    argc = mech_parseattributes(args, argv, 4);

    switch (argc) {
    case 4:
        if (strcmp("l", argv[3])) {
            hudinfo_notify(d, msgclass, "E", "Invalid fourth argument");
            return;
        }
    	lostactical = 1;
    	/* FALLTHROUGH */
    case 3: {
	    float fx, fy;
	    int bearing = atoi(argv[1]);
	    float range = atof(argv[2]);

	    if (!MechIsObservator(mech) &&
		abs((int) range) > MechLRSRange(mech)) {
		hudinfo_notify(d, msgclass, "E", "Out of range");
		return;
	    }
	    FindXY(MechFX(mech), MechFY(mech), bearing, range, &fx, &fy);
	    RealCoordToMapCoord(&cx, &cy, fx, fy);
	}
	/* FALLTHROUGH */
    case 1:
	height = atoi(argv[0]);
	if (!height || height < 0 || height > 40) {
	    hudinfo_notify(d, msgclass, "E", "Invalid 1st argument");
	    return;
	}
	break;
    default:
	hudinfo_notify(d, msgclass, "E", "Invalid arguments");
	return;
    }

    height = MIN(height, 2 * MechLRSRange(mech));
    height = MIN(height, map->map_height);

    sy = MAX(0, cy - height / 2);
    ey = MIN(map->map_height, cy + height / 2);

    sx = MAX(0, cx - LRS_DISPLAY_WIDTH / 2);
    ex = MIN(map->map_width, cx + LRS_DISPLAY_WIDTH / 2);

    if (lostactical || MapIsDark(map) || (MechType(mech) == CLASS_MW &&
    					  mudconf.btech_mw_losmap))
	losmap = CalculateLOSMap(map, mech, sx, sy, ex - sx, ey - sy);

    if (!mudconf.hudinfo_show_mapinfo || 
    	(mudconf.hudinfo_show_mapinfo == 1 && In_Character(map->mynum))) {
	strcpy(mapid, "-1");
	strcpy(mapname, "-1");
    } else {
	sprintf(mapid, "%d", map->mynum);
	sprintf(mapname, "%s", map->mapname);
    };

    sprintf(result, "%d,%d,%d,%d,%s,%s,-1,%d,%d", sx, sy, ex - 1, ey - 1,
	mapid, mapname, map->map_width, map->map_height);
    hudinfo_notify(d, msgclass, "S", result);

    for (y = sy; y < ey; y++) {
	sprintf(result, "%d,", y);
	p = result + strlen(result);

	for (x = sx; x < ex; x++) {
	    if (losmap)
		losflag = LOSMap_GetFlag(losmap, x, y);
	    else
		losflag = MAPLOSHEX_SEE;

	    if (losflag & MAPLOSHEX_SEETERRAIN) {
		*p = GetTerrain(map, x, y);
		if (*p == ' ')
		    *p = '.';
		*p++;
	    } else
		*p++ = '?';

	    if (losflag & MAPLOSHEX_SEEELEV)
		*p++ = GetElev(map, x, y) + '0';
	    else
		*p++ = '?';
	}
	*p = '\0';
	hudinfo_notify(d, msgclass, "L", result);
    }

    hudinfo_notify(d, msgclass, "D", "Done");
}

static char *hud_getmapflags(MAP * map)
{
    static char res[5];
    char *p = res;

    if (map->flags & MAPFLAG_VACUUM)
	*p++ = 'V';
    if (map->flags & MAPFLAG_UNDERGROUND)
	*p++ = 'U';
    if (map->flags & MAPFLAG_DARK)
	*p++ = 'D';

    if (p == res)
        *p++ = '-';

    *p = '\0';
    return res;
}

static void hud_conditions(DESC * d, MECH * mech, char *msgclass,
    char *args)
{
    MAP *map = getMap(mech->mapindex);
    char res[200];
    char lt;

    switch (map->maplight) {
    case 0:
	lt = 'N';
	break;
    case 1:
	lt = 'T';
	break;
    case 2:
	lt = 'D';
	break;
    default:
	lt = '?';
	SendError(tprintf("Unknown light type %d on map #%d",
		map->maplight, map->mynum));
	break;
    }

    sprintf(res, "%c,%d,%d,%d,%s", lt, map->mapvis, map->grav,
	map->temp, hud_getmapflags(map));
    hudinfo_notify(d, msgclass, "R", res);
}

#endif