/*
* $Id: mech.update.c,v 1.4 2005/08/10 14:09:34 av1-op Exp $
*
* Author: Markus Stenberg <fingon@iki.fi>
*
* Copyright (c) 1997 Markus Stenberg
* Copyright (c) 1998-2002 Thomas Wouters
* Copyright (c) 2000-2002 Cord Awtry
* Copyright (c) 1999-2005 Kevin Stevens
* All rights reserved
*
* Last modified: Tue Jul 21 00:16:07 1998 fingon
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sys/file.h>
#include "mech.h"
#include "failures.h"
#include "mech.events.h"
#include "mech.ice.h"
#include "p.mech.ecm.h"
#include "p.mech.tag.h"
#include "p.mech.combat.h"
#include "p.mech.combat.misc.h"
#include "p.mech.damage.h"
#include "p.mech.fire.h"
#include "p.mech.startup.h"
#include "p.mech.utils.h"
#include "p.mech.update.h"
#include "p.btechstats.h"
#include "p.mech.physical.h"
#include "p.bsuit.h"
#include "p.mine.h"
#include "p.mech.lite.h"
#include "p.mech.pickup.h"
extern int arc_override;
int fiery_death(MECH * mech)
{
if (MechTerrain(mech) == FIRE) {
if (is_aero(mech))
return 0;
if (MechMove(mech) == MOVE_VTOL)
return 0;
if (Destroyed(mech))
return 0;
/* Cause various things */
/* MWs _die_ */
if (MechType(mech) == CLASS_MW) {
mech_notify(mech, MECHALL, "You feel tad bit too warm..");
mech_notify(mech, MECHALL, "You faint.");
DestroyMech(mech, mech, 0);
return 1;
}
/* Tanks may die */
return 0; /* Dumb idea */
heat_effect(NULL, mech, 0, 0);
if (Destroyed(mech))
return 1;
}
return 0;
}
int bridge_w_elevation(MECH * mech)
{
return -1;
}
void bridge_set_elevation(MECH * mech)
{
if (MechZ(mech) < (MechUpperElevation(mech) - MoveMod(mech))) {
if (Overwater(mech))
MechZ(mech) = 0;
else
MechZ(mech) = bridge_w_elevation(mech);
return;
}
MechZ(mech) = MechUpperElevation(mech);
}
int DSOkToNotify(MECH * mech)
{
if (DSLastMsg(mech) > muxevent_tick ||
(muxevent_tick - DSLastMsg(mech)) >= DS_SPAM_TIME) {
DSLastMsg(mech) = muxevent_tick;
return 1;
}
return 0;
}
enum {
JUMP, WALK_WALL, WALK_DROP, HIT_UNDER_BRIDGE, WALK_BACK
};
int collision_check(MECH * mech, int mode, int le, int lt)
{
int e;
MAP *mech_map = getMap(mech->mapindex);
if (Overwater(mech) && le < 0)
le = 0;
e = MechElevation(mech);
if (MechRTerrain(mech) == ICE)
if (le >= 0)
e = 0;
if (le < (MechUpperElevation(mech) - MoveMod(mech)) && lt == BRIDGE) {
if (Overwater(mech))
le = 0;
else
le = bridge_w_elevation(mech);
}
if (e < 0 && Overwater(mech))
e = 0;
switch (mode) {
case JUMP:
if (MechRTerrain(mech) == BRIDGE) {
if (MechZ(mech) < 0)
return 1;
if (MechZ(mech) == (e - 1))
return 1;
return 0;
} else
return (MechZ(mech) < e);
case WALK_DROP:
return (le - e) > MoveMod(mech);
case WALK_WALL:
if ((MechMove(mech) == MOVE_HOVER) &&
(MechRTerrain(mech) == BRIDGE) && (((lt == ICE) ||
(lt == WATER)) || ((le == 0) && (lt == BRIDGE)))) {
return 0;
} else {
return (e - le) > MoveMod(mech);
}
case WALK_BACK:
if (MechMove(mech) != MOVE_TRACK && MechType(mech) != CLASS_VTOL)
return (MechSpeed(mech) < 0 ? abs((le - e)) : 0);
case HIT_UNDER_BRIDGE: /* Hovers only... tho it should be fixed for foils and hulls too */
if ((lt == BRIDGE) && (MechRTerrain(mech) == BRIDGE) && (le == 0)
&& (Elevation(mech_map, MechLastX(mech), MechLastY(mech)) != 0)
&& (Elevation(mech_map, MechX(mech), MechY(mech)) == 1))
return 1;
else
return 0;
}
return 0;
}
void CheckNavalHeight(MECH * mech, int oz);
void move_mech(MECH * mech)
{
float newx = 0.0, newy = 0.0, dax, day;
float xy_charge_dist, xscale;
float jump_pos;
#ifdef ODDJUMP
float rjump_pos, midmod;
#endif
int x, y, upd_z = 0;
int last_z = 0;
MECH *target;
MAP *mech_map;
int oi, oz;
int iced = 0;
/* Buffer for printing messages so we don't use the tprintf
* function anymore */
char message_buffer[MBUF_SIZE];
oz = MechZ(mech);
mech_map = getMap(mech->mapindex);
if (!mech_map && MechPilot(mech) >= 0)
mech_map = ValidMap(MechPilot(mech), mech->mapindex);
/* Unit is not on a map so don't need to move it - instead
* reset its values and shut it down */
if (!mech_map) {
mech_notify(mech, MECHALL,
"You are on an invalid map! Map index reset!");
MechCocoon(mech) = 0;
if (Jumping(mech))
mech_land(MechPilot(mech), (void *) mech, "");
mech_shutdown(MechPilot(mech), (void *) mech, "");
snprintf(message_buffer, MBUF_SIZE, "move_mech:invalid map:Mech: %d Index: %d",
mech->mynum, mech->mapindex);
SendError(message_buffer);
mech->mapindex = -1;
return;
}
/* Is the unit on a valid spot on the map */
if (MechX(mech) < 0 || MechX(mech) >= mech_map->map_width ||
MechLastX(mech) < 0 || MechLastX(mech) >= mech_map->map_width ||
MechY(mech) < 0 || MechY(mech) >= mech_map->map_height ||
MechLastY(mech) < 0 || MechLastY(mech) >= mech_map->map_height) {
mech_notify(mech, MECHALL,
"You are at an invalid map location! Map index reset!");
MechCocoon(mech) = 0;
if (Jumping(mech))
mech_land(MechPilot(mech), (void *) mech, "");
mech_shutdown(MechPilot(mech), (void *) mech, "");
snprintf(message_buffer, MBUF_SIZE, "move_mech:invalid map:Mech: %d Index: %d",
mech->mynum, mech->mapindex);
SendError(message_buffer);
mech->mapindex = -1;
return;
}
/* Is the unit charging - and if so have they been charging to long */
if (mudconf.btech_newcharge && MechChargeTarget(mech) > 0) {
if (MechChargeTimer(mech)++ > CHARGE_TIMER_LIMIT) {
mech_notify(mech, MECHALL, "Charge timed out, charge reset.");
MechChargeTarget(mech) = -1;
MechChargeTimer(mech) = 0;
MechChargeDistance(mech) = 0;
}
}
/*! \todo {now that I think about it maybe make a single block
* of code to check for jumping BEFORE anything else.} */
/* Check the move type of the unit */
switch (MechMove(mech)) {
case MOVE_BIPED:
case MOVE_QUAD:
/* Biped/Quad Jumping */
if (Jumping(mech)) {
MarkForLOSUpdate(mech);
FindComponents(JumpSpeed(mech, mech_map) * MOVE_MOD * MAPMOVEMOD(mech_map),
MechJumpHeading(mech), &newx, &newy);
MechFX(mech) += newx;
MechFY(mech) += newy;
jump_pos = length_hypotenuse((MechFX(mech) - MechStartFX(mech)),
(MechFY(mech) - MechStartFY(mech)));
/*! \todo {Not sure what ODDJUMP is but need to figure it out, possibly
* make this a mudconf parameter} */
#ifndef ODDJUMP
MechFZ(mech) = ((4 * JumpSpeedMP(mech, mech_map) * ZSCALE)
/ (MechJumpLength(mech) * MechJumpLength(mech))) *
jump_pos * (MechJumpLength(mech) - jump_pos) +
MechStartFZ(mech) + jump_pos * (MechEndFZ(mech)
- MechStartFZ(mech)) / (MechJumpLength(mech) * HEXLEVEL);
#else
rjump_pos = MechJumpLength(mech) - jump_pos;
if (rjump_pos < 0.0)
rjump_pos = 0.0;
/* New flight path: Make a direct line from the origin to
destination, and imagine a 1-x^4 in relation to the 0 as
the line. y=1 = JumpTop offset, x=0 = middle of path,
x=-1 = beginning, x=1 = end */
midmod = jump_pos / MechJumpLength(mech);
midmod = (midmod - 0.5) * 2;
if (MechJumpTop(mech) >= (1 + JumpSpeedMP(mech, mech_map))) {
midmod = (1.0 - (midmod * midmod)) * MechJumpTop(mech);
} else {
midmod = (1.0 - (midmod * midmod * midmod * midmod)) *
MechJumpTop(mech);
}
MechFZ(mech) = (rjump_pos * MechStartFZ(mech) +
jump_pos * MechEndFZ(mech)) / MechJumpLength(mech) +
midmod * ZSCALE;
#endif
MechZ(mech) = (int) (MechFZ(mech) / ZSCALE + 0.5);
#ifdef JUMPDEBUG
snprintf(message_buffer, MBUF_SIZE,
"#%d: %d, %d, %d (%d, %d, %d)",
mech->mynum, MechX(mech), MechY(mech), MechZ(mech),
(int) MechFX(mech), (int) MechFY(mech),
(int) MechFZ(mech));
SendDebug(message_buffer);
#endif
/* The famous jumping on bridge collision code */
/*! \todo {possibly turn the bridge collision code into
* a mudconf parameter} */
if (MechRTerrain(mech) == BRIDGE &&
collision_check(mech, JUMP, 0, 0) && MechZ(mech) > 0) {
mech_notify(mech, MECHALL,
"CRASH!! You crash at the bridge!");
MechLOSBroadcast(mech, "crashes into the bridge!");
MechFalls(mech, 1, 0);
return;
}
/* Is the jumping unit in its target hex */
if ((MechX(mech) == MechGoingX(mech)) &&
(MechY(mech) == MechGoingY(mech))) {
/*Ok.. in the hex. but no instant landings anymore, laddie */
/*Range to point of origin is larger than whole jump's length */
MapCoordToRealCoord(MechX(mech), MechY(mech), &dax, &day);
/*! \todo {Another instance of that crazy ODDJUMP stuff} */
/* Basicly checking to see if the unit is in the hex,
* the ODDJUMP code looks for the exact center */
#ifdef ODDJUMP
if (length_hypotenuse(dax - MechStartFX(mech),
day - MechStartFY(mech)) <=
length_hypotenuse(MechFX(mech) - MechStartFX(mech),
MechFY(mech) - MechStartFY(mech))) {
LandMech(mech);
MechFX(mech) = (float) dax;
MechFY(mech) = (float) day;
}
#else
LandMech(mech);
MechFX(mech) = (float) dax;
MechFY(mech) = (float) day;
#endif
}
/* Are we landing on ice */
if (MechRTerrain(mech) == ICE) {
if (oz < -1 && MechZ(mech) >= -1)
break_thru_ice(mech);
else if (oz >= -1 && MechZ(mech) < -1)
drop_thru_ice(mech);
}
} else if (fabs(MechSpeed(mech)) > 0.0) {
/* Ok not jumping but we're moving */
FindComponents(MechSpeed(mech) * MOVE_MOD *
MAPMOVEMOD(mech_map), MechLateral(mech) + MechFacing(mech),
&newx, &newy);
MechFX(mech) += newx;
MechFY(mech) += newy;
upd_z = 1;
/* If we're charging record distance traveled */
if (MechChargeTarget(mech) > 0 && mudconf.btech_newcharge) {
xscale = 1.0 / SCALEMAP;
xscale = xscale * xscale;
xy_charge_dist = sqrt(xscale * newx * newx + YSCALE2 * newy * newy);
MechChargeDistance(mech) += xy_charge_dist;
}
} else {
/* Ok not moving or jumping so don't need to calc a new x,y,z */
return;
}
break;
case MOVE_TRACK:
case MOVE_WHEEL:
/*! \todo {Put the tank JJ code here - for tracked/wheeled} */
/* Is the tank moving? */
if (fabs(MechSpeed(mech)) > 0.0) {
/*! \todo {Possibly put in a mudconf parameter for this since
* I think the LATERAL command could check for it} */
#ifndef BT_MOVEMENT_MODES
FindComponents(MechSpeed(mech) * MOVE_MOD *
MAPMOVEMOD(mech_map), MechFacing(mech), &newx, &newy);
#else
FindComponents(MechSpeed(mech) * MOVE_MOD *
MAPMOVEMOD(mech_map), MechLateral(mech) + MechFacing(mech),
&newx, &newy);
#endif
MechFX(mech) += newx;
MechFY(mech) += newy;
upd_z = 1;
/* If we're charging record the distance traveled */
if (MechChargeTarget(mech) > 0 && mudconf.btech_newcharge) {
xscale = 1.0 / SCALEMAP;
xscale = xscale * xscale;
xy_charge_dist = sqrt(xscale * newx * newx + YSCALE2 * newy * newy);
MechChargeDistance(mech) += xy_charge_dist;
}
} else {
/* Ok not moving or jumping so don't need to calc a new x,y,z */
return;
}
break;
case MOVE_HOVER:
/* If we're moving update position */
if (fabs(MechSpeed(mech)) > 0.0) {
/*! \todo {Check the todo before this one, mudconf parameter maybe?} */
#ifndef BT_MOVEMENT_MODES
FindComponents(MechSpeed(mech) * MOVE_MOD *
MAPMOVEMOD(mech_map), MechFacing(mech), &newx, &newy);
#else
FindComponents(MechSpeed(mech) * MOVE_MOD *
MAPMOVEMOD(mech_map), MechLateral(mech) + MechFacing(mech),
&newx, &newy);
#endif
MechFX(mech) += newx;
MechFY(mech) += newy;
upd_z = 1;
/* Record the charge distance */
if (MechChargeTarget(mech) > 0 && mudconf.btech_newcharge) {
xscale = 1.0 / SCALEMAP;
xscale = xscale * xscale;
xy_charge_dist = sqrt(xscale * newx * newx + YSCALE2 * newy * newy);
MechChargeDistance(mech) += xy_charge_dist;
}
} else {
/* Ok not moving or jumping so don't need to calc a new x,y,z */
return;
}
break;
case MOVE_VTOL:
/* If we're landed we're not moving */
if (Landed(mech))
return;
/* Use the same code as subs below */
/*! \todo {VTOLS not able to lateral, nor can subs right now} */
case MOVE_SUB:
MarkForLOSUpdate(mech);
FindComponents(MechSpeed(mech) * MOVE_MOD * MAPMOVEMOD(mech_map),
MechFacing(mech), &newx, &newy);
MechFX(mech) += newx;
MechFY(mech) += newy;
MechFZ(mech) += MechVerticalSpeed(mech) * MOVE_MOD;
MechZ(mech) = MechFZ(mech) / ZSCALE;
break;
case MOVE_FLY:
/* Ok we're in the air */
if (!Landed(mech)) {
MarkForLOSUpdate(mech);
MechFX(mech) += MechStartFX(mech) * MOVE_MOD;
MechFY(mech) += MechStartFY(mech) * MOVE_MOD;
MechFZ(mech) += MechStartFZ(mech) * MOVE_MOD;
MechZ(mech) = MechFZ(mech) / ZSCALE;
/*! \todo {Need to rewrite this for aerodyne DSes unless they're
* set as large aeros which i'm not sure but either way its
* probably not good} */
if (IsDS(mech)) {
/* Fun messages to emit to the pilot */
if (MechZ(mech) < 10 && oz >= 10)
DS_LandWarning(mech, 1);
else if (MechZ(mech) < 50 && oz >= 50)
DS_LandWarning(mech, 0);
else if (MechZ(mech) < 100 && oz >= 100) {
if (abs(MechDesiredAngle(mech)) != 90) {
if (DSOkToNotify(mech)) {
mech_notify(mech, MECHALL, "As the craft enters "
"the lower atmosphere, it's nose rises up "
"for a clean landing..");
snprintf(message_buffer, MBUF_SIZE,
"starts descending towards %d, %d..",
MechX(mech), MechY(mech));
MechLOSBroadcast(mech, message_buffer);
} else {
mech_notify(mech, MECHALL, "Due to low altitude, "
"climbing angle set to 90 degrees.");
}
MechDesiredAngle(mech) = 90;
}
MechStartFX(mech) = 0.0;
MechStartFY(mech) = 0.0;
DS_LandWarning(mech, -1);
}
}
} else {
/* Ok we're rolling around on the ground */
if (!(fabs(MechSpeed(mech)) > 0.0))
return;
FindComponents(MechSpeed(mech) * MOVE_MOD *
MAPMOVEMOD(mech_map), MechFacing(mech), &newx, &newy);
MechFX(mech) += newx;
MechFY(mech) += newy;
upd_z = 1;
}
break;
case MOVE_HULL:
case MOVE_FOIL:
if (fabs(MechSpeed(mech)) > 0.0) {
FindComponents(MechSpeed(mech) * MOVE_MOD *
MAPMOVEMOD(mech_map), MechFacing(mech), &newx, &newy);
MechFX(mech) += newx;
MechFY(mech) += newy;
MechZ(mech) = 0;
MechFZ(mech) = 0.0;
} else {
/* Not moving so no need to update x,y,z and other stuff */
return;
}
break;
}
/* We've already updated the floating x,y values, now to update the hex
* x,y values + both the Z values */
MechLastX(mech) = MechX(mech);
MechLastY(mech) = MechY(mech);
last_z = MechZ(mech);
RealCoordToMapCoord(&MechX(mech), &MechY(mech), MechFX(mech),
MechFY(mech));
/*! \todo {Its the ODDJUMP guy again, whats it for?} */
/* Checking to make sure we didn't jump PAST our target hex */
#ifdef ODDJUMP
if (Jumping(mech) && MechLastX(mech) == MechGoingX(mech) &&
MechLastY(mech) == MechGoingY(mech) &&
(MechX(mech) != MechLastX(mech) ||
MechY(mech) != MechLastY(mech))) {
LandMech(mech);
MechFX(mech) -= newx;
MechFY(mech) -= newy;
MechFZ(mech) = MechEndFZ(mech);
MechX(mech) = MechGoingX(mech);
MechY(mech) = MechGoingY(mech);
MapCoordToRealCoord(MechX(mech), MechY(mech), &MechFX(mech),
&MechFY(mech));
MechZ(mech) = MechFZ(mech) / ZSCALE;
}
#endif
/* Store the current map index */
oi = mech->mapindex;
/* Did we hit mapedge? */
CheckEdgeOfMap(mech);
/* Did our mapindex change? - like did we run out a hangar? */
if (mech->mapindex != oi)
mech_map = getMap(mech->mapindex);
/* We left a hangar and/or moved to a new hex */
if (oi != mech->mapindex || MechLastX(mech) != MechX(mech) ||
MechLastY(mech) != MechY(mech)) {
/* Either the mech or the map is bad */
if (!mech || !mech_map) {
snprintf(message_buffer, MBUF_SIZE,
"Invalide pointer (%s) in move_mech()",
(!mech ? "mech" : !mech_map ? "mech_map" : "weird...."));
SendError(message_buffer);
if (mech) {
/* Bad Map */
mech_notify(mech, MECHALL, "You are on an invalid map! Map index reset!");
MechCocoon(mech) = 0;
if (Jumping(mech))
mech_land(MechPilot(mech), (void *) mech, "");
mech_shutdown(MechPilot(mech), (void *) mech, "");
snprintf(message_buffer, MBUF_SIZE,
"move_mech:invalid map:Mech: %d Index: %d",
mech->mynum, mech->mapindex);
SendError(message_buffer);
mech->mapindex = -1;
}
return;
}
/* We've moved from our hex so break our cover */
if (MechCritStatus(mech) & HIDDEN) {
mech_notify(mech, MECHALL, "You move too much and break your cover!");
MechLOSBroadcast(mech, "breaks from its cover.");
MechCritStatus(mech) &= ~(HIDDEN);
}
StopHiding(mech);
x = MechX(mech);
y = MechY(mech);
MechTerrain(mech) = GetTerrain(mech_map, x, y);
MechElev(mech) = GetElev(mech_map, x, y);
/* Update our Z values */
if (upd_z) {
/* Chance of breaking through ICE */
if (MechRTerrain(mech) == ICE) {
if (oz < -1 && MechZ(mech) >= -1)
break_thru_ice(mech);
else if (MechZ(mech) == 0)
if (possibly_drop_thru_ice(mech))
iced = 1;
}
/* Check for bridges and basic elevation changes */
DropSetElevation(mech, 0);
/* To fix certain slide-under-ice-effect for _mechs_ */
if (MechType(mech) == CLASS_MECH && MechRTerrain(mech) == ICE
&& oz == -1 && MechZ(mech) == -1) {
MechZ(mech) = 0;
MechFZ(mech) = MechZ(mech) * ZSCALE;
}
}
if (!iced)
NewHexEntered(mech, mech_map, newx, newy, last_z);
if (MechX(mech) == x && MechY(mech) == y) {
MarkForLOSUpdate(mech);
MechFloods(mech);
water_extinguish_inferno(mech);
steppable_base_check(mech, x, y);
/* Pilot XP */
if (In_Character(mech->mynum)) {
MechHexes(mech)++;
if (!(MechHexes(mech) % PIL_XP_EVERY_N_STEPS))
if (RGotPilot(mech))
AccumulatePilXP(MechPilot(mech), mech, 1, 0);
}
/* Check for stacking */
domino_space(mech, 0);
}
}
/* If aero/vtol make sure we're not rubbing against the ground or trees */
if ((MechMove(mech) == MOVE_VTOL || is_aero(mech)) && !Landed(mech))
CheckVTOLHeight(mech);
/* If we're a boat make sure we've not run a ground */
if (MechType(mech) == CLASS_VEH_NAVAL)
CheckNavalHeight(mech, oz);
/* We're charging lets do some damage */
if (MechChargeTarget(mech) != -1) {
/* Valid target? */
target = getMech(MechChargeTarget(mech));
if (target) {
if (FaMechRange(mech, target) < CHARGE_DIST_TRIGGER) {
ChargeMech(mech, target);
MechChargeTarget(mech) = -1;
MechChargeTimer(mech) = 0;
MechChargeDistance(mech) = 0;
}
} else {
mech_notify(mech, MECHPILOT, "Invalid CHARGE target!");
MechChargeTarget(mech) = -1;
MechChargeDistance(mech) = 0;
MechChargeTimer(mech) = 0;
}
}
/* If we're towing something update its position with us */
if (MechCarrying(mech) > 0) {
target = getMech(MechCarrying(mech));
if (target && target->mapindex == mech->mapindex) {
MirrorPosition(mech, target, 0);
SetRFacing(target, MechRFacing(mech));
}
}
/* If a bsuit has swarmed a target update its
* position in relation to its target */
BSuitMirrorSwarmedTarget(mech_map, mech);
/* This is really for killing MechWarriors
* actual heat code is checked with UpdateHeat */
fiery_death(mech);
}
void CheckNavalHeight(MECH * mech, int oz)
{
if (MechRTerrain(mech) != WATER && MechRTerrain(mech) != ICE &&
MechRTerrain(mech) != BRIDGE) {
MechSpeed(mech) = 0.0;
MechVerticalSpeed(mech) = 0;
MechDesiredSpeed(mech) = 0.0;
SetFacing(mech, 0);
MechDesiredFacing(mech) = 0;
return;
}
if (!oz && MechZ(mech) && MechElev(mech) > 1) {
MarkForLOSUpdate(mech);
MechZ(mech) = 0;
MechLOSBroadcast(mech, "dives!");
MechZ(mech) = -1;
}
if (MechFZ(mech) > 0.0) {
if (MechVerticalSpeed(mech) > 0 && !MechZ(mech) && oz < 0) {
mech_notify(mech, MECHALL,
"Your sub has reached surface and stops rising.");
MechLOSBroadcast(mech, tprintf("surfaces at %d,%d!",
MechX(mech), MechY(mech)));
/* Possible show-up message? */
}
MechZ(mech) = 0;
MechFZ(mech) = 0.0;
if (MechVerticalSpeed(mech) > 0)
MechVerticalSpeed(mech) = 0;
return;
}
if (MechZ(mech) <= (MechLowerElevation(mech))) {
MechZ(mech) = MIN(0, MechLowerElevation(mech) + 1);
if (MechElevation(mech) > 0)
SendError(tprintf
("Oddity: #%d managed to wind up on '%c' (%d elev.)",
mech->mynum, MechTerrain(mech), MechElev(mech)));
MechFZ(mech) = ((5.0 * MechZ(mech) - 4) * ZSCALE) / 5.0;
if (MechMove(mech) == MOVE_SUB) {
if (MechVerticalSpeed(mech) < 0) {
MechVerticalSpeed(mech) = 0;
mech_notify(mech, MECHALL,
"The sub has reached bottom and stops diving.");
}
#if 0
else
mech_notify(mech, MECHALL, "The sub has reached bottom.");
#endif
}
}
}
void CheckVTOLHeight(MECH * mech)
{
if (InWater(mech) && MechZ(mech) <= 0) {
mech_notify(mech, MECHALL,
"You crash your vehicle into the water!!");
mech_notify(mech, MECHALL,
"Water pours into the cockpit....gulp!");
MechLOSBroadcast(mech, "splashes into the water!");
DestroyAndDump(mech);
return;
}
if (MechZ(mech) >= MechElevation(mech))
return;
if (MechRTerrain(mech) == BRIDGE)
if (MechZ(mech) != (MechElevation(mech) - 1))
return;
aero_land(MechPilot(mech), mech, "");
if (Landed(mech))
return;
mech_notify(mech, MECHALL,
"CRASH!! You smash your toy into the ground!!");
MechLOSBroadcast(mech, "crashes into the ground!");
MechFalls(mech, 1 + fabs(MechVerticalSpeed(mech) / MP1), 0);
/* mech_notify (mech, MECHALL, "Your vehicle is inoperable."); */
MechZ(mech) = MechElevation(mech);
MechFZ(mech) = ZSCALE * MechZ(mech);
MechSpeed(mech) = 0.0;
MechVerticalSpeed(mech) = 0.0;
MechStatus(mech) |= LANDED;
/* DestroyMech (mech, mech); */
}
void UpdateHeading(MECH * mech)
{
int offset;
int normangle;
int mw_mod = 1;
float maxspeed, omaxspeed;
MAP *mech_map;
if (MechFacing(mech) == MechDesiredFacing(mech))
return;
maxspeed = MMaxSpeed(mech);
if (is_aero(mech))
maxspeed = maxspeed * ACCEL_MOD;
if ((MechHeat(mech) >= 9.) &&
(MechSpecials(mech) & TRIPLE_MYOMER_TECH))
maxspeed += 1.5 * MP1;
omaxspeed = maxspeed;
normangle = MechRFacing(mech) - SHO2FSIM(MechDesiredFacing(mech));
if (MechType(mech) == CLASS_MW || MechType(mech) == CLASS_BSUIT)
mw_mod = 60;
else if (MechIsQuad(mech))
mw_mod = 2;
if (mudconf.btech_fasaturn) {
#define FASA_TURN_MOD 3/2
if (Jumping(mech))
offset = 2 * SHO2FSIM(1) * 2 * 360 * FASA_TURN_MOD / 60;
else {
float ts = MechSpeed(mech);
if (ts < 0) {
maxspeed = maxspeed * 2.0 / 3.0;
ts = -ts;
}
if (ts > maxspeed || maxspeed < 0.1) /* kludge */
offset = 0;
else {
offset = SHO2FSIM(1) * 2 * 360 * FASA_TURN_MOD / 60 * (maxspeed - ts) * (omaxspeed / maxspeed) * mw_mod * MP_PER_KPH / 6; /* hmm. */
}
}
} else {
if (Jumping(mech)) {
mech_map = FindObjectsData(mech->mapindex);
offset =
SHO2FSIM(1) * 6 * JumpSpeedMP(mech, mech_map) * mw_mod;
} else if (fabs(MechSpeed(mech)) < 1.0)
offset = SHO2FSIM(1) * 3 * maxspeed * MP_PER_KPH * mw_mod;
else {
offset = SHO2FSIM(1) * 2 * maxspeed * MP_PER_KPH * mw_mod;
if ((SHO2FSIM(abs(normangle)) > offset) &&
IsRunning(MechSpeed(mech), maxspeed)) {
if (MechSpeed(mech) > maxspeed)
offset -= offset / 2 * maxspeed / MechSpeed(mech);
else
offset -=
offset / 2 * (3.0 * MechSpeed(mech) / maxspeed -
2.0);
}
}
}
/* offset = offset * 2 * MOVE_MOD; - Twice as fast as this;dunno why - */
offset = offset * MOVE_MOD;
#ifdef BT_MOVEMENT_MODES
if(GetTurnMode(mech) && HasBoolAdvantage(MechPilot(mech), "maneuvering_ace"))
offset = (offset * 3 ) /2 ;
if (MechStatus2(mech) & (SPRINTING|EVADING) && !HasBoolAdvantage(MechPilot(mech), "maneuvering_ace")) {
if (HasBoolAdvantage(MechPilot(mech), "speed_demon"))
offset = (offset * 2) / 3;
else
offset = (offset / 2);
}
#endif
if (normangle < 0)
normangle += SHO2FSIM(360);
if (IsDS(mech) && offset >= SHO2FSIM(10))
offset = SHO2FSIM(10);
if (normangle > SHO2FSIM(180)) {
AddRFacing(mech, offset);
if (MechFacing(mech) >= 360)
AddFacing(mech, -360);
normangle += offset;
if (normangle >= SHO2FSIM(360))
SetRFacing(mech, SHO2FSIM(MechDesiredFacing(mech)));
} else {
AddRFacing(mech, -offset);
if (MechRFacing(mech) < 0)
AddFacing(mech, 360);
normangle -= offset;
if (normangle < 0)
SetRFacing(mech, SHO2FSIM(MechDesiredFacing(mech)));
}
MechCritStatus(mech) |= CHEAD;
MarkForLOSUpdate(mech);
}
/* MPs lost for heat need to go off walking speed, not off total speed */
#define DECREASE_HEAT(spd) \
tempspeed *= (ceil((rint((maxspeed / 1.5) / MP1) - (spd/MP1) ) * 1.5) * MP1) / maxspeed
#define DECREASE_OLD(spd) \
tempspeed *= (maxspeed - (spd)) / maxspeed
#define INCREASE_OLD(spd) DECREASE_OLD(-(spd))
#define DECREASE_NEW(spd) \
tempspeed *= MP1 / (MP1 + spd)
#define INCREASE_NEW(spd) \
tempspeed *= (MP1 + spd/2) / MP1
#define DECREASE(s) DECREASE_NEW(s)
#define INCREASE(s) INCREASE_NEW(s)
/* If you want to simulate _OLDs, you have to add 1MP in some cases (eww) */
float terrain_speed(MECH * mech, float tempspeed, float maxspeed,
int terrain, int elev)
{
switch (terrain) {
case SNOW:
case ROUGH:
DECREASE(MP1);
break;
case MOUNTAINS:
DECREASE(MP2);
break;
case LIGHT_FOREST:
if (MechType(mech) != CLASS_BSUIT)
DECREASE(MP1);
break;
case HEAVY_FOREST:
if (MechType(mech) != CLASS_BSUIT)
DECREASE(MP2);
break;
case BRIDGE:
case ROAD:
/* Ground units (wheeled and tracked) get +1 MP moving on paved surface */
#ifndef BT_MOVEMENT_MODES
if (MechMove(mech) == MOVE_TRACK || MechMove(mech) == MOVE_WHEEL)
#else
if (!(MechStatus2(mech) & SPRINTING) &&
(MechMove(mech) == MOVE_TRACK || MechMove(mech) == MOVE_WHEEL))
#endif
INCREASE_OLD(MP1);
case ICE:
if (MechZ(mech) >= 0)
break;
/* FALLTHRU */
/* if he's under the ice/bridge, treat as water. */
case WATER:
if (MechIsBiped(mech) || MechIsQuad(mech)) {
if (elev <= -2)
DECREASE(MP3);
else if (elev == -1)
DECREASE(MP1);
}
break;
}
return tempspeed;
}
void UpdateSpeed(MECH * mech)
{
float acc, tempspeed, maxspeed;
MECH *target;
if (!(!Fallen(mech) && !Jumping(mech) && (MechMaxSpeed(mech) > 0.0)))
return;
tempspeed = fabs(MechDesiredSpeed(mech));
maxspeed = MMaxSpeed(mech);
if (maxspeed < 0.0)
maxspeed = 0.0;
if ((MechStatus(mech) & MASC_ENABLED) &&
(MechStatus(mech) & SCHARGE_ENABLED))
maxspeed = ceil((rint(maxspeed / 1.5) / MP1) * 2.5) * MP1;
else if (MechStatus(mech) & MASC_ENABLED)
maxspeed = (4. / 3.) * maxspeed;
else if (MechStatus(mech) & SCHARGE_ENABLED)
maxspeed = (4. / 3.) * maxspeed;
if (MechSpecials(mech) & TRIPLE_MYOMER_TECH) {
if (MechHeat(mech) >= 9.)
maxspeed =
ceil((rint((MMaxSpeed(mech) / 1.5) / MP1) +
1) * 1.5) * MP1;
/* maxspeed *= ((maxspeed + 1.5 * MP1) / maxspeed); */
if (MechDesiredSpeed(mech) >= maxspeed)
MechDesiredSpeed(mech) = maxspeed;
}
if (MechHeat(mech) >= 5.) {
/* if ((MechHeat(mech) >= 9.) && (MechSpecials(mech) & TRIPLE_MYOMER_TECH)) {
tempspeed *= ((maxspeed + 1.5 * MP1) / maxspeed);
}
*/
if (MechHeat(mech) >= 25.)
DECREASE_HEAT(MP5);
else if (MechHeat(mech) >= 20.)
DECREASE_HEAT(MP4);
else if (MechHeat(mech) >= 15.)
DECREASE_HEAT(MP3);
else if (MechHeat(mech) >= 10.)
DECREASE_HEAT(MP2);
else if (!((MechSpecials(mech) & TRIPLE_MYOMER_TECH) &&
MechHeat(mech) >= 9))
DECREASE_HEAT(MP1);
}
if (MechType(mech) != CLASS_MW && MechMove(mech) != MOVE_VTOL &&
(MechMove(mech) != MOVE_FLY || Landed(mech)))
tempspeed =
terrain_speed(mech, tempspeed, maxspeed, MechRTerrain(mech),
MechElevation(mech));
if (MechCritStatus(mech) & CHEAD) {
if (mudconf.btech_slowdown == 2) {
/* _New_ slowdown based on facing vs desired difference */
int dif = MechFacing(mech) - MechDesiredFacing(mech);
if (dif < 0)
dif = -dif;
if (dif > 180)
dif = 360 - dif;
if (dif) {
dif = (dif - 1) / 30;
dif = (dif + 2); /* whee */
/* dif = 2 to 7 */
tempspeed = tempspeed * (10 - dif) / 10;
}
} else if (mudconf.btech_slowdown == 1) {
if (MechFacing(mech) != MechDesiredFacing(mech))
tempspeed = tempspeed * 2.0 / 3.0;
else
tempspeed = tempspeed * 3.0 / 4.0;
}
#ifdef BT_MOVEMENT_MODES
if ((Sprinting(mech) || Evading(mech)) && !(HasBoolAdvantage(MechPilot(mech), "speed_demon") || HasBoolAdvantage(MechPilot(mech), "maneuvering_ace")))
tempspeed = (tempspeed * 2) / 3;
#endif
MechCritStatus(mech) &= ~CHEAD;
}
if (MechIsQuad(mech) && MechLateral(mech))
DECREASE_OLD(MP1); /* In truth 1 MP */
#ifdef BT_MOVEMENT_MODES
else if (MechLateral(mech)) {
if (HasBoolAdvantage(MechPilot(mech), "maneuvering_ace"))
DECREASE_OLD(MP2);
else
DECREASE_OLD(MP3);
}
#endif
if (tempspeed <= 0.0)
tempspeed = 0.0;
if (MechDesiredSpeed(mech) < 0.)
tempspeed = -tempspeed;
/* if (MechSpecials(mech) & TRIPLE_MYOMER_TECH)
{
if (MechHeat(mech) >= 9.)
maxspeed *= ((maxspeed + 1.5 * MP1) / maxspeed);
if (MechDesiredSpeed(mech) >= maxspeed)
MechDesiredSpeed(mech) = maxspeed;
}
*/
if (tempspeed != MechSpeed(mech)) {
if (MechIsQuad(mech))
acc = maxspeed / 10.;
else
acc = maxspeed / 20.;
if (HasBoolAdvantage(MechPilot(mech), "speed_demon"))
acc *= 1.25;
if (tempspeed < MechSpeed(mech)) {
/* Decelerating */
MechSpeed(mech) -= acc;
if (tempspeed > MechSpeed(mech))
MechSpeed(mech) = tempspeed;
} else {
/* Accelerating */
MechSpeed(mech) += acc;
if (tempspeed < MechSpeed(mech))
MechSpeed(mech) = tempspeed;
}
}
if (MechCarrying(mech) > 0) {
target = getMech(MechCarrying(mech));
if (target)
MechSpeed(target) = MechSpeed(mech);
}
}
int OverheatMods(MECH * mech)
{
int returnValue;
if (MechHeat(mech) >= 24.) {
/* +4 to fire... */
returnValue = 4;
} else if (MechHeat(mech) >= 17.) {
/* +3 to fire... */
returnValue = 3;
} else if (MechHeat(mech) >= 13.) {
/* +2 to fire... */
returnValue = 2;
} else if (MechHeat(mech) >= 8.) {
/* +1 to fire... */
returnValue = 1;
} else {
returnValue = 0;
}
return (returnValue);
}
void ammo_explosion(MECH * attacker, MECH * mech, int ammoloc,
int ammocritnum, int damage)
{
if (MechType(mech) == CLASS_MW) {
mech_notify(mech, MECHALL, "Your weapon's ammo explodes!");
MechLOSBroadcast(mech, "'s weapon's ammo explodes!");
} else {
mech_notify(mech, MECHALL, "Ammunition explosion!");
if (GetPartAmmoMode(mech, ammoloc, ammocritnum) & INFERNO_MODE)
MechLOSBroadcast(mech,
"is suddenly enveloped by a brilliant fireball!");
else
MechLOSBroadcast(mech, "has an internal ammo explosion!");
}
DestroyPart(mech, ammoloc, ammocritnum);
if (!attacker)
return;
if (GetPartAmmoMode(mech, ammoloc, ammocritnum) & INFERNO_MODE) {
Inferno_Hit(mech, mech, damage / 4, 0);
damage = damage / 2;
}
if (MechType(mech) == CLASS_BSUIT)
DamageMech(mech, attacker, 0, -1, ammoloc, 0, 0, damage, 0, -1, 0,
-1, 0, 0);
else
DamageMech(mech, attacker, 0, -1, ammoloc, 0, 0, -1, damage, -1, 0,
-1, 0, 0);
if (MechType(mech) != CLASS_BSUIT) {
mech_notify(mech, MECHPILOT,
"You take personal injury from the ammunition explosion!");
if (HasBoolAdvantage(MechPilot(mech), "pain_resistance"))
headhitmwdamage(mech, 1);
else
headhitmwdamage(mech, 2);
}
}
void HandleOverheat(MECH * mech)
{
int avoided = 0;
MAP *mech_map;
if (MechHeat(mech) < 14.)
return;
/* Has it been a TURN already ? */
if ((MechHeatLast(mech) + TURN) > muxevent_tick)
return;
MechHeatLast(mech) = muxevent_tick;
#ifdef BT_EXILE_MW3STATS
if (!isPlayer(MechPilot(mech))) {
#endif
if (MechHeat(mech) >= 30.) {
/* Shutdown */
} else if (MechHeat(mech) >= 26.) {
/* Shutdown avoid on 10+ */
if (Roll() >= 10)
avoided = 1;
} else if (MechHeat(mech) >= 22.) {
/* Shutdown avoid on 8+ */
if (Roll() >= 8)
avoided = 1;
} else if (MechHeat(mech) >= 18.) {
/* Shutdown avoid on 6+ */
if (Roll() >= 6)
avoided = 1;
} else if (MechHeat(mech) >= 14.) {
/* Shutdown avoid on 4+ */
if (Roll() >= 4)
avoided = 1;
}
#ifdef BT_EXILE_MW3STATS
} else {
mech_notify(mech, MECHALL, "You franticly attempt to override the shutdown process!");
avoided = char_getskillsuccess(MechPilot(mech), "computer", (MechHeat(mech) >= 30. ? 8 : MechHeat(mech) >= 26. ? 6 : MechHeat(mech) >= 22. ? 4 : MechHeat(mech) >=18. ? 2 : 0), 1);
if (avoided)
AccumulateComputerXP(MechPilot(mech), mech, 1);
}
#endif
if (!(avoided) && Started(mech)) {
if (MechStatus(mech) & STARTED)
mech_notify(mech, MECHALL, "%ci%crReactor shutting down...%c");
if (Jumping(mech) || OODing(mech) || (is_aero(mech) &&
!Landed(mech))) {
mech_notify(mech, MECHALL, "%chYou fall from the sky!!!!!%c");
MechLOSBroadcast(mech, "falls from the sky!");
mech_map = getMap(mech->mapindex);
MechFalls(mech, JumpSpeedMP(mech, mech_map), 0);
domino_space(mech, 2);
} else
MechLOSBroadcast(mech, "stops in mid-motion!");
Shutdown(mech);
StopMoving(mech);
StopStand(mech);
}
avoided = 0;
/* Ammo */
if (MechHeat(mech) >= 19.) {
if (MechHeat(mech) >= 28.) {
/* Ammo explosion (Avoid 8+) */
if (Roll() >= 8)
avoided = 1;
} else if (MechHeat(mech) >= 23.) {
/* Ammo explosion (Avoid 6+) */
if (Roll() >= 6)
avoided = 1;
} else if (MechHeat(mech) >= 19.) {
/* Ammo explosion (Avoid 4+) */
if (Roll() >= 4)
avoided = 1;
}
if (!(avoided)) {
int ammoloc, ammocritnum, damage;
damage = FindDestructiveAmmo(mech, &ammoloc, &ammocritnum);
if (damage) {
/* BOOM! */
/* That's going to hurt... */
ammo_explosion(mech, mech, ammoloc, ammocritnum, damage);
} else
mech_notify(mech, MECHALL,
"You have no ammunition, lucky you!");
}
}
}
static int EnableSomeHS(MECH * mech)
{
int numsinks = HS_Efficiency(mech);
numsinks = MIN(numsinks, MechDisabledHS(mech));
if (!numsinks)
return 0;
MechDisabledHS(mech) -= numsinks;
MechMinusHeat(mech) += numsinks; /* We dont check for water and such after enabling them, only the next tic. */
#ifdef HEATCUTOFF_DEBUG
mech_notify(mech, MECHALL,
tprintf("%%cg%d heatsink%s kick%s into action.%%c", numsinks,
numsinks == 1 ? "" : "s", numsinks == 1 ? "s" : ""));
#endif
return numsinks;
}
static int DisableSomeHS(MECH * mech)
{
int numsinks = HS_Efficiency(mech);
numsinks = MIN(numsinks, MechActiveNumsinks(mech));
if (!numsinks)
return 0;
MechDisabledHS(mech) += numsinks;
MechMinusHeat(mech) -= numsinks; /* Submerged heatsinks silently still dissipate some heat */
#ifdef HEATCUTOFF_DEBUG
mech_notify(mech, MECHALL,
tprintf("%%cy%d heatsink%s hum%s into silence.%%c", numsinks,
numsinks == 1 ? "" : "s", numsinks == 1 ? "s" : ""));
#endif
return numsinks;
}
void UpdateHeat(MECH * mech)
{
int legsinks;
float maxspeed;
float intheat;
float inheat;
MAP *map;
if (MechType(mech) != CLASS_MECH && MechType(mech) != CLASS_AERO)
return;
inheat = MechHeat(mech);
maxspeed = MMaxSpeed(mech);
MechPlusHeat(mech) = 0.;
if (MechTerrain(mech) == FIRE && MechType(mech) == CLASS_MECH)
MechPlusHeat(mech) += 5.;
if (fabs(MechSpeed(mech)) > 0.0) {
#ifndef BT_MOVEMENT_MODES
if (IsRunning(MechDesiredSpeed(mech), maxspeed))
MechPlusHeat(mech) += 2.;
#else
if (Sprinting(mech) || Evading(mech))
MechPlusHeat(mech) += 3.;
else if (IsRunning(MechDesiredSpeed(mech), maxspeed))
MechPlusHeat(mech) += 2.;
#endif
else
MechPlusHeat(mech) += 1.;
}
if (Jumping(mech))
MechPlusHeat(mech) +=
(MechJumpSpeed(mech) * MP_PER_KPH >
3.) ? MechJumpSpeed(mech) * MP_PER_KPH : 3.;
if (Started(mech))
MechPlusHeat(mech) += (float) MechEngineHeat(mech);
if (StealthArmorActive(mech))
MechPlusHeat(mech) += 10;
if (NullSigSysActive(mech))
MechPlusHeat(mech) += 10;
intheat = MechPlusHeat(mech);
MechPlusHeat(mech) += MechWeapHeat(mech);
/* ADD Water effects here */
if (InWater(mech) && MechZ(mech) <= -1) {
legsinks = FindLegHeatSinks(mech);
legsinks = (legsinks > 4) ? 4 : legsinks;
if (MechZ(mech) == -1 && !Fallen(mech)) {
MechMinusHeat(mech) = MIN(2 * MechActiveNumsinks(mech),
legsinks + MechActiveNumsinks(mech));
} else {
MechMinusHeat(mech) = MIN(2 * MechActiveNumsinks(mech),
6 + MechActiveNumsinks(mech));
}
} else {
MechMinusHeat(mech) = (float) (MechActiveNumsinks(mech));
}
if (Jellied(mech)) {
MechMinusHeat(mech) = MechMinusHeat(mech) - 6;
if (MechMinusHeat(mech) < 0)
MechMinusHeat(mech) = 0;
}
if (InSpecial(mech))
if ((map = FindObjectsData(mech->mapindex)))
if (MapUnderSpecialRules(map))
if (MapTemperature(map) < -30 || MapTemperature(map) > 50) {
if (MapTemperature(map) < -30)
MechMinusHeat(mech) +=
(-30 - MapTemperature(map) + 9) / 10;
else
MechMinusHeat(mech) -=
(MapTemperature(map) - 50 + 9) / 10;
}
/* Handle heat cutoff now */
/* En/DisableSomeHS() take care of MechMinusHeat also. */
if (Heatcutoff(mech)) {
float overheat = MechPlusHeat(mech) - MechMinusHeat(mech);
if (overheat >= 9. + HS_Efficiency(mech))
EnableSomeHS(mech);
else if (overheat < 9.)
DisableSomeHS(mech);
} else if (MechDisabledHS(mech))
EnableSomeHS(mech);
MechHeat(mech) = MechPlusHeat(mech) - MechMinusHeat(mech);
/* No lowering of heat if heat is under 9 */
MechWeapHeat(mech) -=
(MechMinusHeat(mech) - intheat) / WEAPON_RECYCLE_TIME;
if (MechWeapHeat(mech) < 0.0)
MechWeapHeat(mech) = 0.0;
if (MechHeat(mech) < 0.0)
MechHeat(mech) = 0.0;
if ((muxevent_tick % TURN) == 0)
if (MechCritStatus(mech) & LIFE_SUPPORT_DESTROYED ||
(MechHeat(mech) > 30. && Number(0, 1) == 0)) {
if (MechHeat(mech) > 25.) {
mech_notify(mech, MECHPILOT,
"You take personal injury from heat!!");
headhitmwdamage(mech,
MechCritStatus(mech) & LIFE_SUPPORT_DESTROYED ? 2 : 1);
} else if (MechHeat(mech) >= 15.) {
mech_notify(mech, MECHPILOT,
"You take personal injury from heat!!");
headhitmwdamage(mech, 1);
}
}
if (MechHeat(mech) >= 19) {
if (inheat < 19) {
mech_notify(mech, MECHALL,
"%ch%cr=====================================");
mech_notify(mech, MECHALL,
"Your Excess Heat indicator turns RED!");
mech_notify(mech, MECHALL,
"=====================================%c");
}
} else if (MechHeat(mech) >= 14) {
if (inheat >= 19 || inheat < 14) {
mech_notify(mech, MECHALL,
"%ch%cy=======================================");
mech_notify(mech, MECHALL,
"Your Excess Heat indicator turns YELLOW");
mech_notify(mech, MECHALL,
"=======================================%c");
}
} else {
if (inheat >= 14) {
mech_notify(mech, MECHALL,
"%cg======================================");
mech_notify(mech, MECHALL,
"Your Excess Heat indicator turns GREEN");
mech_notify(mech, MECHALL,
"======================================%c");
}
}
HandleOverheat(mech);
}
int recycle_weaponry(MECH * mech)
{
int loop;
int count, i;
int crit[MAX_WEAPS_SECTION];
unsigned char weaptype[MAX_WEAPS_SECTION];
unsigned char weapdata[MAX_WEAPS_SECTION];
char location[20];
int diff = (muxevent_tick - MechLWRT(mech));
int lowest = 0;
if (diff < 1) {
if (diff < 0)
MechLWRT(mech) = muxevent_tick;
return 1;
}
MechLWRT(mech) = muxevent_tick;
if (!Started(mech) || Destroyed(mech))
return 0;
arc_override = 1;
for (loop = 0; loop < NUM_SECTIONS; loop++) {
count = FindWeapons(mech, loop, weaptype, weapdata, crit);
for (i = 0; i < count; i++) {
if (WpnIsRecycling(mech, loop, crit[i])) {
if (diff >= GetPartData(mech, loop, crit[i])) {
GetPartData(mech, loop, crit[i]) = 0;
mech_notify(mech, MECHSTARTED,
tprintf(MechType(mech) ==
CLASS_MW ?
"%%cgYou are ready to attack again with %s.%%c"
: PartTempNuke(mech, loop,
crit[i]) !=
0 ? "%%cg%s is operational again.%%c" :
(GetPartFireMode(mech, loop,
crit[i]) & ROCKET_FIRED) ? "" :
"%%cg%s finished recycling.%%c",
&MechWeapons[weaptype[i]].name[3]));
SetPartTempNuke(mech, loop, crit[i], 0);
} else {
if (PartTempNuke(mech, loop,
crit[i]) != FAIL_DESTROYED) {
GetPartData(mech, loop, crit[i]) -= diff;
if (GetPartData(mech, loop, crit[i]) < lowest ||
!lowest)
lowest = GetPartData(mech, loop, crit[i]);
}
}
}
}
/* Cycle a section */
if (MechSections(mech)[loop].recycle &&
((MechType(mech) == CLASS_MECH)
|| (MechType(mech) == CLASS_BSUIT)
|| (MechType(mech) == CLASS_VEH_GROUND)
|| (MechType(mech) == CLASS_VTOL))) {
/* Is the section finished cycling or do we deincrement it */
if (diff >= MechSections(mech)[loop].recycle &&
!SectIsDestroyed(mech, loop)) {
MechSections(mech)[loop].recycle = 0;
ArmorStringFromIndex(loop, location, MechType(mech),
MechMove(mech));
mech_notify(mech, MECHSTARTED,
tprintf("%%cg%s%s has finished its previous action.%%c",
MechType(mech) == CLASS_BSUIT ? "" : "Your ",
location));
} else {
MechSections(mech)[loop].recycle -= diff;
if (MechSections(mech)[loop].recycle < lowest || !lowest)
lowest = MechSections(mech)[loop].recycle;
}
}
}
arc_override = 0;
return lowest;
}
int SkidMod(float Speed)
{
if (Speed < 2.1)
return -1;
if (Speed < 4.1)
return 0;
if (Speed < 7.1)
return 1;
if (Speed < 10.1)
return 2;
return 4;
}
/*
* Move the unit back to its previous location because of cliff or something
*/
void move_unit_back(MECH *mech, float deltax, float deltay, int lastelevation,
int ot, int le) {
MechFX(mech) -= deltax;
MechFY(mech) -= deltay;
MechX(mech) = MechLastX(mech);
MechY(mech) = MechLastY(mech);
MechZ(mech) = lastelevation;
MechFZ(mech) = MechZ(mech) * ZSCALE;
MechTerrain(mech) = ot;
MechElev(mech) = le;
}
/*
* Check to see what happens to the unit now that its entered a new hex
*/
void NewHexEntered(MECH * mech, MAP * mech_map, float deltax, float deltay,
int last_z)
{
int elevation, lastelevation;
int oldterrain;
int ot, le, ed, done = 0, tt, avoidbth;
int isunder = 0;
float f;
/* Recording the old elevation and terrain */
/*! \todo {Wasn't lastelevation passed as an argument 'last_z' ?} */
ot = oldterrain = GetTerrain(mech_map, MechLastX(mech), MechLastY(mech));
if ((MechMove(mech) == MOVE_HOVER) &&
(oldterrain == WATER || oldterrain == ICE ||
((oldterrain == BRIDGE) && (last_z == 0)))) {
le = lastelevation = elevation = 0;
} else {
le = lastelevation = Elevation(mech_map, MechLastX(mech), MechLastY(mech));
elevation = MechElevation(mech);
if (MechMove(mech) == MOVE_HOVER && elevation < 0)
elevation = 0;
if (ot == ICE && MechZ(mech) >= 0) {
le = lastelevation = 0;
}
if (MechZ(mech) < le)
le = MechZ(mech);
}
switch (MechMove(mech)) {
case MOVE_BIPED:
case MOVE_QUAD:
if (Jumping(mech)) {
if (MechRTerrain(mech) == WATER)
return;
#define MOVE_BACK \
MechFX(mech) -= deltax;\
MechFY(mech) -= deltay;\
MechX(mech) = MechLastX(mech);\
MechY(mech) = MechLastY(mech);\
MechZ(mech) = lastelevation;\
MechFZ(mech) = MechZ(mech) * ZSCALE;\
MechTerrain(mech) = ot;\
MechElev(mech) = le;
/* Did we hit something while jumping */
if (collision_check(mech, JUMP, 0, 0)) {
ed = MAX(1, 1 + MechZ(mech) - Elevation(mech_map,
MechX(mech), MechY(mech)));
move_unit_back(mech, deltax, deltay, lastelevation, ot, le);
mech_notify(mech, MECHALL,
"%chYou attempt to jump over elevation that is too high!!%c");
if (RGotPilot(mech) &&
MadePilotSkillRoll(mech, (int) (MechFZ(mech)) / ZSCALE / 3)) {
mech_notify(mech, MECHALL, "%chYou land safely.%c");
LandMech(mech);
} else {
mech_notify(mech, MECHALL,
"%chYou crash into the obstacle and fall from the sky!!!!!%c");
MechLOSBroadcast(mech,
"crashes into an obstacle and falls from the sky!");
MechFalls(mech, ed, 0);
domino_space(mech, 2);
}
}
return;
}
/* Walked into a wall silly */
if (collision_check(mech, WALK_WALL, lastelevation, oldterrain)) {
move_unit_back(mech, deltax, deltay, lastelevation, ot, le);
mech_notify(mech, MECHALL,
"You attempt to climb a hill too steep for you.");
if (MechPilot(mech) == -1 || (!mudconf.btech_skidcliff &&
MadePilotSkillRoll(mech,
(int) (fabs((MechSpeed(mech)) + MP1) / MP1) / 3))
|| (mudconf.btech_skidcliff && MadePilotSkillRoll(mech,
SkidMod(fabs(MechSpeed(mech)) / MP1)))) {
mech_notify(mech, MECHALL,
"You manage to stop before crashing.");
MechLOSBroadcast(mech, "stops suddenly to avoid a cliff!");
} else {
mech_notify(mech, MECHALL,
"You run headlong into the cliff and fall down!!");
MechLOSBroadcast(mech,
"runs headlong into a cliff and falls down!");
if (!mudconf.btech_skidcliff)
MechFalls(mech, (int) (1 + (MechSpeed(mech)) * MP_PER_KPH) / 4, 0);
else
MechFalls(mech, 1, 0);
}
MechDesiredSpeed(mech) = 0;
MechSpeed(mech) = 0;
MechZ(mech) = lastelevation;
return;
} else if (collision_check(mech, WALK_DROP, lastelevation,
oldterrain)) {
/* Walked off a cliff ... */
mech_notify(mech, MECHALL,
"You notice a large drop in front of you");
avoidbth = mudconf.btech_skidcliff ?
SkidMod(fabs(MechSpeed(mech)) / MP1) :
((fabs((MechSpeed(mech)) + MP1) / MP1) / 3);
if (MechPilot(mech) == -1 || (!MechAutoFall(mech) &&
MadePilotSkillRoll(mech, avoidbth))) {
mech_notify(mech, MECHALL,
"You manage to stop before falling off.");
MechLOSBroadcast(mech,
"stops suddenly to avoid falling off a cliff!");
move_unit_back(mech, deltax, deltay, lastelevation, ot, le);
} else {
mech_notify(mech, MECHALL,
"You run off the cliff and fall to the ground below.");
MechLOSBroadcast(mech,
"runs off a cliff and falls to the ground below!");
MechFalls(mech, lastelevation - elevation, 0);
MechDesiredSpeed(mech) = 0;
MechSpeed(mech) = 0;
}
MechDesiredSpeed(mech) = 0;
MechSpeed(mech) = 0;
return;
} else if (mudconf.btech_roll_on_backwalk &&
(MechSpeed(mech) < 0) &&
(collision_check(mech, WALK_BACK, lastelevation, oldterrain))) {
mech_printf(mech, MECHALL, "You notice a %s behind you!",
(elevation > lastelevation ? "small incline" : "small drop"));
if (MechPilot(mech) == -1
|| (MadePilotSkillRoll(mech,
collision_check(mech, WALK_BACK, lastelevation, oldterrain)
- 1))) {
mech_notify(mech, MECHALL, "You manage to overcome the obstacle.");
} else {
mech_printf(mech, MECHALL, "%s",
(elevation > lastelevation ?
"You stumble on your rear and fall down." :
"You fall on your rear off the small incline."));
/*! \todo {Get rid of this tprintf} */
MechLOSBroadcast(mech, tprintf("%s",(elevation > lastelevation ?
"falls on it's back walking up an incline." :
"falls off the back of a small incline.")));
MechFalls(mech, abs(lastelevation - elevation), 1);
MechDesiredSpeed(mech) = 0;
MechSpeed(mech) = 0;
if (elevation > lastelevation) {
move_unit_back(mech, deltax, deltay, lastelevation, ot, le);
}
}
return;
}
/* Slow the unit if its made an elevation change */
le = elevation - lastelevation;
le = (le < 0) ? -le : le;
if (MechZ(mech) != elevation)
le = 0;
if (le > 0) {
deltax = (le == 1) ? MP1 : MP2;
if (MechSpeed(mech) > 0) {
MechSpeed(mech) -= deltax;
if (MechSpeed(mech) < 0)
MechSpeed(mech) = 0;
} else if (MechSpeed(mech) < 0) {
MechSpeed(mech) += deltax;
if (MechSpeed(mech) > 0)
MechSpeed(mech) = 0;
}
}
if (MechType(mech) == CLASS_BSUIT) {
/* Are they in water, also make sure it affects them */
if (!(MechSpecials2(mech) & WATERPROOF_TECH) &&
(MechRTerrain(mech) == WATER ||
(MechRTerrain(mech) == BRIDGE &&
(lastelevation < (elevation - 1)))) &&
elevation < 0) {
mech_notify(mech, MECHALL,
"You notice a body of water in front of you");
if (MechPilot(mech) == -1 ||
MadePilotSkillRoll(mech,
(int) (fabs((MechSpeed(mech)) + MP1) / MP1) / 3)) {
mech_notify(mech, MECHALL,
"You manage to stop before falling in.");
MechLOSBroadcast(mech,
"stops suddenly to avoid going for a swim!");
} else {
mech_notify(mech, MECHALL,
"You trip at the edge of the water and plunge in...");
MechFloods(mech);
return;
}
move_unit_back(mech, deltax, deltay, lastelevation, ot, le);
MechDesiredSpeed(mech) = 0;
MechSpeed(mech) = 0;
return;
}
} else if (!(MechSpecials2(mech) & WATERPROOF_TECH) &&
((MechRTerrain(mech) == WATER && MechZ(mech) < 0) ||
(MechRTerrain(mech) == BRIDGE && MechZ(mech) < 0) ||
(MechRTerrain(mech) == ICE && MechZ(mech) < 0) ||
MechRTerrain(mech) == HIGHWATER) &&
MechType(mech) != CLASS_MW) {
int skillmod, dammod;
MechDesiredSpeed(mech) = MIN(MechDesiredSpeed(mech),
WalkingSpeed(MMaxSpeed(mech)));
#ifdef BT_MOVEMENT_MODES
if (MechStatus2(mech) & SPRINTING) {
MechStatus2(mech) &= ~SPRINTING;
MechLOSBroadcast(mech, "breaks out of its sprint as it enters water!");
mech_notify(mech, MECHALL, "You lose your sprinting momentum as you "
"enter water!");
MECHEVENT(mech, EVENT_MOVEMODE, mech_movemode_event, TURN,
MODE_OFF|MODE_SPRINT|MODE_MODEFAIL);
}
#endif
if (IsRunning(MechSpeed(mech), MMaxSpeed(mech))) {
mech_notify(mech, MECHPILOT,
"You struggle to keep control as you run into the water!");
skillmod = 2;
dammod = 2;
} else {
mech_notify(mech, MECHPILOT, "You use your piloting skill "
"to maneuver through the water.");
skillmod = 0;
dammod = 0;
}
skillmod += (MechRTerrain(mech) == HIGHWATER ? -2 :
MechRTerrain(mech) == BRIDGE ? bridge_w_elevation(mech) :
MechElev(mech) > 3 ? 1 : (MechElev(mech) - 2));
if (!MadePilotSkillRoll(mech, skillmod)) {
mech_notify(mech, MECHALL,
"You slip in the water and fall down");
MechLOSBroadcast(mech,
"slips in the water and falls down!");
MechFalls(mech, 1, dammod);
done = 1;
}
}
break;
case MOVE_TRACK:
if (collision_check(mech, WALK_WALL, lastelevation, oldterrain)) {
mech_notify(mech, MECHALL,
"You attempt to climb a hill too steep for you.");
if (MechPilot(mech) == -1 || (!mudconf.btech_skidcliff &&
MadePilotSkillRoll(mech,
(int) (fabs((MechSpeed(mech)) + MP1) / MP1) / 3))
|| (mudconf.btech_skidcliff &&
MadePilotSkillRoll(mech,
SkidMod(fabs(MechSpeed(mech)) / MP1)))) {
mech_notify(mech, MECHALL,
"You manage to stop before crashing.");
MechLOSBroadcast(mech, "stops suddenly to avoid a cliff!");
} else {
if (!mudconf.btech_skidcliff) {
mech_notify(mech, MECHALL, "You smash into a cliff!!");
MechLOSBroadcast(mech, "crashes to a cliff!");
MechFalls(mech, (int) (MechSpeed(mech) * MP_PER_KPH / 4), 0);
} else {
mech_notify(mech, MECHALL,
"You skid to a violent halt!!");
MechLOSBroadcast(mech, "goes into a skid!");
MechFalls(mech, 0, 0);
}
}
move_unit_back(mech, deltax, deltay, lastelevation, ot, le);
MechDesiredSpeed(mech) = 0;
MechSpeed(mech) = 0;
return;
} else if (collision_check(mech, WALK_DROP, lastelevation,
oldterrain)) {
mech_notify(mech, MECHALL,
"You notice a large drop in front of you");
avoidbth = mudconf.btech_skidcliff ?
SkidMod(fabs(MechSpeed(mech)) / MP1) :
((fabs((MechSpeed(mech)) + MP1) / MP1) / 3);
if (MechPilot(mech) == -1 || (!MechAutoFall(mech) &&
MadePilotSkillRoll(mech, avoidbth))) {
mech_notify(mech, MECHALL,
"You manage to stop before falling off.");
MechLOSBroadcast(mech,
"stops suddenly to avoid falling off a cliff!");
} else {
mech_notify(mech, MECHALL,
"You drive off the cliff and fall to the ground below.");
MechLOSBroadcast(mech,
"drives off a cliff and falls to the ground below.");
MechFalls(mech, lastelevation - elevation, 0);
domino_space(mech, 2);
if (MechRTerrain(mech) == WATER &&
!(MechSpecials2(mech) & WATERPROOF_TECH)) {
mech_notify(mech, MECHALL,
"You drive into the water and your vehicle becomes inoperable.");
Destroy(mech);
}
return;
}
move_unit_back(mech, deltax, deltay, lastelevation, ot, le);
MechDesiredSpeed(mech) = 0;
MechSpeed(mech) = 0;
return;
} else if (mudconf.btech_roll_on_backwalk && (MechSpeed(mech) < 0) &&
(collision_check(mech, WALK_BACK, lastelevation, oldterrain))) {
mech_printf(mech, MECHALL, "You notice a %s behind you!",
(elevation > lastelevation ? "small incline" : "small drop"));
if (MechPilot(mech) == -1 || (MadePilotSkillRoll(mech,
collision_check(mech, WALK_BACK, lastelevation, oldterrain)
- 1))) {
mech_notify(mech, MECHALL, "You manage to overcome the obstacle.");
} else {
mech_printf(mech, MECHALL, "%s",
(elevation > lastelevation ?
"You stumble on your rear and fall down." :
"You fall on your rear off the small incline."));
MechLOSBroadcast(mech, tprintf("%s",(elevation > lastelevation
? "falls on it's back walking up an incline." :
"falls off the back of a small incline.")));
MechFalls(mech, abs(lastelevation - elevation), 1);
MechDesiredSpeed(mech) = 0;
MechSpeed(mech) = 0;
if (elevation > lastelevation) {
move_unit_back(mech, deltax, deltay, lastelevation, ot, le);
}
}
return;
}
if (!(MechSpecials2(mech) & WATERPROOF_TECH) &&
(MechRTerrain(mech) == WATER ||
(MechRTerrain(mech) == BRIDGE && (lastelevation < (elevation - 1)))) &&
elevation < 0) {
mech_notify(mech, MECHALL,
"You notice a body of water in front of you");
if (MechPilot(mech) == -1 ||
MadePilotSkillRoll(mech,
(int) (fabs((MechSpeed(mech)) + MP1) / MP1) / 3)) {
mech_notify(mech, MECHALL,
"You manage to stop before falling in.");
MechLOSBroadcast(mech,
"stops suddenly to avoid driving into the water!");
} else {
mech_notify(mech, MECHALL,
"You drive into the water and your vehicle becomes inoperable.");
Destroy(mech);
return;
}
move_unit_back(mech, deltax, deltay, lastelevation, ot, le);
MechDesiredSpeed(mech) = 0;
MechSpeed(mech) = 0;
return;
}
/* New terrain restrictions */
if (mudconf.btech_newterrain) {
tt = MechRTerrain(mech);
if ((tt == HEAVY_FOREST) && fabs(MechSpeed(mech)) > MP1) {
#if 0
mech_notify(mech, MECHALL,
"You cruise at a bunch of trees!");
#endif
mech_notify(mech, MECHALL,
"You try to dodge the larger trees..");
if (MechPilot(mech) == -1 || MadePilotSkillRoll(mech,
(int) (fabs(MechSpeed(mech)) / MP1 / 6))) {
mech_notify(mech, MECHALL, "You manage to dodge 'em!");
} else {
mech_notify(mech, MECHALL,
"You swerve, but not enough! This'll hurt!");
MechLOSBroadcast(mech, "cruises headlong at a tree!");
f = fabs(MechSpeed(mech));
MechSpeed(mech) = MechSpeed(mech) / 2.0;
MechFalls(mech, MAX(1, (int) sqrt(f / MP1 / 2)), 0);
}
}
}
/* Slow them if they made an elevation change */
le = elevation - lastelevation;
le = (le < 0) ? -le : le;
if (le > 0) {
deltax = (le == 1) ? MP2 : MP3;
if (MechSpeed(mech) > 0) {
MechSpeed(mech) -= deltax;
if (MechSpeed(mech) < 0)
MechSpeed(mech) = 0;
} else if (MechSpeed(mech) < 0) {
MechSpeed(mech) += deltax;
if (MechSpeed(mech) > 0)
MechSpeed(mech) = 0;
}
}
break;
case MOVE_WHEEL:
/* Cliff ! */
if (collision_check(mech, WALK_WALL, lastelevation, oldterrain)) {
mech_notify(mech, MECHALL,
"You attempt to climb a hill too steep for you.");
if (MechPilot(mech) == -1 || (!mudconf.btech_skidcliff &&
MadePilotSkillRoll(mech,
(int) (fabs((MechSpeed(mech)) + MP1) / MP1) / 3))
|| (mudconf.btech_skidcliff && MadePilotSkillRoll(mech,
SkidMod(fabs(MechSpeed(mech)) / MP1)))) {
mech_notify(mech, MECHALL,
"You manage to stop before crashing.");
MechLOSBroadcast(mech, "stops suddenly to avoid a cliff!");
} else {
if (!mudconf.btech_skidcliff) {
mech_notify(mech, MECHALL, "You smash into a cliff!!");
MechLOSBroadcast(mech, "crashes to a cliff!");
MechFalls(mech, (int) (MechSpeed(mech) * MP_PER_KPH / 4), 0);
} else {
mech_notify(mech, MECHALL,
"You skid to a violent halt!");
MechLOSBroadcast(mech, "skids to a halt!");
MechFalls(mech, 0, 0);
}
}
move_unit_back(mech, deltax, deltay, lastelevation, ot, le);
MechDesiredSpeed(mech) = 0;
MechSpeed(mech) = 0;
return;
} else if (collision_check(mech, WALK_DROP, lastelevation,
oldterrain)) {
mech_notify(mech, MECHALL,
"You notice a large drop in front of you");
avoidbth = mudconf.btech_skidcliff ?
SkidMod(fabs(MechSpeed(mech)) / MP1) :
((fabs((MechSpeed(mech)) + MP1) / MP1) / 3);
if (MechPilot(mech) == -1 || (!MechAutoFall(mech) &&
MadePilotSkillRoll(mech, avoidbth))) {
mech_notify(mech, MECHALL,
"You manage to stop before falling off.");
MechLOSBroadcast(mech,
"stops suddenly to avoid driving off a cliff!");
} else {
mech_notify(mech, MECHALL,
"You drive off the cliff and fall to the ground below.");
MechLOSBroadcast(mech,
"drives off a cliff and falls to the ground below.");
MechFalls(mech, lastelevation - elevation, 0);
domino_space(mech, 2);
if (MechRTerrain(mech) == WATER &&
!(MechSpecials2(mech) & WATERPROOF_TECH)) {
mech_notify(mech, MECHALL,
"You drive into the water and your vehicle becomes inoperable.");
Destroy(mech);
}
return;
}
move_unit_back(mech, deltax, deltay, lastelevation, ot, le);
MechDesiredSpeed(mech) = 0;
MechSpeed(mech) = 0;
return;
} else if (mudconf.btech_roll_on_backwalk &&
(MechSpeed(mech) < 0) &&
(collision_check(mech, WALK_BACK, lastelevation, oldterrain))) {
mech_printf(mech, MECHALL, "You notice a %s behind you!",
(elevation > lastelevation ? "small incline" : "small drop"));
if (MechPilot(mech) == -1 || (MadePilotSkillRoll(mech,
collision_check(mech, WALK_BACK, lastelevation, oldterrain)
- 1))) {
mech_notify(mech, MECHALL,
"You manage to overcome the obstacle.");
} else {
mech_printf(mech, MECHALL, "%s",
(elevation > lastelevation ?
"You stumble on your rear and fall down." :
"You fall on your rear off the small incline."));
MechLOSBroadcast(mech,
tprintf("%s",(elevation > lastelevation ?
"falls on it's back walking up an incline." :
"falls off the back of a small incline.")));
MechFalls(mech, abs(lastelevation - elevation), 1);
MechDesiredSpeed(mech) = 0;
MechSpeed(mech) = 0;
if (elevation > lastelevation) {
move_unit_back(mech, deltax, deltay, lastelevation, ot, le);
}
}
return;
}
if (!(MechSpecials2(mech) & WATERPROOF_TECH) &&
(MechRTerrain(mech) == WATER ||
(MechRTerrain(mech) == BRIDGE && (lastelevation < (elevation - 1)))) &&
elevation < 0) {
mech_notify(mech, MECHALL,
"You notice a body of water in front of you");
if (MechPilot(mech) == -1 ||
MadePilotSkillRoll(mech,
(int) (fabs((MechSpeed(mech)) + MP1) / MP1) / 3)) {
mech_notify(mech, MECHALL,
"You manage to stop before falling in.");
MechLOSBroadcast(mech,
"stops suddenly to driving into the water!");
} else {
mech_notify(mech, MECHALL,
"You drive into the water and your vehicle becomes inoperable.");
Destroy(mech);
return;
}
move_unit_back(mech, deltax, deltay, lastelevation, ot, le);
MechDesiredSpeed(mech) = 0;
MechSpeed(mech) = 0;
return;
}
/* New terrain restrictions */
if (mudconf.btech_newterrain) {
tt = MechRTerrain(mech);
if ((tt == HEAVY_FOREST || tt == LIGHT_FOREST) &&
fabs(MechSpeed(mech)) > MP1) {
#if 0
mech_notify(mech, MECHALL,
"You cruise at a bunch of trees!");
#endif
mech_notify(mech, MECHALL,
"You try to dodge the larger trees..");
if (MechPilot(mech) == -1 ||
MadePilotSkillRoll(mech,
(tt == HEAVY_FOREST ? 3 : 0) +
(fabs(MechSpeed(mech)) / MP1 / 6))) {
mech_notify(mech, MECHALL, "You manage to dodge 'em!");
} else {
mech_notify(mech, MECHALL,
"You swerve, but not enough! This'll hurt!");
MechLOSBroadcast(mech, "cruises headlong at a tree!");
f = fabs(MechSpeed(mech));
MechSpeed(mech) = MechSpeed(mech) / 2.0;
MechFalls(mech, MAX(1, (int) sqrt(f / MP1 / 2)), 0);
}
} else if ((tt == ROUGH) && fabs(MechSpeed(mech)) > MP1) {
#if 0
mech_notify(mech, MECHALL,
"You cruise at some rough terrain!");
#endif
mech_notify(mech, MECHALL, "You try to avoid the rocks..");
if (MechPilot(mech) == -1 || MadePilotSkillRoll(mech,
(int) (fabs(MechSpeed(mech)) / MP1 / 6))) {
mech_notify(mech, MECHALL, "You manage to dodge 'em!");
} else {
mech_notify(mech, MECHALL,
"You swerve, but not enough! This'll hurt!");
MechLOSBroadcast(mech, "cruises headlong at a rock!");
f = fabs(MechSpeed(mech));
MechSpeed(mech) = MechSpeed(mech) / 2.0;
MechFalls(mech, MAX(1, (int) sqrt(f / MP1 / 2)), 0);
}
}
}
/* Slow them down if they change elevations */
le = elevation - lastelevation;
le = (le < 0) ? -le : le;
if (le > 0) {
deltax = (le == 1) ? MP2 : MP3;
if (MechSpeed(mech) > 0) {
MechSpeed(mech) -= deltax;
if (MechSpeed(mech) < 0)
MechSpeed(mech) = 0;
} else if (MechSpeed(mech) < 0) {
MechSpeed(mech) += deltax;
if (MechSpeed(mech) > 0)
MechSpeed(mech) = 0;
}
}
break;
case MOVE_HULL:
case MOVE_FOIL:
case MOVE_SUB:
if ((MechRTerrain(mech) != WATER && MechRTerrain(mech) != BRIDGE)
|| abs(MechElev(mech)) < (abs(MechZ(mech)) + (MechMove(mech) ==
MOVE_FOIL ? -1 : 0))) {
/* Run aground */
MechElev(mech) = le;
MechTerrain(mech) = ot;
mech_notify(mech, MECHALL,
"You attempt to get too close with ground!");
if (MechPilot(mech) == -1 ||
MadePilotSkillRoll(mech,
(int) (fabs((MechSpeed(mech)) + MP1) / MP1) / 3)) {
mech_notify(mech, MECHALL,
"You manage to stop before crashing.");
MechLOSBroadcast(mech,
"stops suddenly to avoid running aground!");
move_unit_back(mech, deltax, deltay, lastelevation, ot, le);
} else {
mech_notify(mech, MECHALL, "You smash into the ground!!");
MechLOSBroadcast(mech, "smashes aground!");
MechFalls(mech, (int) (MechSpeed(mech) * MP_PER_KPH / 4),
0);
}
MechSpeed(mech) = 0;
MechDesiredSpeed(mech) = 0;
MechVerticalSpeed(mech) = 0;
return;
}
if (elevation > 0)
elevation = 0;
break;
case MOVE_HOVER:
if (collision_check(mech, WALK_WALL, lastelevation, oldterrain)) {
MechElev(mech) = le;
MechTerrain(mech) = ot;
mech_notify(mech, MECHALL,
"You attempt to climb a hill too steep for you.");
if (MechPilot(mech) == -1 || (!mudconf.btech_skidcliff &&
MadePilotSkillRoll(mech,
(int) (fabs((MechSpeed(mech)) + MP1) / MP1) / 3))
|| (mudconf.btech_skidcliff && MadePilotSkillRoll(mech,
SkidMod(fabs(MechSpeed(mech)) / MP1)))) {
mech_notify(mech, MECHALL,
"You manage to stop before crashing.");
MechLOSBroadcast(mech, "stops suddenly to avoid a cliff!");
} else {
if (!mudconf.btech_skidcliff) {
mech_notify(mech, MECHALL, "You smash into a cliff!!");
MechLOSBroadcast(mech, "smashes into a cliff!");
MechFalls(mech,
(int) (MechSpeed(mech) * MP_PER_KPH / 4), 0);
} else {
mech_notify(mech, MECHALL,
"You skid to a violent halt!");
MechLOSBroadcast(mech, "Skids to a halt!");
MechFalls(mech, 0, 0);
}
}
move_unit_back(mech, deltax, deltay, lastelevation, ot, le);
MechDesiredSpeed(mech) = 0;
MechSpeed(mech) = 0;
return;
} else if (collision_check(mech, WALK_DROP, lastelevation,
oldterrain)) {
mech_notify(mech, MECHALL,
"You notice a large drop in front of you");
avoidbth = mudconf.btech_skidcliff ?
SkidMod(fabs(MechSpeed(mech)) / MP1) :
((fabs((MechSpeed(mech)) + MP1) / MP1) / 3);
if (MechPilot(mech) == -1 || (!MechAutoFall(mech) &&
MadePilotSkillRoll(mech, avoidbth))) {
mech_notify(mech, MECHALL,
"You manage to stop before falling off.");
MechLOSBroadcast(mech,
"stops suddenly to avoid falling off a cliff!");
} else {
mech_notify(mech, MECHALL,
"You drive off the cliff and fall to the ground below.");
MechLOSBroadcast(mech,
"drives off a cliff and falls to the ground below.");
MechFalls(mech, lastelevation - elevation, 0);
return;
}
move_unit_back(mech, deltax, deltay, lastelevation, ot, le);
MechDesiredSpeed(mech) = 0;
MechSpeed(mech) = 0;
return;
} else if (collision_check(mech, HIT_UNDER_BRIDGE, lastelevation,
oldterrain)) {
mech_notify(mech, MECHALL,
"You notice the underside of the bridge in front of you!");
if (MechPilot(mech) == -1 || (!mudconf.btech_skidcliff &&
MadePilotSkillRoll(mech,
(int) (fabs((MechSpeed(mech)) + MP1) / MP1) / 3))
|| (mudconf.btech_skidcliff &&
MadePilotSkillRoll(mech,
SkidMod(fabs(MechSpeed(mech)) / MP1)))) {
mech_notify(mech, MECHALL,
"You manage to stop before slamming into the bridge.");
MechLOSBroadcast(mech,
"stops suddenly to avoid slamming in the bridge!");
} else {
mech_notify(mech, MECHALL,
"You drive right into the underside of the bridge.");
MechLOSBroadcast(mech,
"drives right into the underside of the bridge.");
MechFalls(mech, 1, 0);
}
move_unit_back(mech, deltax, deltay, lastelevation, ot, le);
MechDesiredSpeed(mech) = 0;
MechSpeed(mech) = 0;
return;
} else if (mudconf.btech_roll_on_backwalk &&
(MechSpeed(mech) < 0) &&
(collision_check(mech, WALK_BACK, lastelevation, oldterrain)) && !isunder) {
mech_printf(mech, MECHALL, "You notice a %s behind you!",
(elevation > lastelevation ? "small incline" : "small drop"));
if (MechPilot(mech) == -1 || (MadePilotSkillRoll(mech,
collision_check(mech, WALK_BACK, lastelevation, oldterrain)
- 1))) {
mech_notify(mech, MECHALL,
"You manage to overcome the obstacle.");
} else {
mech_printf(mech, MECHALL, "%s",
(elevation > lastelevation ?
"You stumble on your rear and fall down." :
"You fall on your rear off the small incline."));
MechLOSBroadcast(mech,
tprintf("%s",(elevation > lastelevation ?
"falls on it's back walking up an incline." :
"falls off the back of a small incline.")));
MechFalls(mech, abs(lastelevation - elevation), 1);
MechDesiredSpeed(mech) = 0;
MechSpeed(mech) = 0;
if (elevation > lastelevation) {
move_unit_back(mech, deltax, deltay, lastelevation, ot, le);
}
}
return;
}
tt = MechRTerrain(mech);
if ((tt == HEAVY_FOREST || tt == LIGHT_FOREST) &&
fabs(MechSpeed(mech)) > MP1) {
#if 0
mech_notify(mech, MECHALL, "You cruise at a bunch of trees!");
#endif
mech_notify(mech, MECHALL,
"You try to dodge the larger trees..");
if (MechPilot(mech) == -1 ||
MadePilotSkillRoll(mech,
(tt == HEAVY_FOREST ? 3 : 0) +
(fabs(MechSpeed(mech)) / MP1 / 6))) {
mech_notify(mech, MECHALL, "You manage to dodge 'em!");
} else {
mech_notify(mech, MECHALL,
"You swerve, but not enough! This'll hurt!");
MechLOSBroadcast(mech, "cruises headlong at a tree!");
f = fabs(MechSpeed(mech));
MechSpeed(mech) = MechSpeed(mech) / 2.0;
MechFalls(mech, MAX(1, (int) sqrt(f / MP1 / 2)), 0);
}
}
/* Slow the unit down if its made an elevation change */
le = elevation - lastelevation;
le = (le < 0) ? -le : le;
if (le > 0) {
deltax = (le == 1) ? MP2 : MP3;
if (MechSpeed(mech) > 0) {
MechSpeed(mech) -= deltax;
if (MechSpeed(mech) < 0)
MechSpeed(mech) = 0;
} else if (MechSpeed(mech) < 0) {
MechSpeed(mech) += deltax;
if (MechSpeed(mech) > 0)
MechSpeed(mech) = 0;
}
}
break;
case MOVE_VTOL:
case MOVE_FLY:
if (Landed(mech) && MechRTerrain(mech) != ROAD &&
MechRTerrain(mech) != BRIDGE && MechRTerrain(mech) != GRASSLAND
&& MechRTerrain(mech) != BUILDING) {
mech_notify(mech, MECHALL,
"You go where no flying thing has ever gone before..");
if (RGotPilot(mech) && MadePilotSkillRoll(mech, 5)) {
mech_notify(mech, MECHALL, "You stop in time!");
move_unit_back(mech, deltax, deltay, lastelevation, ot, le);
} else {
mech_notify(mech, MECHALL,
"Eww.. You've a bad feeling about this.");
MechLOSBroadcast(mech, "crashes!");
MechFalls(mech, 1, 0);
}
MechDesiredSpeed(mech) = 0;
MechSpeed(mech) = 0;
return;
} else if (Landed(mech) && mudconf.btech_roll_on_backwalk &&
(MechSpeed(mech) < 0) &&
(collision_check(mech, WALK_BACK, lastelevation, oldterrain))) {
mech_printf(mech, MECHALL, "You notice a %s behind you!",
(elevation > lastelevation ? "small incline" : "small drop"));
if (MechPilot(mech) == -1 || (MadePilotSkillRoll(mech,
collision_check(mech, WALK_BACK, lastelevation, oldterrain)
- 1))) {
mech_notify(mech, MECHALL, "You manage to overcome the obstacle.");
} else {
mech_printf(mech, MECHALL, "%s", (elevation > lastelevation ?
"You stumble on your rear and fall down." :
"You fall on your rear off the small incline."));
MechLOSBroadcast(mech, tprintf("%s",(elevation > lastelevation ?
"falls on it's back walking up an incline." :
"falls off the back of a small incline.")));
MechFalls(mech, (abs(lastelevation - elevation) + 1000), 1);
MechDesiredSpeed(mech) = 0;
MechSpeed(mech) = 0;
if (elevation > lastelevation) {
move_unit_back(mech, deltax, deltay, lastelevation, ot, le);
}
}
return;
}
if (MechRTerrain(mech) == WATER)
return;
if (MechRTerrain(mech) == LIGHT_FOREST ||
MechRTerrain(mech) == HEAVY_FOREST)
elevation = MechElevation(mech) + 2;
else
elevation = MechElevation(mech);
if (collision_check(mech, JUMP, 0, 0)) {
MechFX(mech) -= deltax;
MechFY(mech) -= deltay;
MechX(mech) = MechLastX(mech);
MechY(mech) = MechLastY(mech);
MechZ(mech) = lastelevation;
MechFZ(mech) = MechZ(mech) * ZSCALE;
MechElev(mech) = le;
MechTerrain(mech) = ot;
mech_notify(mech, MECHALL,
"You attempt to fly over elevation that is too high!!");
if (MechPilot(mech) == -1 || (MadePilotSkillRoll(mech,
(int) (MechFZ(mech) / ZSCALE / 3)) &&
(ot == GRASSLAND || ot == ROAD || ot == BUILDING))) {
mech_notify(mech, MECHALL, "You land safely.");
MechStatus(mech) |= LANDED;
MechSpeed(mech) = 0.0;
MechVerticalSpeed(mech) = 0.0;
} else {
mech_notify(mech, MECHALL,
"You crash into the obstacle and fall from the sky!!!!!");
MechLOSBroadcast(mech,
"crashes into an obstacle and falls from the sky!");
MechFalls(mech, MechsElevation(mech) + 1, 0);
domino_space(mech, 2);
}
}
break;
}
if (!done) {
possible_mine_poof(mech, MINE_STEP);
if (mudconf.btech_fasaadvvhlfire &&
(MechType(mech) == CLASS_VEH_GROUND) &&
(MechTerrain(mech) == FIRE))
checkVehicleInFire(mech, 1);
}
}
void CheckDamage(MECH * wounded)
{
/* should be called from UpdatePilotSkillRolls */
/* this is so that a roll will be made only when the mech takes damage */
int now = muxevent_tick % TURN;
int staggerLevel = 0;
int headingChange = 0;
if (mudconf.btech_newstagger) {
if (StaggerDamage(wounded) <= 0)
return;
staggerLevel = StaggerLevel(wounded);
if (Fallen(wounded) || (MechType(wounded) != CLASS_MECH)) {
if (CheckingStaggerDamage(wounded) ||
(StaggerDamage(wounded) > 0))
StopStaggerCheck(wounded);
return;
}
if (!CheckingStaggerDamage(wounded)) {
if ((Jumping(wounded) && (staggerLevel < 1)) ||
!Jumping(wounded))
StartStaggerCheck(wounded);
}
if (staggerLevel < 1) {
return;
}
SendDebug(tprintf("For %d. StaggerDamage: %d. StaggerLevel: %d.",
wounded->mynum, StaggerDamage(wounded),
StaggerLevel(wounded)));
if (LastStaggerNotify(wounded) < staggerLevel) {
LastStaggerNotify(wounded) = staggerLevel;
if (Jumping(wounded) || OODing(wounded)) {
switch (staggerLevel) {
case 1:
mech_notify(wounded, MECHALL,
"%cy%chThe damage causes you to spin a little in your flight path.%cn");
headingChange = 15;
break;
case 2:
mech_notify(wounded, MECHALL,
"%crThe damage spins you but you maintain your flight!%cn");
MechLOSBroadcast(wounded,
"turns slightly from the damage!");
headingChange = 45;
break;
default:
mech_notify(wounded, MECHALL,
"%cr%chThe damage causes you to spin completely around!%cn");
MechLOSBroadcast(wounded,
"spins around from the damage!");
headingChange = 180;
break;
}
SetFacing(wounded,
AcceptableDegree(MechFacing(wounded) +
headingChange) * ((Roll() >= 6) ? 1 : -1));
} else {
switch (staggerLevel) {
case 1:
mech_notify(wounded, MECHALL,
"%cy%chThe damage causes you to stagger a little.%cn");
break;
case 2:
mech_notify(wounded, MECHALL,
"%crThe damage causes you to stagger even more!%cn");
MechLOSBroadcast(wounded,
"starts to stagger from the damage!");
break;
default:
mech_notify(wounded, MECHALL,
"%cr%chThe damage causes you to stagger violently while attempting to keep your footing!%cn");
MechLOSBroadcast(wounded,
"staggers back and forth attempting to keep its footing!");
break;
}
}
}
} else {
if (!IsDS(wounded) && MechTurnDamage(wounded) >= 20 &&
(!MechStaggeredLastTurn(wounded) ||
MechStaggerStamp(wounded) == now)) {
if (!Jumping(wounded) && !Fallen(wounded) && !OODing(wounded)) {
mech_notify(wounded, MECHALL,
"You stagger from the damage!");
if (!MadePilotSkillRoll(wounded, 1)) {
mech_notify(wounded, MECHALL,
"You fall over from all the damage!!");
MechLOSBroadcast(wounded,
"falls down, staggered by the damage!");
MechFalls(wounded, 1, 0);
}
}
MechTurnDamage(wounded) = 0;
SetMechStaggerStamp(wounded, now);
return;
}
if ((MechStaggeredLastTurn(wounded) &&
MechStaggerStamp(wounded) == now) ||
(!MechStaggeredLastTurn(wounded) && !now)) {
MechTurnDamage(wounded) = 0;
SetMechStaggerStamp(wounded, -1);
}
}
}
void UpdatePilotSkillRolls(MECH * mech)
{
int makeroll = 0, grav = 0;
float maxspeed;
if (((muxevent_tick % TURN) == 0) && !Fallen(mech) && !Jumping(mech) &&
!OODing(mech))
/* do this once a turn (30 secs), only if mech is standing */
{
maxspeed = MMaxSpeed(mech);
if (!Started(mech))
makeroll = 4;
if ((MechHeat(mech) >= 9.) &&
(MechSpecials(mech) & TRIPLE_MYOMER_TECH))
maxspeed =
ceil((rint((MMaxSpeed(mech) / 1.5) / MP1) +
1) * 1.5) * MP1;
/* maxspeed += 1.5 * MP1; */
#ifndef BT_MOVEMENT_MODES
if (InSpecial(mech) && InGravity(mech))
#else
if (InSpecial(mech) && InGravity(mech) && !MoveModeChange(mech))
#endif
if (MechSpeed(mech) > MechMaxSpeed(mech) &&
MechType(mech) == CLASS_MECH) {
grav = 1;
makeroll = 1;
}
if (IsRunning(MechSpeed(mech), maxspeed) &&
((MechCritStatus(mech) & GYRO_DAMAGED) ||
(MechCritStatus(mech) & HIP_DAMAGED)))
makeroll = 1;
if (makeroll) {
if (!MadePilotSkillRoll(mech, (makeroll - 1))) {
if (grav) {
int dam = (MechSpeed(mech) - MechMaxSpeed(mech)) / MP1 + 1;
mech_notify(mech, MECHALL,
"Your legs take some damage!");
if (MechIsQuad(mech)) {
if (!SectIsDestroyed(mech, LARM))
DamageMech(mech, mech, 0, -1, LARM, 0, 0, 0,
dam, 0, 0, -1, 0, 1);
if (!SectIsDestroyed(mech, RARM))
DamageMech(mech, mech, 0, -1, RARM, 0, 0, 0,
dam, 0, 0, -1, 0, 1);
}
if (!SectIsDestroyed(mech, LLEG))
DamageMech(mech, mech, 0, -1, LLEG, 0, 0, 0,
dam, 0, 0, -1, 0, 1);
if (!SectIsDestroyed(mech, RLEG))
DamageMech(mech, mech, 0, -1, RLEG, 0, 0, 0,
dam, 0, 0, -1, 0, 1);
} else {
mech_notify(mech, MECHALL,
"Your damaged mech falls as you try to run");
MechLOSBroadcast(mech, "falls down.");
MechFalls(mech, 1, 0);
}
}
}
}
if (MechType(mech) == CLASS_MECH)
CheckDamage(mech);
else
MechTurnDamage(mech) = 0;
if ((muxevent_tick % TURN) == 0) {
if (Started(mech) && MechMove(mech) != MOVE_NONE)
CheckGenericFail(mech, -1, NULL, NULL);
}
}
void updateAutoturnTurret(MECH * mech)
{
MECH *target;
int bearing;
float fx, fy;
if (!Started(mech) || Uncon(mech) || Blinded(mech))
return;
if ((MechTankCritStatus(mech) & TURRET_JAMMED) ||
(MechTankCritStatus(mech) & TURRET_LOCKED))
return;
if (!GetSectInt(mech, TURRET))
return;
if (MechTarget(mech) == -1 && (MechTargY(mech) == -1 ||
MechTargX(mech) == -1))
return;
if (MechTarget(mech) != -1) {
target = getMech(MechTarget(mech));
fx = MechFX(target);
fy = MechFY(target);
} else {
MapCoordToRealCoord(MechTargX(mech), MechTargY(mech), &fx, &fy);
}
bearing =
AcceptableDegree(FindBearing(MechFX(mech), MechFY(mech), fx,
fy) - MechFacing(mech));
MechTurretFacing(mech) = bearing;
MarkForLOSUpdate(mech);
}
/* This function is called once every second for every mech in the game */
void mech_update(dbref key, void *data)
{
MECH *mech = (MECH *) data;
if (!mech)
return;
MechStatus(mech) &= ~FIRED;
if (is_aero(mech)) {
aero_update(mech);
return;
}
if (Started(mech) || Uncon(mech))
UpdatePilotSkillRolls(mech);
if (Started(mech) || MechPlusHeat(mech) > 0.1)
UpdateHeat(mech);
if (Started(mech))
MechVisMod(mech) =
BOUNDED(0, MechVisMod(mech) + Number(-40, 40), 100);
checkECM(mech);
checkTAG(mech);
end_lite_check(mech);
if (MechStatus2(mech) & AUTOTURN_TURRET)
updateAutoturnTurret(mech);
}