/*
* $Id: mech.sensor.c,v 1.3 2005/08/08 07:56:08 murrayma 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
*
* Created: Mon Sep 2 14:45:01 1996 fingon
* Last modified: Thu Jul 9 20:35:16 1998 fingon
*
*/
#include "mech.h"
#include "map.h"
#define _MECH_SENSOR_C
#include "p.mech.ecm.h"
#include "p.mech.tag.h"
#include "mech.events.h"
#include "mech.sensor.h"
#include "autopilot.h"
#include "p.mech.utils.h"
#include "p.mech.lite.h"
#include "p.mech.los.h"
#include "p.btechstats.h"
#define SEE_SENSOR_PRIMARY 1
#define SEE_SENSOR_SECONDARY 2
int Sensor_ToHitBonus(MECH * mech, MECH * target, int flag, int maplight,
float range, int wAmmoMode)
{
int bth1, bth2;
int wLightMod = (wAmmoMode & AC_INCENDIARY_MODE) ? 1 : 0;
MAP *map = getMap(mech->mapindex);
maplight = maplight + wLightMod;
if (maplight < 0)
maplight = 0;
if (maplight > 2)
maplight = 2;
if (!(flag & (MECHLOSFLAG_SEESP | MECHLOSFLAG_SEESS)))
return 10000;
if (!(flag & MECHLOSFLAG_SEESP)) {
bth2 = 1 + sensors[(int) MechSensor(mech)[1]].tohitbonus_func(mech,
target, map, flag, maplight);
#ifdef SENSOR_BTH_DEBUG
SendDebug(tprintf("%d: BTH S+%d", mech->mynum, bth2));
#endif
return bth2;
}
if (!(flag & MECHLOSFLAG_SEESS) ||
(MechSensor(mech)[0] == MechSensor(mech)[1])) {
bth1 = sensors[(int) MechSensor(mech)[0]].tohitbonus_func(mech,
target, map, flag, maplight);
#ifdef SENSOR_BTH_DEBUG
SendDebug(tprintf("%d: BTH P+%d", mech->mynum, bth1));
#endif
return bth1;
}
bth1 = sensors[(int) MechSensor(mech)[0]].tohitbonus_func(mech, target,
map, flag, maplight);
bth2 = 1 + sensors[(int) MechSensor(mech)[1]].tohitbonus_func(mech,
target, map, flag, maplight);
#ifdef SENSOR_BTH_DEBUG
SendDebug(tprintf("%d: BTH +%d/+%d", mech->mynum, bth1, bth2));
#endif
return MIN(bth1, bth2);
}
int Sensor_CanSee(MECH * mech, MECH * target, int *flag, int arc,
float range, int mapvis, int maplight, int cloudbase)
{
int i, j = 0, sn;
MAP *map = getMap(mech->mapindex);
if (!(*flag & MECHLOSFLAG_SEEC2))
return 0;
if (target && (MechCritStatus(target) & INVISIBLE))
return 0;
/* Ok.. s'pose we can, at that. */
if (MechSensor(mech)[0] != MechSensor(mech)[1]) {
#define MaxVis(mech,sensor) ((sensors[sensor].maxvis*(((sensor)>=2 && MechMove(mech)==MOVE_NONE)?140:100)) / 100)
#define MaxVar(mech,sensor) sensors[sensor].maxvvar
#define MAXVR(mech,sensor) MaxVis(mech,sensor) - MaxVar(mech, sensor)
/* Check both seperately */
for (i = 0; i < 2; i++) {
sn = MechSensor(mech)[i];
/* No chance */
if (!sensors[sn].fullvision && !(arc & (FORWARDARC|TURRETARC)) &&
!Sees360(mech))
continue;
if (MaxVis(mech, sn) < range)
continue;
/* Okay, so this is a horrible, horrible hack that'll break when new
* sensors get added. Thankfully it's not as ugly as the rest of the
* constructs in this area, so i dont really care. -Foo */
if (target) {
if (cloudbase && sn < 3 && ((MechZ(mech) < cloudbase)
? (MechZ(target) >= cloudbase) : (MechZ(target)
< cloudbase)))
continue;
} else {
if (cloudbase && MechZ(mech) > cloudbase)
continue;
}
if (!sensors[sn].cansee_func(mech, target, map, range, *flag))
continue;
if (!sensors[sn].seechance_func(target, map, sn, range, mapvis,
maplight))
continue;
if (MaxVar(mech, sn) && (MAXVR(mech, sn)) < range)
if (((MAXVR(mech, sn)) + (MechVisMod(mech) * (MaxVar(mech,
sn) + 1)) / 100) < range)
continue;
j += (i + 1);
}
return j;
}
sn = MechSensor(mech)[0];
if (MaxVis(mech, sn) < range)
return 0;
if (cloudbase && target && sn < 3 &&
((MechZ(mech) < cloudbase) ? (MechZ(target) >= cloudbase)
: (MechZ(target) < cloudbase)))
return 0;
if (!sensors[sn].cansee_func(mech, target, map, range, *flag))
return 0;
if (!sensors[sn].seechance_func(target, map, sn, range, mapvis, maplight))
return 0;
if (MaxVar(mech, sn) && (MAXVR(mech, sn)) < range)
if (((MAXVR(mech, sn)) + MechVisMod(mech) * (MaxVar(mech,
sn) + 1) / 100) < range)
return 0;
return 3;
}
int Sensor_ArcBaseChance(int type, int arc)
{
int base = 100;
switch (type) {
case CLASS_MW:
if (arc & (LSIDEARC | RSIDEARC | REARARC))
return 0;
break;
case CLASS_BSUIT:
case CLASS_MECH:
if (arc & (LSIDEARC | RSIDEARC))
base = 70;
else if (arc & REARARC)
base = 40;
break;
default:
if (arc & (LSIDEARC | RSIDEARC))
base = 80;
else if (arc & REARARC)
base = 50;
if (arc & TURRETARC)
base += 15;
break;
}
return base;
}
extern int bth_modifier[];
/* Slow, but sacrifices we make for sake of playability.. :-) */
int Sensor_DriverBaseChance(MECH * mech)
{
int i = 1;
if (MechPer(mech) <= 2)
i = 36;
else if (MechPer(mech) >= 12)
i = 1;
else
i = (36 - bth_modifier[MechPer(mech) - 2]);
return 64 + i; /* Padded a bit */
}
int Sensor_Sees(MECH * mech, MECH * target, int f, int arc, float range,
int snum, int chance_divisor, int mapvis, int maplight)
{
MAP *map = getMap(mech->mapindex);
int chance = (Sensor_ArcBaseChance(MechType(mech), arc) * ((target &&
MechTeam(mech) != MechTeam(target)) ?
Sensor_DriverBaseChance(mech) : 100)) / 100;
int ch2 = sensors[snum].seechance_func(target, map, snum, range,
mapvis, maplight);
if (!ch2 || !sensors[snum].cansee_func(mech, target, map, range, f))
return 0;
if (target && IsDS(target))
chance = chance * 4;
if (target && MechCritStatus(target) & HIDDEN &&
MechTeam(mech) != MechTeam(target)) {
if (sensors[snum].matchletter[0] == 'B' &&
(MechInfantrySpecials(target) & STEALTH_TECH) &&
(!(MechInfantrySpecials(target) & CS_PURIFIER_STEALTH_TECH)))
return 0;
if (ch2 <= 100) {
if (range > 5)
return 0;
chance = chance / 4;
}
}
if (range < 3 || Number(1, 10000) < ((chance * ch2) / chance_divisor)) {
if (target && In_Character(mech->mynum) &&
In_Character(target->mynum) &&
MechTeam(mech) != MechTeam(target))
if (!Number(0, 5))
MadePerceptionRoll(mech, -2);
return 1;
}
return 0;
}
/* Main idea: If primary & secondary scanner differ,
check both scanners for chance (with secondary at 1/2 chance).
Also, if non-360degree scanners are used, check only forward arc for
them.
If both same, multiply chance by 1.1
*/
int Sensor_SeesNow(MECH * mech, MECH * target, int f, int arc, float range,
int mapvis, int maplight)
{
int i, sn;
if (MechSensor(mech)[0] != MechSensor(mech)[1]) {
/* Check both seperately */
for (i = 0; i < 2; i++) {
sn = MechSensor(mech)[i];
/* No chance */
if (!sensors[sn].fullvision && !(arc & (FORWARDARC|TURRETARC)) &&
!Sees360(mech))
continue;
if (MaxVis(mech, sn) < range)
continue;
if (Sensor_Sees(mech, target, f, arc, range, sn, i + 1, mapvis,
maplight))
return (i + 1);
}
return 0;
}
sn = MechSensor(mech)[0];
if (MaxVis(mech, sn) < range)
return 0;
return (Sensor_Sees(mech, target, f, arc, range, sn, 1, mapvis,
maplight));
return 3;
}
char *my_dump_flag(int i)
{
int j;
static char buf[MBUF_SIZE];
strcpy(buf, "");
for (j = 0; j < 32; j++)
if (i & (1 << j)) {
if (buf[0] == 0)
sprintf(buf, "%d", j);
else
sprintf(buf + strlen(buf), ",%d", j);
}
return buf;
}
#define AUTOCON_LONG 0x01
#define AUTOCON_WARN 0x02
#define AUTOCON_SHORT 0x04
static int valid_to_notice(MECH * mech, MECH * targ, int los)
{
int bf = (mech->brief / 4);
int foe;
if ((los < 0 && MechSeemsFriend(mech, targ)) ||
(los > 0 && MechTeam(mech) == MechTeam(targ)))
foe = 0;
else
foe = AUTOCON_WARN;
switch (bf) {
case 0:
return AUTOCON_LONG | foe;
case 1:
return AUTOCON_SHORT | foe;
case 2:
return foe ? (AUTOCON_LONG | foe) : 0;
case 3:
return foe ? (AUTOCON_SHORT | foe) : 0;
case 4:
return AUTOCON_SHORT;
case 5:
return foe ? AUTOCON_SHORT : 0;
case 6:
default:
return 0;
}
}
void Sensor_DoWeSeeNow(MECH * mech, unsigned short *fl, float range, int x,
int y, MECH * target, int mapvis, int maplight, int cloudbase,
int seeanew, int wlf)
{
int arc;
float x1, y1;
int sc, sl, st;
int f = *fl;
char buf[MBUF_SIZE];
if (!Started(mech))
return;
if (target) {
x1 = MechFX(target);
y1 = MechFY(target);
if (MechZ(mech) >= ATMO_Z && MechZ(target) >= ATMO_Z)
range = range / 3;
} else
MapCoordToRealCoord(x, y, &x1, &y1);
arc = InWeaponArc(mech, x1, y1);
if (f & MECHLOSFLAG_SEEN) {
if ((sl =
Sensor_CanSee(mech, target, &f, arc, range, mapvis,
maplight, cloudbase))) {
if (sl & 1)
f |= MECHLOSFLAG_SEESP;
if (sl & 2)
f |= MECHLOSFLAG_SEESS;
}
if (!(f & (MECHLOSFLAG_SEESP | MECHLOSFLAG_SEESS))) {
if (MechTeam(mech) != MechTeam(target))
MechNumSeen(mech) = MAX(0, MechNumSeen(mech) - 1);
f &= ~MECHLOSFLAG_SEEN;
if ((Started(target) || SeeWhenShutdown(target) ||
MechAutoconSD(mech)) &&
(st = valid_to_notice(mech, target, wlf)) && seeanew < 3) {
if (st & AUTOCON_WARN)
strcpy(buf, "%cy");
else
buf[0] = 0;
if (st & AUTOCON_SHORT)
sprintf(buf + strlen(buf), "Lost: %s, %s arc.",
GetMechToMechID_base(mech, target, wlf),
GetArcID(mech, arc));
else
sprintf(buf,
"You have lost %s from your scanners. It was last in your %s arc.",
GetMechToMechID_base(mech, target, wlf),
GetArcID(mech, arc));
if (st & AUTOCON_WARN)
strcat(buf, "%cn");
mech_notify(mech, MECHALL, buf);
}
if ((MechStatus(mech) & LOCK_TARGET) &&
target->mynum == MechTarget(mech)) {
mech_notify(mech, MECHALL,
"Weapon system reports the lock has been lost.");
LoseLock(mech);
}
#ifdef SENSOR_DEBUG
sprintf(buf, "Notice: #%d lost #%d (Sensor: %d, Flag: %s)",
mech->mynum, target->mynum,
(f & (MECHLOSFLAG_SEESP | MECHLOSFLAG_SEESS)),
my_dump_flag(f));
SendSensor(buf);
#endif
MechPNumSeen(mech)++;
}
*fl = f;
return;
}
if ((sc =
Sensor_CanSee(mech, target, &f, arc, range, mapvis, maplight,
cloudbase))) {
if (!seeanew) {
MechPNumSeen(mech)++; /* Whee, something we _could_ see */
*fl = f;
return;
}
if ((sl =
Sensor_SeesNow(mech, target, f, arc, range, mapvis,
maplight))) {
if (sc & 1)
f |= MECHLOSFLAG_SEESP;
if (sc & 2)
f |= MECHLOSFLAG_SEESS;
}
if ((f & (MECHLOSFLAG_SEESP | MECHLOSFLAG_SEESS))) {
if (MechTeam(mech) != MechTeam(target)) {
MechNumSeen(mech)++;
UnZombifyMech(mech);
}
f |= MECHLOSFLAG_SEEN;
*fl = f;
if ((Started(target) || SeeWhenShutdown(target) ||
MechAutoconSD(mech)) &&
(st = valid_to_notice(mech, target, -1)) && seeanew < 2) {
if (st & AUTOCON_WARN)
strcpy(buf, "%cr");
else
buf[0] = 0;
if (st & AUTOCON_SHORT)
sprintf(buf + strlen(buf), "Seen: %s, %s arc.",
GetMechToMechID(mech, target), GetArcID(mech, arc));
else
sprintf(buf + strlen(buf),
"You notice %s in your %s arc.",
GetMechToMechID(mech, target), GetArcID(mech, arc));
if (st & AUTOCON_WARN)
strcat(buf, "%cn");
mech_notify(mech, MECHALL, buf);
}
if (MechTeam(mech) != MechTeam(target))
StopHiding(target);
#ifdef SENSOR_DEBUG
sprintf(buf, "Notice: #%d saw #%d (Sensor: %d, Flag: %s C:%d)",
mech->mynum, target->mynum,
(f & (MECHLOSFLAG_SEESP | MECHLOSFLAG_SEESS)),
my_dump_flag(f), seeanew);
SendSensor(buf);
#endif
} else
MechPNumSeen(mech)++;
}
*fl = f;
}
void update_LOSinfo(dbref obj, MAP * map)
{
int i, j, fl;
int mapvis = map->mapvis;
int maplight = map->maplight;
MECH *mech, *target;
float range;
int wlf;
/* First, for all moved mechs, calculate new LOS flags */
for (i = 0; i < map->first_free; i++) {
mech = getMech(map->mechsOnMap[i]);
if (!mech)
continue;
if (!Started(mech))
continue;
for (j = i + 1; j < map->first_free; j++)
if (map->mechflags[i] || map->mechflags[j]) {
target = getMech(map->mechsOnMap[j]);
if (!target)
continue;
range = FaMechRange(mech, target);
if (ECMEnabled(mech) || ECCMEnabled(mech) ||
AngelECMEnabled(mech) || AngelECCMEnabled(mech))
if (range < ECM_RANGE)
checkECM(target);
if (TAGTarget(mech) > 0)
checkTAG(mech);
if (MechStatus2(mech) & SLITE_ON)
if (range < LITE_RANGE)
cause_lite(mech, target);
if (range > map->maxvis && MechZ(target) < 11 &&
MechZ(mech) < 11) {
map->LOSinfo[i][j] = MECHLOSFLAG_BLOCK;
continue;
}
wlf = !(map->LOSinfo[i][j] & MECHLOSFLAG_BLOCK) &&
((map->LOSinfo[i][j] & MECHLOSFLAG_SEESP) ||
(map->LOSinfo[i][j] & MECHLOSFLAG_SEESS));
map->LOSinfo[i][j] = fl =
CalculateLOSFlag(mech, target, map, MechX(target),
MechY(target), map->LOSinfo[i]
[j], (float) range);
/* Then, we update the SEES* */
#ifdef ADVANCED_LOS
Sensor_DoWeSeeNow(mech, &map->LOSinfo[i][j], range, -1, -1,
target, mapvis, maplight, map->cloudbase, 0, wlf);
#endif
}
}
for (i = 1; i < map->first_free; i++) {
if (map->mechsOnMap[i] > 0);
mech = getMech(map->mechsOnMap[i]);
if (!mech)
continue;
if (!Started(mech))
continue;
for (j = 0; j < i; j++)
if (map->mechflags[i] || map->mechflags[j]) {
target = getMech(map->mechsOnMap[j]);
if (!target)
continue;
range = FaMechRange(mech, target);
if (ECMEnabled(mech) || ECCMEnabled(mech) ||
AngelECMEnabled(mech) || AngelECCMEnabled(mech))
if (range < ECM_RANGE)
checkECM(target);
if (TAGTarget(mech) > 0)
checkTAG(mech);
if (MechStatus2(mech) & SLITE_ON)
if (range < LITE_RANGE)
cause_lite(mech, target);
if (Started(target))
if (map->LOSinfo[j][i] & MECHLOSFLAG_BLOCK) {
wlf = !(map->LOSinfo[i][j] & MECHLOSFLAG_BLOCK) &&
((map->LOSinfo[i][j] & MECHLOSFLAG_SEESP) ||
(map->LOSinfo[i][j] & MECHLOSFLAG_SEESS));
map->LOSinfo[i][j] =
MECHLOSFLAG_BLOCK | (map->LOSinfo[i][j] &
(MECHLOSFLAG_SEEN | MECHLOSFLAG_SEEC2));
#ifdef ADVANCED_LOS
Sensor_DoWeSeeNow(mech, &map->LOSinfo[i][j], range,
-1, -1, target, mapvis, maplight,
map->cloudbase, 0, wlf);
#endif
continue;
}
if (range > map->maxvis && MechZ(target) < 11 &&
MechZ(mech) < 11) {
map->LOSinfo[i][j] = MECHLOSFLAG_BLOCK;
continue;
}
/* Then, we update the SEES* */
wlf = !(map->LOSinfo[i][j] & MECHLOSFLAG_BLOCK) &&
((map->LOSinfo[i][j] & MECHLOSFLAG_SEESP) ||
(map->LOSinfo[i][j] & MECHLOSFLAG_SEESS));
map->LOSinfo[i][j] = fl =
CalculateLOSFlag(mech, target, map, MechX(target),
MechY(target), map->LOSinfo[i]
[j], (float) range);
Sensor_DoWeSeeNow(mech, &map->LOSinfo[i][j], range, -1, -1,
target, mapvis, maplight, map->cloudbase, 0, wlf);
}
}
for (i = 0; i < map->first_free; i++)
map->mechflags[i] = 0;
}
void add_sensor_info(char *buf, MECH * mech, int sn, int verbose)
{
if (!verbose)
sprintf(buf + strlen(buf), "(R:%s)", sensors[sn].range_desc);
else {
sprintf(buf + strlen(buf), "\n\tRange: %s\n\tBlocked by: %s",
sensors[sn].range_desc, sensors[sn].block_desc);
if (sensors[sn].special_desc)
sprintf(buf + strlen(buf), "\n\tNotes: %s",
sensors[sn].special_desc);
}
}
static char *sensor_mode_name(MECH * mech, int sn, int full, int verbose)
{
static char buf[MBUF_SIZE];
if (sn < 0 || sn >= NUM_SENSORS)
return "None";
if (sensors[sn].fullvision) {
sprintf(buf, "%s ", sensors[sn].sensorname);
add_sensor_info(buf, mech, sn, verbose);
} else {
if (full || Sees360(mech))
sprintf(buf, "%s in 360 degree scanning mode ",
sensors[sn].sensorname);
else
sprintf(buf, "%s in 120 degree scanning mode (Forward arc) ",
sensors[sn].sensorname);
add_sensor_info(buf, mech, sn, verbose);
}
return buf;
}
static void sensor_mode(MECH * mech, char *msg, dbref player, int p, int s,
int verbose)
{
char buf[MBUF_SIZE];
int i;
if (p != s) {
for (i = 0; i < strlen(msg); i++)
buf[i] = '-';
buf[strlen(msg)] = 0;
notify(player, msg);
notify(player, buf);
notify(player, tprintf("Primary: %s", sensor_mode_name(mech, p,
0, verbose)));
notify(player, tprintf("Secondary: %s", sensor_mode_name(mech, s,
0, verbose)));
} else
notify(player, tprintf("%s: %s", msg, sensor_mode_name(mech, p, 1,
verbose)));
}
static int tmp_prim;
static int tmp_sec;
static int tmp_found;
static void sensor_check(MUXEVENT * e)
{
int d = ((int) e->data2);
tmp_prim = d / NUM_SENSORS;
tmp_sec = d % NUM_SENSORS;
tmp_found = 1;
}
static char SensorInf[] = "vliesrbVLIESRB";
char *mechSensorInfo(int mode, MECH * mech, char *arg)
{
static char buffer[5];
tmp_found = 0;
buffer[0] = SensorInf[(short) MechSensor(mech)[0]];
buffer[1] = SensorInf[(short) MechSensor(mech)[1]];
if (SensorChange(mech)) {
muxevent_gothru_type_data(EVENT_SCHANGE, (void *) mech, sensor_check);
if (tmp_found) {
buffer[2] = SensorInf[tmp_prim + NUM_SENSORS];
buffer[3] = SensorInf[tmp_sec + NUM_SENSORS];
buffer[4] = '\0';
return buffer;
}
}
buffer[2] = '\0';
return buffer;
}
static void show_sensor(dbref player, MECH * mech, int verbose)
{
tmp_found = 0;
sensor_mode(mech, "Sensors", player, MechSensor(mech)[0],
MechSensor(mech)[1], verbose);
if (SensorChange(mech)) {
muxevent_gothru_type_data(EVENT_SCHANGE, (void *) mech, sensor_check);
if (tmp_found)
sensor_mode(mech, "Wanted", player, tmp_prim, tmp_sec, 0);
}
}
static void mech_sensorchange_event(MUXEVENT * e)
{
int d = (int) e->data2;
MECH *mech = (MECH *) e->data;
int prim = d / NUM_SENSORS;
int sec = d % NUM_SENSORS;
if (!Started(mech))
return;
MechSensor(mech)[0] = prim;
MechSensor(mech)[1] = sec;
mech_notify(mech, MECHALL,
"As your sensors change, your lock clears.");
MechTarget(mech) = -1;
MarkForLOSUpdate(mech);
}
int CanChangeTo(MECH * mech, int s)
{
MAP *map;
int i;
if (!(map = getMap(mech->mapindex))) {
mech_notify(mech, MECHALL, "Where are you? ;-)");
return 0;
}
/* < 0, means you you don't have the sensors if you _do_ have the bit
> 0, means you have the sensors if you have the bit */
if ((i = sensors[s].required_special)) {
/* original specials struct */
if (sensors[s].specials_set == 1) {
if ((i > 0) == ((!(MechSpecials(mech) & abs(i))) != 0)) {
mech_notify(mech, MECHALL,
tprintf("You lack the %s sensors!",
sensors[s].sensorname));
return 0;
}
} else {
if ((i > 0) == ((!(MechSpecials2(mech) & abs(i))) != 0)) {
mech_notify(mech, MECHALL,
tprintf("You lack the %s sensors!",
sensors[s].sensorname));
return 0;
}
}
}
if (sensors[s].min_light >= 0 && sensors[s].min_light > map->maplight) {
if (!Destroyed(mech) && Started(mech))
mech_notify(mech, MECHALL,
tprintf("It's now too dark to use %s!",
sensors[s].sensorname));
return 0;
}
if (sensors[s].max_light >= 0 && sensors[s].max_light < map->maplight) {
if (!Destroyed(mech) && Started(mech))
mech_notify(mech, MECHALL,
tprintf("The light's kinda too bright now to use %s!",
sensors[s].sensorname));
return 0;
}
switch (sensors[s].attributeCheck) {
case SENSOR_ATTR_SEISMIC:
if ((MechType(mech) == CLASS_MW) ||
(MechType(mech) == CLASS_BSUIT) ||
(MechType(mech) == CLASS_VEH_NAVAL) ||
(MechMove(mech) == MOVE_HOVER)) {
mech_notify(mech, MECHALL,
tprintf("You lack the %s sensors!",
sensors[s].sensorname));
return 0;
}
break;
}
return 1;
}
void sensor_light_availability_check(MECH * mech)
{
int p = MechSensor(mech)[0], s = MechSensor(mech)[1];
int same = (p == s);
if (sensors[p].min_light >= 0 || sensors[p].max_light >= 0)
if (!CanChangeTo(mech, p))
MechSensor(mech)[0] = 0;
if (!same && (sensors[s].min_light >= 0 || sensors[s].max_light >= 0))
if (!CanChangeTo(mech, s))
MechSensor(mech)[1] = 0;
}
static int set_sensor(MECH * mech, char ps, char ss)
{
int prim = -1, sec = -1;
int i;
if (!Started(mech))
return 0;
for (i = 0; i < NUM_SENSORS; i++) {
if (sensors[i].matchletter[0] == ps)
prim = i;
if (sensors[i].matchletter[0] == ss)
sec = i;
}
if (prim < 0 || sec < 0)
return -1;
if (prim != MechSensor(mech)[0] || sec != MechSensor(mech)[1]) {
if (!CanChangeTo(mech, prim))
return -1;
if (!CanChangeTo(mech, sec))
return -1;
StopSensorChange(mech);
MECHEVENT(mech, EVENT_SCHANGE, mech_sensorchange_event,
SCHANGE_TICK, ((prim * NUM_SENSORS) + sec));
}
return 0;
}
void mech_sensor(dbref player, void *data, char *buffer)
{
MECH *mech = (MECH *) data;
char *args[3];
int argc;
if (!mech)
return;
#ifdef SIMPLE_SENSORS
notify(player,
"Sensors are unavailable, as regrettable as it may be.");
return;
#endif
DOCHECK(MechType(mech) == CLASS_MW,
"You're using your eyes, and nothing you can do changes that!");
argc = mech_parseattributes(buffer, args, 2);
DOCHECK(argc > 2, "Invalid number of arguments!");
switch (argc) {
case 0:
show_sensor(player, mech, 0);
break;
case 1:
show_sensor(player, mech, 1);
break;
case 2:
DOCHECK(set_sensor(mech, toupper(args[0][0]), toupper(args[1][0]))
< 0, "Invalid arguments!");
show_sensor(player, mech, 0);
break;
}
}
void possibly_see_mech(MECH * mech)
{
MAP *map = getMap(mech->mapindex);
int i, j;
MECH *seer;
int mapvis;
int maplight;
float range;
int num = mech->mapnumber;
if (!map)
return;
mapvis = map->mapvis;
maplight = map->maplight;
/* This is quiet ; no message for noticing foe etc */
/* Basically, this is a 'bonus' effect in addition to the movement-caused
effects, but just done once / move of the guy */
for (i = 0; i < map->first_free; i++)
if (i != num && (j = map->mechsOnMap[i]) >= 0) {
if (!(seer = getMech(j)))
continue;
if (seer->mapindex != map->mynum) {
SendError(tprintf("Mech #%d was on map #%d but with "
"incorrect mapindex (%d)", seer->mynum,
map->mynum, seer->mapindex));
map->mechsOnMap[i] = -1;
continue;
}
range = FaMechRange(seer, mech);
map->LOSinfo[i][num] =
CalculateLOSFlag(seer, mech, map, MechX(mech), MechY(mech),
map->LOSinfo[i][num], (float) range);
/* Then, we update the SEES* */
/* seeanew used to be 2 ; I want them to know they notice
it first not to bug me 'bout it, though */
#ifdef ADVANCED_LOS
Sensor_DoWeSeeNow(seer, &map->LOSinfo[i][num], range, -1, -1,
mech, mapvis, maplight, map->cloudbase, 2, 0);
#endif
}
}
static void mech_unblind_event(MUXEVENT * e)
{
MECH *m = (MECH *) e->data;
MechStatus(m) &= ~BLINDED;
if (!Uncon(m))
mech_notify(m, MECHALL, "Your sight recovers.");
}
void ScrambleInfraAndLiteAmp(MECH * mech, int time, int chance,
char *inframsg, char *liteampmsg)
{
MAP *mech_map = getMap(mech->mapindex);
int i;
MECH *tempMech;
possibly_see_mech(mech);
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),
FaMechRange(tempMech, mech))) {
if (Blinded(tempMech) || Uncon(tempMech))
continue;
if (sensors[(int)
MechSensor(tempMech)[0]].matchletter[0] == 'I'
|| sensors[(int)
MechSensor(tempMech)
[0]].matchletter[1] == 'I') {
if (chance)
if (Number(1, 100) > chance)
continue;
/* Infra effect */
mech_notify(tempMech, MECHALL, inframsg);
} else if (sensors[(int)
MechSensor(tempMech)[0]].matchletter[0]
== 'L' || sensors[(int)
MechSensor(tempMech)
[0]].matchletter[1]
== 'L') {
if (chance)
if (Number(1, 100) > chance)
continue;
/* Liteamp effect */
mech_notify(tempMech, MECHALL, liteampmsg);
} else
continue;
MechStatus(tempMech) |= BLINDED;
MECHEVENT(tempMech, EVENT_BLINDREC, mech_unblind_event,
time, 0);
}
}