/*
* $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