/*
* $Id: aero.move.c,v 1.2 2005/08/10 14:09:34 av1-op 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: Mon Jul 20 00:34:50 1998 fingon
*
*/
#define MIN_TAKEOFF_SPEED 3
#include <math.h>
#include "muxevent.h"
#include "mech.h"
#include "mech.events.h"
#include "p.mech.sensor.h"
#include "p.mech.update.h"
#include "p.artillery.h"
#include "p.mech.combat.h"
#include "p.mech.combat.misc.h"
#include "p.mech.utils.h"
#include "p.econ_cmds.h"
#include "p.mech.ecm.h"
#include "p.mech.tag.h"
#include "p.mech.lite.h"
#include "spath.h"
#include "p.mine.h"
struct land_data_type {
int type;
int maxvertup;
int maxvertdown;
int minhoriz;
int maxhoriz;
int launchvert;
int launchtime; /* In secs */
char *landmsg;
char *landmsg_others;
char *takeoff;
char *takeoff_others;
} /* maxvertup / maxvertdown / minhoriz / maxhoriz / launchv /
launchtime */ land_data[] = {
{
CLASS_VTOL, 10, -60, -15, 15, 5, 0,
"You bring your VTOL to a safe landing.", "lands.",
"The rotor whines overhead as you lift off into the sky.",
"takes off!"}, {
CLASS_AERO, 10, -30, MIN_TAKEOFF_SPEED * MP1, 999, 20, 10,
"You land your AeroFighter safely.", "lands safely.",
"The Aerofighter launches into the air!",
"launches into the air!"}, {
CLASS_DS, 10, -25, MIN_TAKEOFF_SPEED * MP1, 999, 20, 300,
"The DropShip lands safely.", "lands safely.",
"The DropShip's nose lurches upward, and it starts climbing to the sky!",
"starts climbing to the sky!"}, {
CLASS_SPHEROID_DS, 15, -40, -40, 40, 20, 300,
"The DropShip touches down safely.",
"touches down, and settles.",
"The DropShip slowly lurches upwards as engines battle the gravity..",
"starts climbing up to the sky!"}
};
#define NUM_LAND_TYPES (sizeof(land_data)/sizeof(struct land_data_type))
static void aero_takeoff_event(MUXEVENT * e)
{
MECH *mech = (MECH *) e->data;
MAP *map = getMap(mech->mapindex);
int i = -1;
int count = (int) e->data2;
if (IsDS(mech))
for (i = 0; i < NUM_LAND_TYPES; i++)
if (MechType(mech) == land_data[i].type)
break;
if (count > 0) {
if (count > 5) {
if (!(count % 10))
mech_notify(mech, MECHALL, tprintf("Launch countdown: %d.",
count));
} else
mech_notify(mech, MECHALL, tprintf("Launch countdown: %d.",
count));
if (i >= 0) {
if (count == (land_data[i].launchtime / 4))
DSSpam_O(mech,
"'s engines start to glow with unbearable intensity..");
switch (count) {
case 10:
DSSpam_O(mech, "'s engines are almost ready to lift off!");
break;
case 6:
DSSpam_O(mech,
"'s engines generate a tremendous heat wave!");
ScrambleInfraAndLiteAmp(mech, 2, 0,
"The blinding flash of light momentarily blinds you!",
"The blinding flash of light momentarily blinds you!");
break;
case 2:
mech_notify(mech, MECHALL,
"The engines pulse out a stream of superheated plasma!");
DSSpam_O(mech,
"'s engines send forth a tremendous stream of superheated plasma!");
ScrambleInfraAndLiteAmp(mech, 4, 0,
"The blinding flash of light blinds you!",
"The blinding flash of light blinds you!");
break;
case 1:
DS_BlastNearbyMechsAndTrees(mech,
"You receive a direct hit!",
"is caught in the middle of the inferno!",
"You are hit by the wave!", "gets hit by the wave!",
"are instantly burned to ash!", 400);
break;
}
}
MECHEVENT(mech, EVENT_TAKEOFF, aero_takeoff_event, 1, (void *)
(count - 1));
return;
}
if (i < 0) {
if (RollingT(mech) && MechSpeed(mech) < (MIN_TAKEOFF_SPEED * MP1)) {
mech_notify(mech, MECHALL,
"You're moving too slowly to lift off!");
return;
}
for (i = 0; i < NUM_LAND_TYPES; i++)
if (MechType(mech) == land_data[i].type)
break;
}
StopSpinning(mech);
mech_notify(mech, MECHALL, land_data[i].takeoff);
MechLOSBroadcast(mech, land_data[i].takeoff_others);
MechStartFX(mech) = 0;
MechStartFY(mech) = 0;
MechStartFZ(mech) = 0;
if (IsDS(mech))
SendDSInfo(tprintf("DS #%d has lifted off at %d %d "
"on map #%d", mech->mynum, MechX(mech), MechY(mech),
map->mynum));
if (MechCritStatus(mech) & HIDDEN) {
mech_notify(mech, MECHALL, "You move too much and break your cover!");
MechLOSBroadcast(mech, "breaks its cover in the brush.");
MechCritStatus(mech) &= ~(HIDDEN);
}
if (MechType(mech) != CLASS_VTOL) {
MechDesiredAngle(mech) = 90;
MechDesiredSpeed(mech) = MechMaxSpeed(mech) * 2 / 3;
} else {
MechSpeed(mech) = 0;
MechDesiredSpeed(mech) = 0;
MechVerticalSpeed(mech) = 60.0;
}
ContinueFlying(mech);
MaybeMove(mech);
}
void aero_takeoff(dbref player, void *data, char *buffer)
{
MECH *mech = (MECH *) data;
MAP *map = getMap(mech->mapindex);
int i, j;
for (i = 0; i < NUM_LAND_TYPES; i++)
if (MechType(mech) == land_data[i].type)
break;
if ((j = atoi(buffer)))
DOCHECK(!WizP(player), "Insufficient access!");
DOCHECK(TakingOff(mech),
"The launch sequence has already been initiated!");
DOCHECK(i == NUM_LAND_TYPES, "This vehicle type cannot takeoff!");
cch(MECH_USUAL);
DOCHECK(!FlyingT(mech),
"Only VTOL, Aerospace fighters and Dropships can take off.");
DOCHECK(!Landed(mech), "You haven't landed!");
if (Fallen(mech) || (MMaxSpeed(mech) <= MP1) ||
(SectIsDestroyed(mech, ROTOR))) {
DOCHECK(MechType(mech) == CLASS_VTOL, "The rotor's dead!");
notify(player, "The engines are dead!");
return;
}
if (!AeroFreeFuel(mech) && AeroFuel(mech) < 1) {
DOCHECK(MechType(mech) == CLASS_VTOL, "Your VTOL's out of fuel!");
notify(player,
"Your craft's out of fuel! No taking off until it's refueled.");
return;
}
DOCHECK(MechType(mech) == CLASS_AERO &&
MechSpeed(mech) < (MIN_TAKEOFF_SPEED * MP1),
"You're moving too slowly to take off!");
DOCHECK(MapIsUnderground(map),
"Realize the ceiling in this grotto is a bit to low for that!");
if (land_data[i].launchtime > 0)
mech_notify(mech, MECHALL,
"Launch sequence initiated.. type 'land' to abort it.");
DSSpam(mech, "starts warming engines for liftoff!");
if (IsDS(mech))
SendDSInfo(tprintf("DS #%d has started takeoff at %d %d on map #%d",
mech->mynum, MechX(mech), MechY(mech), map->mynum));
if (MechCritStatus(mech) & HIDDEN) {
mech_notify(mech, MECHALL, "You break your cover to takeoff!");
MechLOSBroadcast(mech, "breaks its cover as it begins takeoff.");
MechCritStatus(mech) &= ~(HIDDEN);
}
StopHiding(mech);
MECHEVENT(mech, EVENT_TAKEOFF, aero_takeoff_event, 1, (void *)
j ? j : land_data[i].launchtime);
}
#define NUM_NEIGHBORS 7
void DS_BlastNearbyMechsAndTrees(MECH * mech, char *hitmsg, char *hitmsg1,
char *nearhitmsg, char *nearhitmsg1, char *treehitmsg, int damage)
{
MAP *map = getMap(mech->mapindex);
int x = MechX(mech), y = MechY(mech), z = MechZ(mech);
int x1, y1, x2, y2, d;
int rng = (damage > 100 ? 5 : 3);
for (x1 = x - rng; x1 <= (x + rng); x1++)
for (y1 = y - rng; y1 <= (y + rng); y1++) {
x2 = BOUNDED(0, x1, map->map_width - 1);
y2 = BOUNDED(0, y1, map->map_height - 1);
if (x1 != x2 || y1 != y2)
continue;
if ((d = MyHexDist(x, y, x1, y1, 0)) > rng)
continue;
d = MAX(1, d);
switch (GetRTerrain(map, x1, y1)) {
case LIGHT_FOREST:
case HEAVY_FOREST:
if (!find_decorations(map, x1, y1)) {
HexLOSBroadcast(map, x1, y1,
tprintf("%%ch%%crThe trees in $h %s%%cn",
treehitmsg));
if ((damage / d) > 100) {
SetTerrain(map, x1, y1, ROUGH);
} else {
add_decoration(map, x1, y1, TYPE_FIRE, FIRE,
FIRE_DURATION);
}
}
break;
}
}
MechZ(mech) = z + 6;
blast_hit_hexesf(map, damage, 5, damage / 2, MechFX(mech),
MechFY(mech), MechFX(mech), MechFY(mech), hitmsg, hitmsg1,
nearhitmsg, nearhitmsg1, 0, 4, 4, 1, rng);
MechZ(mech) = z;
}
enum {
NO_ERROR, INVALID_TERRAIN, UNEVEN_TERRAIN, BLOCKED_LZ
};
char *reasons[] = {
"Improper terrain",
"Uneven ground",
"Blocked landing zone"
};
static int improper_lz_status;
static int improper_lz_height;
static void ImproperLZ_callback(MAP *map, int x, int y)
{
if (Elevation(map, x, y) != improper_lz_height)
improper_lz_status = 0;
else
improper_lz_status++;
}
#define MechCheckLZ(m) ImproperLZ((m), MechX((m)), MechY((m)))
int ImproperLZ(MECH * mech, int x, int y)
{
MAP * map = getMap(mech->mapindex);
if (GetRTerrain(map, x, y) != GRASSLAND &&
GetRTerrain(map, x, y) != ROAD)
return INVALID_TERRAIN;
improper_lz_status = 0;
improper_lz_height = Elevation(map, x, y);
visit_neighbor_hexes(map, x, y, ImproperLZ_callback);
if (improper_lz_status != 6)
return UNEVEN_TERRAIN;
if (is_blocked_lz(mech, map, x, y))
return BLOCKED_LZ;
return NO_ERROR;
}
void aero_land(dbref player, void *data, char *buffer)
{
MECH *mech = (MECH *) data;
MAP *map = getMap(mech->mapindex);
int i, t;
double horiz = 0.0;
int vert, vertmin = 0, vertmax = 0;
DOCHECK(MechType(mech) != CLASS_VTOL &&
MechType(mech) != CLASS_AERO &&
!IsDS(mech), "You can't land this type of vehicle.");
DOCHECK(MechType(mech) == CLASS_VTOL &&
AeroFuel(mech) <= 0 &&
!AeroFreeFuel(mech), "You lack fuel to maneuver for landing!");
for (i = 0; i < NUM_LAND_TYPES; i++)
if (MechType(mech) == land_data[i].type)
break;
if (i == NUM_LAND_TYPES)
return;
DOCHECK((Fallen(mech)) &&
(MechType(mech) == CLASS_VTOL), "The rotor's dead!");
DOCHECK((Fallen(mech)) &&
(MechType(mech) != CLASS_VTOL), "The engines are dead!");
if (MechStatus(mech) & LANDED) {
if (TakingOff(mech)) {
mech_notify(mech, MECHALL, tprintf("Launch aborted by %s.",
Name(player)));
if (IsDS(mech))
SendDSInfo(tprintf("DS #%d aborted takeoff at %d %d "
"on map #%d", mech->mynum, MechX(mech),
MechY(mech), map->mynum));
StopTakeOff(mech);
return;
}
notify(player, "You're already landed!");
return;
}
DOCHECK(MechZ(mech) > MechElevation(mech) + 1,
"You are too high to land here.");
DOCHECK(((horiz =
my_sqrtm((double) MechDesiredSpeed(mech),
(double) MechVerticalSpeed(mech))) >=
((double) 1.0 + land_data[i].maxhoriz)),
"You're moving too fast to land.");
DOCHECK(horiz < land_data[i].minhoriz,
"You're moving too slowly to land.");
DOCHECK(((vert = MechVerticalSpeed(mech)) > (vertmax =
land_data[i].maxvertup)) ||
(MechVerticalSpeed(mech) < (vertmin =
land_data[i].maxvertdown)),
"You are moving too fast to land. ");
if (MechSpeed(mech) < land_data[i].minhoriz) {
if (MechStartFZ(mech) <= 0)
notify(player,
"You're falling, not landing! Pick up some horizontal speed first.");
else
notify(player, "You're climbing not landing!");
return;
}
t = MechRTerrain(mech);
DOCHECK(!(t == GRASSLAND || t == ROAD || (MechType(mech) == CLASS_VTOL
&& t == BUILDING)),
"You can't land on this type of terrain.");
if (MechType(mech) != CLASS_VTOL && MechCheckLZ(mech)) {
mech_notify(mech, MECHALL,
"This location is no good for landing!");
return;
}
if (IsDS(mech))
SendDSInfo(tprintf("DS #%d has landed at %d %d on map #%d",
mech->mynum, MechX(mech), MechY(mech), map->mynum));
mech_notify(mech, MECHALL, land_data[i].landmsg);
MechLOSBroadcast(mech, land_data[i].landmsg_others);
MechZ(mech) = MechElevation(mech);
MechFZ(mech) = ZSCALE * MechZ(mech);
MechStatus(mech) |= LANDED;
MechSpeed(mech) = 0.0;
MechVerticalSpeed(mech) = 0.0;
MechStartFX(mech) = 0.0;
MechStartFY(mech) = 0.0;
MechStartFZ(mech) = 0.0;
possible_mine_poof(mech, MINE_LAND);
}
void aero_ControlEffect(MECH * mech)
{
if (Spinning(mech))
return;
if (Destroyed(mech))
return;
if (Landed(mech))
return;
mech_notify(mech, MECHALL, "You lose control of your craft!");
MechLOSBroadcast(mech, "spins out of control!");
StartSpinning(mech);
MechStartSpin(mech) = mudstate.now;
}
void ds_BridgeHit(MECH * mech)
{
/* Implementation: Kill all players on bridge :-) */
if (Destroyed(mech))
return;
if (In_Character(mech->mynum))
mech_notify(mech, MECHALL,
"SHIT! The shot seems to be coming straight for the bridge!");
KillMechContentsIfIC(mech->mynum);
}
#define degsin(a) ((double) sin((double) (a) * M_PI / 180.0))
#define degcos(a) ((double) cos((double) (a) * M_PI / 180.0))
void aero_UpdateHeading(MECH * mech)
{
/* Heading things are done in speed now, odd as though it might
seem */
if (SpheroidDS(mech))
UpdateHeading(mech);
}
double length_hypotenuse(double x, double y)
{
if (x < 0)
x = -x;
if (y < 0)
y = -y;
return sqrt(x * x + y * y);
}
double my_sqrtm(double x, double y)
{
double d;
if (x < 0)
x = -x;
if (y < 0)
y = -y;
if (y > x) {
d = y;
y = x;
x = d;
}
return sqrt(x * x - y * y);
}
#define AERO_BONUS 3
void aero_UpdateSpeed(MECH * mech)
{
float xypart;
float wx, wy, wz;
float nx, ny, nz;
float nh;
float dx, dy, dz;
float vlen, mod;
float sp;
float ab = 0.7;
float m = 1.0;
if (Spinning(mech)) {
MechDesiredSpeed(mech) =
BOUNDED(0, MechDesiredSpeed(mech) + Number(1, 10),
MMaxSpeed(mech));
MechDesiredAngle(mech) =
MAX(-90, MechDesiredAngle(mech) - Number(1, 15));
MechDesiredFacing(mech) =
AcceptableDegree(MechDesiredFacing(mech) + Number(-3, 3));
}
wz = MechDesiredSpeed(mech) * degsin(MechDesiredAngle(mech));
if (MechType(mech) == CLASS_AERO)
ab = 2.5;
if (MechZ(mech) < ATMO_Z)
ab = ab / 2;
/* First, we calculate the vector we want to be going */
xypart = MechDesiredSpeed(mech) * degcos(MechDesiredAngle(mech));
if (AeroFuel(mech) < 0) {
wz = wz / 5.0;
xypart = xypart / 5.0;
}
if (xypart < 0)
xypart = 0 - xypart;
m = ACCEL_MOD;
FindComponents(m * xypart, MechDesiredFacing(mech), &wx, &wy);
wz = wz * m;
/* Then, we calculate the present heading / speed */
nx = MechStartFX(mech);
ny = MechStartFY(mech);
nz = MechStartFZ(mech);
/* Ok, we've present heading / speed */
/* Next, we make vector from n[xyz] -> w[xyz] */
dx = wx - nx;
dy = wy - ny;
dz = wz - nz;
vlen = length_hypotenuse(length_hypotenuse(dx, dy), dz);
if (!(vlen > 0.0))
return;
if (vlen > (m * ab * MMaxSpeed(mech) / AERO_SECS_THRUST)) {
mod = (float) ab *m * MMaxSpeed(mech) / AERO_SECS_THRUST / vlen;
dx *= mod;
dy *= mod;
dz *= mod;
/* Ok.. we've a new modified speed vector */
}
nx += dx;
ny += dy;
nz += dz;
/* Then, we need to calculate present heading / speed / verticalspeed */
nh = (float) atan2(ny, nx) / TWOPIOVER360;
if (!SpheroidDS(mech))
SetFacing(mech, AcceptableDegree((int) nh + 90));
xypart = length_hypotenuse(nx, ny);
MechSpeed(mech) = xypart;
sp = length_hypotenuse(length_hypotenuse(nx, ny), nz); /* Whole speed */
MechVerticalSpeed(mech) = nz;
if (!SpheroidDS(mech) && fabs(MechSpeed(mech)) < MP1)
SetFacing(mech, MechDesiredFacing(mech));
MechStartFX(mech) = nx;
MechStartFY(mech) = ny;
MechStartFZ(mech) = nz;
}
int FuelCheck(MECH * mech)
{
int fuelcost = 1;
/* We don't do anything particularly nasty to shutdown things */
if (!Started(mech))
return 0;
if (AeroFreeFuel(mech))
return 0;
if (fabs(MechSpeed(mech)) > MMaxSpeed(mech)) {
if (MechZ(mech) < ATMO_Z)
fuelcost = abs(MechSpeed(mech) / MMaxSpeed(mech));
} else if (fabs(MechSpeed(mech)) < MP1 &&
fabs(MechVerticalSpeed(mech)) < MP2)
if (Number(0, 1) == 0)
return 0; /* Approximately half of the time free */
if (AeroFuel(mech) > 0) {
if (AeroFuel(mech) <= fuelcost)
AeroFuel(mech) = 0;
else
AeroFuel(mech) -= fuelcost;
return 0;
}
/* DropShips do not need crash ; they switch to (VERY SLOW) secondary
power source. */
if (IsDS(mech)) {
if (AeroFuel(mech) < 0)
return 0;
AeroFuel(mech)--;
mech_notify(mech, MECHALL,
"As the fuel runs out, the engines switch to backup power.");
return 0;
}
if (AeroFuel(mech) < 0)
return 1;
/* Now, the true nastiness begins ;) */
AeroFuel(mech)--;
if (!(AeroFuel(mech) % 100) && AeroFuel(mech) >= AeroFuelOrig(mech))
SetCargoWeight(mech);
if (MechType(mech) == CLASS_VTOL) {
MechLOSBroadcast(mech, "'s rotors suddenly stop!");
mech_notify(mech, MECHALL, "The sound of rotors slowly stops..");
} else {
MechLOSBroadcast(mech, "'s engines die suddenly..");
mech_notify(mech, MECHALL, "Your engines die suddenly..");
}
MechSpeed(mech) = 0.0;
MechDesiredSpeed(mech) = 0.0;
if (!Landed(mech)) {
mech_notify(mech, MECHALL,
"You ponder F = ma, S = F/m, S = at^2 => S=agt^2 in relation to the ground..");
/* Start free-fall */
MechVerticalSpeed(mech) = 0;
/* Hmm. This _can_ be ugly if things crash in middle of fall. Oh well. */
mech_notify(mech, MECHALL,
"You start free-fall.. Enjoy the ride!");
MECHEVENT(mech, EVENT_FALL, mech_fall_event, FALL_TICK, -1);
}
return 1;
}
void aero_update(MECH * mech)
{
if (Destroyed(mech))
return;
if (Started(mech) || Uncon(mech)) {
UpdatePilotSkillRolls(mech);
}
if (Started(mech) || MechPlusHeat(mech) > 0.)
UpdateHeat(mech);
if (!(mudstate.now / 3 % 5)) {
if (!Spinning(mech))
return;
if (Destroyed(mech))
return;
if (Landed(mech))
return;
if (MadePilotSkillRoll(mech,
(MechStartSpin(mech) - mudstate.now) / 15 + 8)) {
mech_notify(mech, MECHALL,
"You recover control of your craft.");
StopSpinning(mech);
}
}
if (Started(mech))
MechVisMod(mech) =
BOUNDED(0, MechVisMod(mech) + Number(-40, 40), 100);
checkECM(mech);
checkTAG(mech);
end_lite_check(mech);
}
void aero_thrust(dbref player, void *data, char *arg)
{
MECH *mech = (MECH *) data;
char *args[1];
float newspeed, maxspeed;
DOCHECK(Landed(mech), "You're landed!");
DOCHECK(is_aero(mech) && Spinning(mech) &&
!Landed(mech),
"You are unable to control your craft at the moment.");
if (mech_parseattributes(arg, args, 1) != 1) {
notify(player, tprintf("Your current thrust is %.2f.",
MechDesiredSpeed(mech)));
return;
}
newspeed = atof(args[0]);
if (RollingT(mech))
DOCHECK(newspeed < (MP1 * MIN_TAKEOFF_SPEED / ACCEL_MOD),
tprintf("Minimum thrust you stay in air with is %.1f kph.",
(float) MP1 * MIN_TAKEOFF_SPEED / ACCEL_MOD));
maxspeed = MMaxSpeed(mech);
if (!(maxspeed > 0.0))
maxspeed = 0.0;
DOCHECK(Fallen(mech), "Your engine's dead, no way to thrust!");
DOCHECK(newspeed < 0,
"Doh, thrust backwards.. where's your sense of adventure?");
if (newspeed > maxspeed) {
notify(player, tprintf("Maximum thrust: %.2f (%.2f kb/sec2)",
maxspeed, maxspeed / 10));
return;
}
MechDesiredSpeed(mech) = newspeed;
mech_notify(mech, MECHALL, tprintf("Thrust set to %.2f.", newspeed));
MaybeMove(mech);
}
void aero_vheading(dbref player, void *data, char *arg, int flag)
{
char *args[1];
int i = 0;
MECH *mech = (MECH *) data;
if (mech_parseattributes(arg, args, 1) != 1) {
notify(player, tprintf("Present angle: %d degrees.",
MechDesiredAngle(mech)));
return;
}
i = flag * atoi(args[0]);
if (abs(i) > 90)
i = 90 * flag;
DOCHECK(abs(i) != 90 && MechZ(mech) < ATMO_Z &&
SpheroidDS(mech), tprintf("You can go only up / down at <%d z!",
ATMO_Z));
if (i >= 0)
mech_notify(mech, MECHALL,
tprintf("Climbing angle set to %d degrees.", i));
else
mech_notify(mech, MECHALL,
tprintf("Diving angle set to %d degrees.", 0 - i));
MechDesiredAngle(mech) = i;
}
void aero_climb(dbref player, MECH * mech, char *arg)
{
aero_vheading(player, mech, arg, 1);
}
void aero_dive(dbref player, MECH * mech, char *arg)
{
aero_vheading(player, mech, arg, -1);
}
static char *colorstr(int serious)
{
if (serious == 1)
return "%ch%cr";
if (serious == 0)
return "%ch%cy";
return "";
}
void DS_LandWarning(MECH * mech, int serious)
{
int ilz = MechCheckLZ(mech);
if (!ilz)
return;
ilz--;
mech_notify(mech, MECHALL, tprintf("%sWARNING: %s - %s%%cn",
colorstr(serious), reasons[ilz],
serious == 1 ? "CLIMB UP NOW!!!" : serious ==
0 ? "No further descent is advisable." :
"Please do not even consider landing here."));
}
void aero_checklz(dbref player, MECH * mech, char *buffer)
{
int ilz, argc;
char *args[3];
int x, y;
cch(MECH_USUAL);
argc = mech_parseattributes(buffer, args, 3);
switch(argc) {
case 2:
x = atoi(args[0]);
y = atoi(args[1]);
if (!MechIsObservator(mech)) {
float fx, fy;
MapCoordToRealCoord(x, y, &fx, &fy);
DOCHECK(FindHexRange(MechFX(mech), MechFY(mech), fx, fy) >
MechTacRange(mech), "Out of range!");
}
break;
case 0:
x = MechX(mech);
y = MechY(mech);
break;
default:
notify(player, "Invalid number of parameters!");
return;
}
ilz = ImproperLZ(mech, x, y);
DOCHECKMA(!ilz,
tprintf("The hex (%d,%d) looks good enough for a landing.",
x, y));
ilz--;
mech_notify(mech, MECHALL,
tprintf("The hex (%d,%d) doesn't look good for landing: %s.",
x, y, reasons[ilz]));
}