/*
* $Id: mech.contacts.c,v 1.1.1.1 2005/01/11 21:18:14 kstevens Exp $
*
* Author: Markus Stenberg <fingon@iki.fi>
*
* Copyright (c) 1996 Markus Stenberg
* Copyright (c) 1998-2002 Thomas Wouters
* Copyright (c) 2000-2002 Cord Awtry
* All rights reserved
*
* Last modified: Tue Oct 6 17:15:16 1998 fingon
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sys/file.h>
#include "mech.h"
#include "mech.events.h"
#include "map.h"
#include "p.mech.utils.h"
#include "p.mech.los.h"
char *default_contactoptions = "!db";
static char *ac_desc[] = {
"0 - See enemies and friends, long text, color",
"1 - See enemies and friends, short text, color",
"2 - See enemies only, long text, color",
"3 - See enemies only, short text, color",
"4 - See enemies and friends, short text, no color",
"5 - See enemies only, short text, no color",
"6 - Disabled"
};
static char *c_desc[] = {
"0 - Very verbose",
"1 - Short form, the usual one",
"2 - Short form, the usual one, but do not see buildings",
"3 - Shorter form"
};
void show_brief_flags(dbref player, MECH * mech)
{
notify(player, tprintf("Brief status for %s:", GetMechToMechID(mech,
mech)));
#ifdef ADVANCED_LOS
notify(player, tprintf(" (A)utocontacts: %s",
ac_desc[mech->brief / 4]));
#endif
notify(player, tprintf(" (C)ontacts: %s",
c_desc[mech->brief % 4]));
}
void mech_brief(dbref player, void *data, char *buffer)
{
MECH *mech = (MECH *) data;
char c;
int v;
cch(MECH_USUALSM);
skipws(buffer);
if (!*buffer) {
show_brief_flags(player, mech);
return;
}
c = *buffer;
buffer++;
skipws(buffer);
DOCHECK(!*buffer, "Argument missing!");
DOCHECK(Readnum(v, buffer), "Invalid number!");
switch (toupper(c)) {
#ifdef ADVANCED_LOS
case 'A':
DOCHECK(v < 0 || v > 6, "Number out of range!");
v = BOUNDED(0, v, 6);
mech->brief = mech->brief % 4;
mech->brief += v * 4;
mech_notify(mech, MECHALL,
tprintf("Autocontact brevity set to %s.", ac_desc[v]));
return;
#endif
case 'C':
DOCHECK(v < 0 || v > 3, "Number out of range!");
v = BOUNDED(0, v, 3);
mech->brief = ((mech->brief / 4) * 4) + v;
mech_notify(mech, MECHALL, tprintf("Contact brevity set to %s.",
c_desc[v]));
return;
}
}
#define SEE_DEAD 0x01
#define SEE_SHUTDOWN 0x02
#define SEE_ALLY 0x04
#define SEE_ENEMA 0x08
#define SEE_TARGET 0x10
#define SEE_BUILDINGS 0x20
#define SEE_NEGNEXT 0x80
char getWeaponArc(MECH * mech, int arc)
{
if (arc & FORWARDARC)
return '*';
else if (arc & TURRETARC)
return 't';
else if (arc & RSIDEARC)
return 'r';
else if (arc & LSIDEARC)
return 'l';
else if (arc & REARARC)
return 'v';
else
return '?';
}
/* who: 0 for friend, 1 for enemy, 2 for 'self' */
char *getStatusString(MECH * target, int who)
{
static char statusstr[20];
int sptr = 0;
if (Destroyed(target))
statusstr[sptr++] = 'D';
if (Starting(target))
statusstr[sptr++] = 's';
else if (!Started(target))
statusstr[sptr++] = 'S';
if (Standing(target))
statusstr[sptr++] = 'f';
else if (Fallen(target))
statusstr[sptr++] = 'F';
if (ChangingHulldown(target))
statusstr[sptr++] = 'h';
else if (IsHulldown(target))
statusstr[sptr++] = 'H';
if (Towed(target))
statusstr[sptr++] = 'T';
else if (MechCarrying(target) > 0)
statusstr[sptr++] = 't';
if (Jumping(target))
statusstr[sptr++] = 'J';
if (OODing(target))
statusstr[sptr++] = 'O';
if (MechHeat(target))
statusstr[sptr++] = '+';
if (Jellied(target))
statusstr[sptr++] = 'I';
if (Burning(target))
statusstr[sptr++] = 'B';
if (MechLites(target))
statusstr[sptr++] = 'L';
if (MechLit(target))
statusstr[sptr++] = 'l';
if (MechSwarmTarget(target) > 0)
statusstr[sptr++] = 'W';
if (CarryingClub(target))
statusstr[sptr++] = 'C';
if (checkAllSections(target, NARC_ATTACHED) ||
checkAllSections(target, INARC_HOMING_ATTACHED)) {
if (who == 1)
statusstr[sptr++] = 'N';
else
statusstr[sptr++] = 'n';
}
#ifndef ECM_ON_CONTACTS
if (who > 1) {
#endif
if (AnyECCMActive(target))
statusstr[sptr++] = 'P';
if (AnyECMActive(target))
statusstr[sptr++] = 'E';
if (AnyECMProtected(target))
statusstr[sptr++] = 'p';
if (AnyECMDisturbed(target))
statusstr[sptr++] = 'e';
#ifndef ECM_ON_CONTACTS
}
#endif
if (Spinning(target))
statusstr[sptr++] = 'X';
#ifdef BT_MOVEMENT_MODES
if (Sprinting(target))
statusstr[sptr++] = 'M';
if (Evading(target))
statusstr[sptr++] = 'm';
#endif
statusstr[sptr] = '\0';
return statusstr;
}
char getStatusChar(MECH * mech, MECH * mechTarget, int wCharNum)
{
char cRet = ' ';
switch (wCharNum) {
case 1:
cRet = MechSwarmTarget(mechTarget) > 0 ? 'W' :
Towed(mechTarget) ? 'T' : MechCarrying(mechTarget) >
0 ? 't' : CarryingClub(mechTarget) ? 'C' :
#ifdef BT_MOVEMENT_MODES
Sprinting(mechTarget) ? 'M' : Evading(mechTarget) ? 'm' :
#endif
' ';
break;
case 2:
cRet = Destroyed(mechTarget) ? 'D' :
MechLites(mechTarget) ? 'L' : MechLit(mechTarget) ? 'l' : ' ';
break;
case 3:
cRet = Jumping(mechTarget) ? 'J' : OODing(mechTarget) ? 'O' :
Fallen(mechTarget) ? 'F' : Standing(mechTarget) ? 'f' :
ChangingHulldown(mechTarget) ? 'h' : IsHulldown(mechTarget) ?
'H' : Spinning(mech) ? 'X' : ' ';
break;
case 4:
cRet = Started(mechTarget) ?
(MechHeat(mechTarget) ? '+' :
Jellied(mechTarget) ? 'I' :
Burning(mechTarget) ? 'B' : ' ') :
Staggering(mechTarget) ? 'G' :
Starting(mechTarget) ? 's' : 'S';
break;
case 5:
cRet = (checkAllSections(mechTarget, NARC_ATTACHED) ||
checkAllSections(mechTarget, INARC_HOMING_ATTACHED)) ?
(MechTeam(mechTarget) == MechTeam(mech) ? 'n' : 'N') :
#ifdef ECM_ON_CONTACTS
AnyECCMActive(mech) ? 'P' :
AnyECMActive(mech) ? 'E' : AnyECMProtected(mech) ? 'p' :
AnyECMDisturbed(mech) ? 'e' :
#endif
' ';
break;
}
return cRet;
}
void mech_contacts(dbref player, void *data, char *buffer)
{
MECH *mech = (MECH *) data, *tempMech;
MAP *mech_map = getMap(mech->mapindex), *tmp_map;
mapobj *building;
int loop, i, j, argc, bearing, buffindex = 0;
char *args[1], bufflist[MAX_MECHS_PER_MAP][120], buff[100];
int sbuff[MAX_MECHS_PER_MAP];
float range, rangelist[MAX_MECHS_PER_MAP], fx, fy;
int mechfound;
char weaponarc;
char *mech_name;
char see_what;
char *str;
char move_type[30];
char cStatus1, cStatus2, cStatus3, cStatus4, cStatus5;
int losflag;
int isvb;
int inlos;
int IsUsingHUD = 0;
cch(MECH_USUAL);
mechfound = 0;
argc = mech_parseattributes(buffer, args, 1);
isvb = (mech->brief % 4);
if (argc > 0) {
if (args[0][0] == 'h') {
IsUsingHUD = 1;
see_what =
(SEE_DEAD | SEE_SHUTDOWN | SEE_ENEMA | SEE_ALLY |
SEE_TARGET);
} else {
if (args[0][0] == '+') {
str = silly_atr_get(player, A_CONTACTOPT);
if (!*str)
strcpy(buff, default_contactoptions);
else {
strncpy(buff, str, 50);
buff[49] = 0;
if (strlen(buff) == 0)
strcpy(buff, default_contactoptions);
}
} else {
strncpy(buff, args[0], 50);
buff[49] = 0;
}
if (isvb == 1)
see_what = SEE_BUILDINGS;
else
see_what = 0x0;
for (loop = 0; loop < 50 && buff[loop]; loop++) {
char c;
c = buff[loop];
if (c == 'd')
(see_what & SEE_NEGNEXT) ? (see_what &=
~SEE_DEAD) : (see_what |= SEE_DEAD);
else if (c == 's')
(see_what & SEE_NEGNEXT) ? (see_what &=
~SEE_SHUTDOWN) : (see_what |= SEE_SHUTDOWN);
else if (c == 'b')
(see_what & SEE_NEGNEXT) ? (see_what &=
~SEE_BUILDINGS) : (see_what |= SEE_BUILDINGS);
else if (c == 'e')
(see_what & SEE_NEGNEXT) ? (see_what &=
~SEE_ENEMA) : (see_what |= SEE_ENEMA);
else if (c == 'a')
(see_what & SEE_NEGNEXT) ? (see_what &=
~SEE_ALLY) : (see_what |= SEE_ALLY);
else if (c == 't')
(see_what & SEE_NEGNEXT) ? (see_what &=
~SEE_TARGET) : (see_what |= SEE_TARGET);
else if (c == '!') {
see_what =
(SEE_NEGNEXT | SEE_DEAD | SEE_SHUTDOWN | SEE_ENEMA
| SEE_ALLY | SEE_TARGET);
} else
notify(player,
tprintf("Ignoring %c as contact option.", c));
}
}
} else {
see_what =
(SEE_DEAD | SEE_SHUTDOWN | SEE_ENEMA | SEE_ALLY | SEE_TARGET);
if (isvb == 1)
see_what |= SEE_BUILDINGS;
}
if (IsUsingHUD)
notify(player, "#HUDINFO:CON#Line of Sight Contacts:");
else if (isvb <= 2)
notify(player, "Line of Sight Contacts:");
for (loop = 0; loop < mech_map->first_free; loop++) {
if (!(mech_map->mechsOnMap[loop] != mech->mynum &&
mech_map->mechsOnMap[loop] != -1))
continue;
tempMech = (MECH *) FindObjectsData(mech_map->mechsOnMap[loop]);
if (!tempMech)
continue;
if (argc) {
if (!((MechSeemsFriend(mech, tempMech) ? (see_what & SEE_ALLY)
: (see_what & SEE_ENEMA)) ||
((see_what & SEE_TARGET) &&
(tempMech->mynum == MechTarget(mech)))))
continue;
if (!(((see_what & SEE_SHUTDOWN) || Started(tempMech)) ||
Destroyed(tempMech) || ((see_what & SEE_TARGET) &&
(tempMech->mynum == MechTarget(mech)))))
continue;
if (!(((see_what & SEE_DEAD) || !Destroyed(tempMech)) ||
((see_what & SEE_TARGET) &&
(tempMech->mynum == MechTarget(mech)))))
continue;
}
range = FlMechRange(mech_map, mech, tempMech);
if (!(losflag =
InLineOfSight(mech, tempMech, MechX(tempMech),
MechY(tempMech), range)))
continue;
if (Good_obj(tempMech->mynum)) {
if (!InLineOfSight_NB(mech, tempMech, MechX(tempMech),
MechY(tempMech), 0.0)) {
mech_name = "something";
inlos = 0;
} else {
mech_name = silly_atr_get(tempMech->mynum, A_MECHNAME);
inlos = 1;
}
} else
continue;
bearing =
FindBearing(MechFX(mech), MechFY(mech), MechFX(tempMech),
MechFY(tempMech));
weaponarc = getWeaponArc(mech, InWeaponArc(mech, MechFX(tempMech),
MechFY(tempMech)));
strcpy(move_type, GetMoveTypeID(MechMove(tempMech)));
if (isvb) {
if (!inlos) {
cStatus1 = ' ';
cStatus2 = ' ';
cStatus3 = ' ';
cStatus4 = ' ';
cStatus5 = ' ';
} else {
cStatus1 = getStatusChar(mech, tempMech, 1);
cStatus2 = getStatusChar(mech, tempMech, 2);
cStatus3 = getStatusChar(mech, tempMech, 3);
cStatus4 = getStatusChar(mech, tempMech, 4);
cStatus5 = getStatusChar(mech, tempMech, 5);
}
if (!IsUsingHUD) {
#ifdef SIMPLE_SENSORS
sprintf(buff,
"%s%c[%s]%c %-12.12s x:%3d y:%3d z:%3d r:%4.1f b:%3d s:%5.1f h:%3d S:%c%c%c%c%c%s",
#else
sprintf(buff,
"%s%c%c%c[%s]%c %-12.12s x:%3d y:%3d z:%3d r:%4.1f b:%3d s:%5.1f h:%3d S:%c%c%c%c%c%s",
#endif
tempMech->mynum == MechTarget(mech) ? "%ch%cr" :
!MechSeemsFriend(mech, tempMech) ? "%ch%cy" : "",
#ifndef SIMPLE_SENSORS
(losflag & MECHLOSFLAG_SEESP) ? 'P' : ' ',
(losflag & MECHLOSFLAG_SEESS) ? 'S' : ' ',
#endif
weaponarc, MechIDS(tempMech,
MechSeemsFriend(mech, tempMech)),
move_type[0], mech_name, MechX(tempMech),
MechY(tempMech), MechZ(tempMech), range, bearing,
MechSpeed(tempMech), MechVFacing(tempMech),
cStatus1,
cStatus2,
cStatus3,
cStatus4,
cStatus5,
(tempMech->mynum == MechTarget(mech) ||
!MechSeemsFriend(mech, tempMech)) ? "%c" : "");
} else {
#ifdef SIMPLE_SENSORS
sprintf(buff, "#HUDINFO:CON#%c,%c,%s,%c,%-12.12s,%3d,%3d,%3d,%4.1f,%3d,%4.1f,%3d,%c%c%c%c%c", /* ) <- balance */
#else
sprintf(buff,
"#HUDINFO:CON#%c,%c,%c,%c,%s,%c,%-12.12s,%3d,%3d,%3d,%4.1f,%3d,%4.1f,%3d,%c%c%c%c%c",
#endif
(tempMech->mynum == MechTarget(mech)) ? 'T' :
!MechSeemsFriend(mech, tempMech) ? 'E' : 'F',
#ifndef SIMPLE_SENSORS
(losflag & MECHLOSFLAG_SEESP) ? 'P' : ' ',
(losflag & MECHLOSFLAG_SEESS) ? 'S' : ' ',
#endif
weaponarc, MechIDS(tempMech,
MechSeemsFriend(mech, tempMech)),
move_type[0], mech_name, MechX(tempMech),
MechY(tempMech), MechZ(tempMech), range, bearing,
MechSpeed(tempMech), MechVFacing(tempMech),
cStatus1, cStatus2, cStatus3, cStatus4, cStatus5);
}
rangelist[buffindex] = range;
rangelist[buffindex] +=
(MechStatus(tempMech) & DESTROYED) ? 10000 : 0;
strcpy(bufflist[buffindex++], buff);
} else {
sprintf(buff, "[%s] %-17s Tonnage: %d", MechIDS(tempMech,
MechSeemsFriend(mech, tempMech)), mech_name,
MechTons(tempMech));
notify(player, buff);
sprintf(buff, " Range: %.1f hex\tBearing: %d degrees",
range, bearing);
notify(player, buff);
sprintf(buff, " Speed: %.1f KPH\tHeading: %d degrees",
MechSpeed(tempMech), MechVFacing(tempMech));
notify(player, buff);
sprintf(buff, " X, Y: %3d, %3d \tHeat: %.0f deg C.",
MechX(tempMech), MechY(tempMech), MechHeat(tempMech));
notify(player, buff);
sprintf(buff, " Movement Type: %s", move_type);
notify(player, buff);
notify(player, tprintf(" Mech is in %s Arc",
GetArcID(mech, InWeaponArc(mech, MechFX(tempMech),
MechFY(tempMech)))));
if (MechStatus(tempMech) & DESTROYED)
notify(player, " Mech Destroyed");
if (!(MechStatus(tempMech) & STARTED))
notify(player, " Mech Shutdown");
if (Fallen(tempMech))
notify(player, " Mech has Fallen!");
if (Jumping(tempMech))
notify(player,
tprintf(" Mech is Jumping!\tJump Heading: %d",
MechJumpHeading(tempMech)));
notify(player, " ");
}
}
if (see_what & SEE_BUILDINGS) {
for (building = first_mapobj(mech_map, TYPE_BUILD); building;
building = next_mapobj(building)) {
MapCoordToRealCoord(building->x, building->y, &fx, &fy);
range =
FindRange(MechFX(mech), MechFY(mech), MechFZ(mech), fx, fy,
ZSCALE * ((i =
Elevation(mech_map, building->x,
building->y)) + 1));
losflag =
InLineOfSight(mech, NULL, building->x, building->y, range);
if (!losflag || (losflag & MECHLOSFLAG_BLOCK))
continue;
if (!(building->obj && (tmp_map = getMap(building->obj))))
continue;
if (BuildIsInvis(tmp_map))
continue;
if ((j = !can_pass_lock(mech->mynum, tmp_map->mynum, A_LENTER))
&& BuildIsHidden(tmp_map))
continue;
bearing = FindBearing(MechFX(mech), MechFY(mech), fx, fy);
weaponarc = getWeaponArc(mech, InWeaponArc(mech, fx, fy));
mech_name = silly_atr_get(building->obj, A_MECHNAME);
if (!mech_name || !*mech_name)
mech_name = strip_ansi(Name(building->obj));
if (!IsUsingHUD) {
#ifdef SIMPLE_SENSORS
sprintf(buff,
"%s%c %-23.23s x:%3d y:%3d z:%2d r:%4.1f b:%3d CF:%4d /%4d S:%c%c%s",
#else
sprintf(buff,
"%s%c%c%c %-23.23s x:%3d y:%3d z:%2d r:%4.1f b:%3d CF:%4d /%4d S:%c%c%s",
#endif
j ? "%ch%cy" : "",
#ifndef SIMPLE_SENSORS
(losflag & MECHLOSFLAG_SEESP) ? 'P' : ' ',
(losflag & MECHLOSFLAG_SEESS) ? 'S' : ' ',
#endif
weaponarc, mech_name, building->x, building->y, i,
range, bearing, tmp_map->cf, tmp_map->cfmax,
(BuildIsSafe(tmp_map) || (j &&
BuildIsCS(tmp_map))) ? 'X' : j ? 'x' :
BuildIsCS(tmp_map) ? 'C' : ' ',
BuildIsHidden(tmp_map) ? 'H' : ' ', j ? "%c" : "");
} else {
#ifdef SIMPLE_SENSORS
sprintf(buff, "#HUDINFO:CON#%c,%c,%-21.21s,%3d,%3d,%3d,%4.1f,%3d,%4d,%4d,%c%c", /* ) <- balance */
#else
sprintf(buff,
"#HUDINFO:CON#%c,%c,%c,%c,%-21.21s,%3d,%3d,%3d,%4.1f,%3d,%4d,%4d,%c%c",
#endif
j ? 'E' : 'F',
#ifndef SIMPLE_SENSORS
(losflag & MECHLOSFLAG_SEESP) ? 'P' : ' ',
(losflag & MECHLOSFLAG_SEESS) ? 'S' : ' ',
#endif
weaponarc, mech_name, building->x, building->y, i,
range, bearing, tmp_map->cf, tmp_map->cfmax,
(BuildIsSafe(tmp_map) || (j &&
BuildIsCS(tmp_map))) ? 'X' : j ? 'x' :
BuildIsCS(tmp_map) ? 'C' : ' ',
BuildIsHidden(tmp_map) ? 'H' : ' ');
}
rangelist[buffindex] = range + 20000;
strcpy(bufflist[buffindex++], buff);
}
}
if (isvb) {
for (i = 0; i < buffindex; i++)
sbuff[i] = i;
/* print a sorted list of detected mechs */
/* use the ever-popular bubble sort */
for (i = 0; i < (buffindex - 1); i++)
for (j = (i + 1); j < buffindex; j++)
if (rangelist[sbuff[j]] > rangelist[sbuff[i]]) {
loop = sbuff[i];
sbuff[i] = sbuff[j];
sbuff[j] = loop;
}
for (loop = 0; loop < buffindex; loop++)
notify(player, bufflist[sbuff[loop]]);
}
if (IsUsingHUD)
notify(player, "#HUDINFO:CON#End Contact List");
else if (isvb <= 2)
notify(player, "End Contact List");
}
#undef SEE_DEAD
#undef SEE_SHUTDOWN
#undef SEE_ALLY
#undef SEE_ENEMA
#undef SEE_TARGET
#undef SEE_BUILDINGS
#undef SEE_NEGNEXT