btmux-0.6-rc4/doc/
btmux-0.6-rc4/event/
btmux-0.6-rc4/game/
btmux-0.6-rc4/game/maps/
btmux-0.6-rc4/game/mechs/
btmux-0.6-rc4/game/text/help/
btmux-0.6-rc4/game/text/help/cat_faction/
btmux-0.6-rc4/game/text/help/cat_inform/
btmux-0.6-rc4/game/text/help/cat_misc/
btmux-0.6-rc4/game/text/help/cat_mux/
btmux-0.6-rc4/game/text/help/cat_mux/cat_commands/
btmux-0.6-rc4/game/text/help/cat_mux/cat_functions/
btmux-0.6-rc4/game/text/help/cat_templates/
btmux-0.6-rc4/game/text/wizhelp/
btmux-0.6-rc4/include/
btmux-0.6-rc4/misc/
btmux-0.6-rc4/python/
btmux-0.6-rc4/src/hcode/btech/
btmux-0.6-rc4/tree/
/*
 * Author: Markus Stenberg <fingon@iki.fi>
 *
 *  Copyright (c) 1996 Markus Stenberg
 *  Copyright (c) 1998-2002 Thomas Wouters
 *  Copyright (c) 2000-2002 Cord Awtry
 *  Copyright (c) 1999-2005 Kevin Stevens
 *       All rights reserved
 */

#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sys/file.h>

#include "mech.h"
#include "mech.events.h"
#include "p.mech.events.h"
#include "p.mech.ice.h"
#include "p.mech.utils.h"
#include "p.mine.h"
#include "p.bsuit.h"
#include "p.mech.los.h"
#include "p.mech.update.h"
#include "p.mech.physical.h"
#include "p.mech.combat.h"
#include "p.mech.combat.misc.h"
#include "p.mech.damage.h"
#include "p.btechstats.h"
#include "p.mech.hitloc.h"
#include "p.template.h"
#include "p.map.conditions.h"
#include "p.mech.fire.h"
#include "mech.events.h"

struct {
	char *name;
	char *full;
	int ofs;
} lateral_modes[] = {
	{
	"nw", "Front/Left", 300}, {
	"fl", "Front/Left", 300}, {
	"ne", "Front/Right", 60}, {
	"fr", "Front/Right", 60}, {
	"sw", "Rear/Left", 240}, {
	"rl", "Rear/Left", 240}, {
	"se", "Rear/Right", 120}, {
	"rr", "Rear/Right", 120}, {
	"-", "None", 0}, {
	NULL, 0}
};

const char *LateralDesc(MECH * mech)
{
	int i;

	for(i = 0; MechLateral(mech) != lateral_modes[i].ofs; i++);
	return lateral_modes[i].full;
}

void mech_lateral(dbref player, void *data, char *buffer)
{
	MECH *mech = (MECH *) data;
	int i;

	cch(MECH_USUALO);
#ifndef BT_MOVEMENT_MODES
	DOCHECK(MechType(mech) != CLASS_MECH ||
			!MechIsQuad(mech),
			"Only quadrupeds can alter their lateral movement!");
#else
	DOCHECK(!((MechType(mech) == CLASS_MECH && MechIsQuad(mech)) ||
			  (MechType(mech) == CLASS_VTOL) ||
			  (MechMove(mech) == MOVE_HOVER)),
			"You cannot alter your lateral movement!");
#endif
	DOCHECK(CountDestroyedLegs(mech) > 0,
			"You need all four legs to use lateral movement!");
	skipws(buffer);

	for(i = 0; lateral_modes[i].name; i++)
		if(!strcasecmp(lateral_modes[i].name, buffer))
			break;
	DOCHECK(!lateral_modes[i].name, "Invalid mode!");
	if(lateral_modes[i].ofs == MechLateral(mech)) {
		DOCHECK(!ChangingLateral(mech), "You are going that way already!");
		mech_notify(mech, MECHALL, "Lateral mode change aborted.");
		StopLateral(mech);
		return;
	}
	mech_printf(mech, MECHALL,
				"Wanted lateral movement mode changed to %s.",
				lateral_modes[i].full);
	StopLateral(mech);
	MECHEVENT(mech, EVENT_LATERAL, mech_lateral_event, LATERAL_TICK, i);
}
void mech_turnmode(dbref player, void *data, char *buffer)
{
	MECH *mech = (MECH *) data;

	if(!GotPilot(mech) || MechPilot(mech) != player) {
		notify(player, "You're not the pilot!");
		return;
	}

	if(!HasBoolAdvantage(player, "maneuvering_ace")) {
		mech_notify(mech, MECHPILOT, "You're not skilled enough to do that.");
		return;
	}

	if(buffer && !strcasecmp(buffer, "tight")) {
		SetTurnMode(mech, 1);
		mech_notify(mech, MECHALL, "You brace for tighter turns.");
		return;
	}
	if(buffer && !strcasecmp(buffer, "normal")) {
		SetTurnMode(mech, 0);
		mech_notify(mech, MECHALL, "You assume a normal turn mode.");
		return;
	}
	mech_printf(mech, MECHALL, "Your turning type is : %s",
				GetTurnMode(mech) ? "TIGHT" : "NORMAL");
	return;
}

void mech_bootlegger(dbref player, void *data, char *buffer)
{
	MECH *mech = (MECH *) data;
	float fMinSpeed = (4 * MP1);
	int wBTHMod = 0;
	int wFallLevels = 0;
	int i;
	int wHeadingChange = 0;
	int wNewHeading;
	float fMechSpeed = MechSpeed(mech);
	int wMechTons = MechTons(mech);
	char strLocation[50];
	char *args[1];

	cch(MECH_USUALO);

	DOCHECK(mech_parseattributes(buffer, args, 1) != 1,
			"Invalid number of arguments!");
	DOCHECK(CountDestroyedLegs(mech) > 0,
			"You can't perform a bootlegger with destroyed legs!");
	DOCHECK(fMechSpeed < fMinSpeed,
			tprintf
			("You are going too slow to perform a bootlegger! The required minimum speed is %4.1f KPH.",
			 fMinSpeed));

	switch (toupper(args[0][0])) {
	case 'R':
		wHeadingChange = 90;
		break;
	case 'L':
		wHeadingChange = -90;
		break;
	}

	DOCHECK(wHeadingChange == 0, "Invalid turn direction!");

	for(i = 0; i < NUM_SECTIONS; i++) {
		if((i == LLEG) || (i == RLEG) || (MechIsQuad(mech) && ((i == LARM)
															   || (i ==
																   RARM)))) {
			ArmorStringFromIndex(i, strLocation, MechType(mech),
								 MechMove(mech));

			if(SectHasBusyWeap(mech, i)) {
				mech_printf(mech, MECHALL,
							"You have weapons recycling in your %s.",
							strLocation);
				return;
			}

			if(MechSections(mech)[i].recycle) {
				mech_printf(mech, MECHALL,
							"Your %s is still recovering from its last action.",
							strLocation);
				return;
			}

			wBTHMod += MechSections(mech)[i].basetohit;
		}
	}

	if(fMechSpeed <= (4 * MP1)) {
		wBTHMod += 0;
	} else if(fMechSpeed <= (8 * MP1)) {
		wBTHMod += 1;
	} else if(fMechSpeed <= (12 * MP1)) {
		wBTHMod += 2;
	} else {
		wBTHMod += 3;
	}

	if(wMechTons <= 35) {
		wBTHMod += 0;
	} else if(wMechTons <= 55) {
		wBTHMod += 1;
	} else if(wMechTons <= 75) {
		wBTHMod += 2;
	} else {
		wBTHMod += 3;
	}

	wBTHMod += (InWater(mech) ? 2 : 0);

	wBTHMod = MAX(wBTHMod, 1);

	skipws(buffer);

	SendDebug(tprintf
			  ("#%d attempts to do a bootlegger (mech). Tonnage: %d, Speed: %4.1f, BTHMod: %d",
			   mech->mynum, wMechTons, fMechSpeed, wBTHMod));

	if(MadePilotSkillRoll(mech, wBTHMod)) {
		wNewHeading = AcceptableDegree(MechFacing(mech) + wHeadingChange);

		SetFacing(mech, wNewHeading);
		MechDesiredFacing(mech) = wNewHeading;
		MechSpeed(mech) = MechSpeed(mech) / 2;

		mech_printf(mech, MECHALL,
					"You plant a foot and swivel, changing your heading to %d.",
					wNewHeading);

		for(i = 0; i < NUM_SECTIONS; i++) {
			if((i == LLEG) || (i == RLEG) || (MechIsQuad(mech) &&
											  ((i == LARM) || (i == RARM))))
				SetRecycleLimb(mech, i, 30);
		}

	} else {
		wFallLevels = MAX(wBTHMod, 1);

		mech_notify(mech, MECHALL, "You plant a foot and try to swivel...");
		mech_notify(mech, MECHALL,
					"... but realize a little late that this is harder than it looks!");
		MechLOSBroadcast(mech,
						 "attempts to fight the forces of inertia but looses the battle miserably!");

		if(wFallLevels > 2)
			MechLOSBroadcast(mech, "tumbles over and over and over!");

		MechFalls(mech, wFallLevels, 1);
	}
}

void mech_eta(dbref player, void *data, char *buffer)
{
	MECH *mech = (MECH *) data;
	MAP *mech_map;
	int argc, eta_x, eta_y;
	float fx, fy, range;
	int etahr, etamin;
	char *args[3];

	cch(MECH_USUAL);
	mech_map = getMap(mech->mapindex);
	argc = mech_parseattributes(buffer, args, 2);
	DOCHECK(argc == 1, "Invalid number of arguments!");
	switch (argc) {
	case 0:
		DOCHECK(!(MechTargX(mech) >= 0 &&
				  MechTarget(mech) < 0),
				"You have invalid default target for ETA!");
		eta_x = MechTargX(mech);
		eta_y = MechTargY(mech);
		break;
	case 2:
		eta_x = atoi(args[0]);
		eta_y = atoi(args[1]);
		break;
	default:
		notify(player, "Invalid arguments!");
		return;
	}
	MapCoordToRealCoord(eta_x, eta_y, &fx, &fy);
	range = FindRange(MechFX(mech), MechFY(mech), 0, fx, fy, 0);
	if(fabs(MechSpeed(mech)) < 0.1)
		mech_printf(mech, MECHALL,
					"Range to hex (%d,%d) is %.1f.  ETA: Never, mech not moving.",
					eta_x, eta_y, range);
	else {
		etamin = abs(range / (MechSpeed(mech) / KPH_PER_MP));
		etahr = etamin / 60;
		etamin = etamin % 60;
		mech_printf(mech, MECHALL,
					"Range to hex (%d,%d) is %.1f.  ETA: %.2d:%.2d.",
					eta_x, eta_y, range, etahr, etamin);
	}
}

float MechCargoMaxSpeed(MECH * mech, float mspeed)
{
	int lugged = 0, mod = 2;
	MECH *c;
	MAP *map;

	if(MechCarrying(mech) > 0) {	/* Ug-lee! */
		MECH *t;

		if((t = getMech(MechCarrying(mech))))
			if(!(MechCritStatus(t) & OWEIGHT_OK))
				MechCritStatus(mech) &= ~LOAD_OK;

	}

	/*! \todo {Fix this calculation to include gravity and TSM for
	 * when BT_MOVMENT_MODES is enabled} */
	if((MechCritStatus(mech) & LOAD_OK) &&
	   (MechCritStatus(mech) & OWEIGHT_OK) &&
	   (MechCritStatus(mech) & SPEED_OK)) {

		mspeed = MechRMaxSpeed(mech);
#ifndef BT_MOVEMENT_MODES

		/* Is masc and/or scharge on */
		if((MechStatus(mech) & MASC_ENABLED) &&
		   (MechStatus(mech) & SCHARGE_ENABLED))
			mspeed = ceil((rint(mspeed / 1.5) / MP1) * 2.5) * MP1;
		else if(MechStatus(mech) & MASC_ENABLED)
			mspeed *= 4. / 3.;
		else if(MechStatus(mech) & SCHARGE_ENABLED)
			mspeed *= 4. / 3.;

		if(InSpecial(mech) && InGravity(mech))
			if((map = FindObjectsData(mech->mapindex)))
				mspeed = mspeed * 100 / MAX(50, MapGravity(map));

#else
		/* Is masc and/or scharge and/or sprinting on */
		if(MechStatus(mech) & (MASC_ENABLED | SCHARGE_ENABLED) ||
		   MechStatus2(mech) & SPRINTING)
			mspeed = WalkingSpeed(mspeed) * (1.5 +
											 (MechStatus(mech) & MASC_ENABLED
											  ? 0.5 : 0.0) +
											 (MechStatus(mech) &
											  SCHARGE_ENABLED ? 0.5 : 0.0) +
											 (!MoveModeChange(mech)
											  && MechStatus2(mech) & SPRINTING
											  ? 0.5 : 0.0));

		/* if the player has speed demon give him his boost in speed */
		if(!MoveModeChange(mech) && MechStatus2(mech) & SPRINTING
		   && HasBoolAdvantage(MechPilot(mech), "speed_demon"))
			mspeed += MP1;
#endif
		return mspeed;
	}
	MechRTonsV(mech) = get_weight(mech);

	/*! \todo {Check some of this math better} */
	if(!(MechCritStatus(mech) & LOAD_OK)) {
		if(MechCarrying(mech) > 0)
			if((c = getMech(MechCarrying(mech)))) {
				lugged = get_weight(c) * 2;
				if(MechSpecials(mech) & SALVAGE_TECH)
					lugged = lugged / 2;
				if((MechSpecials(mech) & TRIPLE_MYOMER_TECH) &&
				   (MechHeat(mech) >= 9.))
					lugged = lugged / 2;

				if(MechSpecials2(mech) & CARRIER_TECH)
					lugged = lugged / 2;
			}

		if(MechSpecials(mech) & CARGO_TECH)
			mod = 1;

		if(MechType(mech) == CLASS_MECH)
			mod = mod * 2;

		lugged += MechCarriedCargo(mech) * mod / 2;
		MechRCTonsV(mech) = lugged;
		MechCritStatus(mech) |= LOAD_OK;
	}
	if(Destroyed(mech))
		mspeed = 0.0;
	else {
		int mv = MechRTonsV(mech);
		int sv = MechTons(mech) * 1024;

		if(mv == 1 && !Destroyed(mech))
			mv = sv;
		else {
			if(mv > sv)
				mv = mv + (mv - sv) / 2;
			else
				mv = mv + (sv - mv) / 3;
		}
		if(3 * sv < (MechRCTonsV(mech) + mv))
			mspeed = 0.0;
		else
#ifdef WEIGHT_OVERSPEEDING
			mspeed =
				MechMaxSpeed(mech) * MechTons(mech) * 1024.0 / MAX(1024 *
																   MechRealTons
																   (mech) +
																   MechRCTonsV
																   (mech) / 3,
																   (MAX
																	(1024,
																	 mv +
																	 MechRCTonsV
																	 (mech))));
#else
			mspeed =
				MechMaxSpeed(mech) * MechTons(mech) * 1024.0 / MAX(1024 *
																   MechTons
																   (mech) +
																   MechRCTonsV
																   (mech) / 3,
																   (MAX
																	(1024,
																	 mv +
																	 MechRCTonsV
																	 (mech))));
#endif /* WEIGHT_OVERSPEEDING */
	}
	MechRMaxSpeed(mech) = mspeed;
	MechWalkXPFactor(mech) = MAX(1, (int) mspeed / MP1) * 2;
	MechCritStatus(mech) |= SPEED_OK;
	return MMaxSpeed(mech);
}

void mech_drop(dbref player, void *data, char *buffer)
{
	MECH *mech = (MECH *) data;
	float s1;
	int wDropLevels = 0;
	int wDropBTH = 0;
	int tHasSwarmers = 0;

	cch(MECH_USUAL);
	DOCHECK(MechType(mech) == CLASS_BSUIT, "No crawling!");
	DOCHECK(MechType(mech) != CLASS_MECH &&
			MechType(mech) != CLASS_MW, "You can't prone in this!");
	DOCHECK(Fallen(mech), "You are already prone.");
	DOCHECK(Jumping(mech) || OODing(mech), "You can't prone in the air!");
	DOCHECK(Standing(mech), "You can't drop while trying to stand up!");

	s1 = MMaxSpeed(mech) / 3.0;

	if((MechType(mech) == CLASS_MECH) && CountSwarmers(mech))
		tHasSwarmers = 1;

	if(MechType(mech) != CLASS_MW && fabs(MechSpeed(mech)) > s1 * 2) {
		mech_notify(mech, MECHALL,
					"You attempt a controlled drop while running.");
		wDropLevels = 2;
		wDropBTH = 2;
	} else if(fabs(MechSpeed(mech)) > s1) {
		mech_notify(mech, MECHALL,
					"You attempt a controlled drop from your fast walk.");
		wDropLevels = 1;
	}

	if(Staggering(mech)) {
		mech_notify(mech, MECHALL,
					"Still staggering, you try not to fall on your face.");
		wDropLevels = (wDropLevels == 0 ? 1 : wDropLevels);
		wDropBTH = wDropBTH + StaggerLevel(mech);
	}

	if(tHasSwarmers)
		mech_notify(mech, MECHALL,
					"The suits hanging off you make a controlled drop harder!");

	if((wDropLevels > 0) || tHasSwarmers) {
		if(MadePilotSkillRoll(mech, wDropBTH)) {
			mech_notify(mech, MECHALL,
						"You hit the ground with minimal damage");
			MechLOSBroadcast(mech, "drops to the ground!");

			if(tHasSwarmers)
				StopBSuitSwarmers(FindObjectsData(mech->mapindex), mech, 0);

		} else {
			mech_notify(mech, MECHALL, "You fall to the ground hard");
			MechLOSBroadcast(mech, "falls hard to the ground!");

			if(wDropLevels <= 0)
				wDropLevels = 1;

			if(tHasSwarmers)
				StopBSuitSwarmers(FindObjectsData(mech->mapindex), mech, 0);

			MechFalls(mech, wDropLevels, 1);
		}
	} else {
		mech_notify(mech, MECHALL, "You drop to the ground prone!");
		MechLOSBroadcast(mech, "drops to the ground!");
	}

	MakeMechFall(mech);
	MechDesiredSpeed(mech) = 0;
	MechSpeed(mech) = 0;
	MechFloods(mech);
	water_extinguish_inferno(mech);

	possible_mine_poof(mech, MINE_STEP);
}

void mech_stand(dbref player, void *data, char *buffer)
{
	MECH *mech = (MECH *) data;
	char *args[2];
	int wcDeadLegs = 0;
	int tNeedsPSkill = 1;
	int tDoStand = 1;
	int bth, mechstandtime, standanyway = 0, standcarefulmod = 0;
	int i;

	cch(MECH_USUAL);
	DOCHECK(MechType(mech) == CLASS_BSUIT, "You're standing already!");
	DOCHECK(MechType(mech) != CLASS_MECH &&
			MechType(mech) != CLASS_MW,
			"This vehicle cannot stand like a 'Mech.");
	DOCHECK(Jumping(mech), "You're standing while jumping!");
	DOCHECK(OODing(mech), "You're standing while flying!");

	/* set the number of dead legs we have */
	wcDeadLegs = CountDestroyedLegs(mech);

	DOCHECK(((MechIsQuad(mech) && (wcDeadLegs > 3)) || (!MechIsQuad(mech)
														&& (wcDeadLegs > 1))),
			"You have no legs to stand on!");
	DOCHECK(wcDeadLegs > 2, "You'd be far too unstable!");
	DOCHECK(MechCritStatus(mech) & GYRO_DESTROYED,
			"You cannot stand with a destroyed gyro!");

	DOCHECK(!Fallen(mech), "You're already standing!");
	DOCHECK(Standrecovering(mech),
			"You're still recovering from your last attempt!");
	DOCHECK(IsHulldown(mech), "You can not stand while hulldown");
	DOCHECK(ChangingHulldown(mech),
			"You are busy changing your hulldown mode");

	bth = MechPilotSkillRoll_BTH(mech, 0);

	/* Check to see if the user specified an argument for the command */
	if(proper_explodearguments(buffer, args, 2)) {
		if(strcmp(args[0], "check") == 0) {
			notify_printf(player, "Your BTH to stand would be: %d", bth);
			for(i = 0; i < 2; i++) {
				if(args[i])
					free(args[i]);
			}
			return;
		} else if(strcmp(args[0], "anyway") == 0) {
			standanyway = 1;
		} else if(strcmp(args[0], "careful") == 0) {
			standcarefulmod = -2;
		} else {
			notify(player, "Unknown argument! use 'stand check', "
				   "'stand anyway', or 'stand careful'");
			for(i = 0; i < 2; i++) {
				if(args[i])
					free(args[i]);
			}
			return;
		}
	}

	DOCHECK(!standanyway && bth > 12,
			"You would fail; use 'stand anyway' if you really want to stand.");

	MakeMechStand(mech);

	/*  quads with all 4 legs don't have to roll to stand */
	if(((wcDeadLegs == 0) && MechIsQuad(mech)) ||
	   (MechType(mech) == CLASS_MW)) {
		tNeedsPSkill = 0;
	}

	MechLOSBroadcast(mech, "attempts to stand up.");

	if(MechRTerrain(mech) == ICE && MechZ(mech) == -1)
		break_thru_ice(mech);

	if(tNeedsPSkill) {
		if(!MadePilotSkillRoll(mech, standcarefulmod)) {
			mech_notify(mech, MECHALL,
						"You fail your attempt to stand and fall back on the ground");
			MechFalls(mech, 1, 1);
			mechstandtime = ((MechType(mech) == CLASS_MW) ?
							 DROP_TO_STAND_RECYCLE / 3 : StandMechTime(mech));
			/* Not strictly FASA, but allows legged mechs to stand careful */
			if(standcarefulmod) {
				mechstandtime = MAX(30, mechstandtime * 2);
			}
			MECHEVENT(mech, EVENT_STANDFAIL, mech_standfail_event,
					  mechstandtime, 0);
			tDoStand = 0;
		}
	}

	if(tDoStand) {
		/* Now we set a counter in goingy to keep him from moving or jumping until he is finished standing */
		mech_notify(mech, MECHALL, "You begin to stand up.");
		mechstandtime = ((MechType(mech) == CLASS_MW) ?
						 DROP_TO_STAND_RECYCLE / 3 : StandMechTime(mech));
		/* Not strictly FASA, but allows legged mechs to stand careful */
		if(standcarefulmod) {
			mechstandtime = mechstandtime * 2;
		}
		MECHEVENT(mech, EVENT_STAND, mech_stand_event, mechstandtime, 0);
	}
	/* Free args */
	for(i = 0; i < 2; i++) {
		if(args[i])
			free(args[i]);
	}

}

void mech_land(dbref player, void *data, char *buffer)
{
	MECH *mech = (MECH *) data;

	cch(MECH_USUAL);
	if(MechType(mech) != CLASS_MECH && MechType(mech) != CLASS_MW &&
	   MechType(mech) != CLASS_BSUIT && MechType(mech) != CLASS_VEH_GROUND) {
		aero_land(player, data, buffer);
		return;
	}
	if(Jumping(mech)) {
		mech_notify(mech, MECHALL,
					"You abort your full jump and attempt to land early");
		if(MadePilotSkillRoll(mech, 0)) {
			mech_notify(mech, MECHALL, "You are able to abort the jump.");

/*        MechLOSBroadcast (mech, "lands abruptly!"); */
			LandMech(mech);
		} else {
			mech_notify(mech, MECHALL, "You don't quite make it.");
			MechLOSBroadcast(mech,
							 "attempts a landing, but crashes to the ground!");
			MechFalls(mech, 1, 0);
			MechDFATarget(mech) = -1;
			MechGoingX(mech) = MechGoingY(mech) = 0;
			MechSpeed(mech) = 0;
			MaybeMove(mech);

		}
	} else
		notify(player, "You're not jumping!");
}

/* Facing related */
void mech_heading(dbref player, void *data, char *buffer)
{
	MECH *mech = (MECH *) data;
	char *args[1];
	int newheading;

	cch(MECH_USUAL);
	if(mech_parseattributes(buffer, args, 1) == 1) {
		DOCHECK(MechMove(mech) == MOVE_NONE,
				"This piece of equipment is stationary!");
		DOCHECK(WaterBeast(mech) &&
				NotInWater(mech),
				"You are regrettably unable to move at this time. We apologize for the inconvenience.");
		DOCHECK(is_aero(mech) && Spinning(mech) &&
				!Landed(mech),
				"You are unable to control your craft at the moment.");
		DOCHECK(PerformingAction(mech),
				"You are too busy at the moment to turn.");
		DOCHECK(MechDugIn(mech),
				"You are in a hole you dug, unable to move [use speed cmd to get out].");
		DOCHECK(IsHulldown(mech), "You can not turn while hulldown");
		DOCHECK(ChangingHulldown(mech),
				"You are busy changing your hulldown mode");
		if(Digging(mech)) {
			mech_notify(mech, MECHALL,
						"You cease your attempts at digging in.");
			StopDigging(mech);
		}
		newheading = AcceptableDegree(atoi(args[0]));
		MechDesiredFacing(mech) = newheading;
		mech_printf(mech, MECHALL, "Heading changed to %d.", newheading);
		MaybeMove(mech);
	} else {
		notify_printf(player, "Your current heading is %i.",
					  MechFacing(mech));
	}
}

void mech_turret(dbref player, void *data, char *buffer)
{
	MECH *mech = (MECH *) data;
	char *args[1];
	int newheading;

	cch(MECH_USUALO);
	DOCHECK(MechType(mech) == CLASS_MECH || MechType(mech) == CLASS_MW ||
			MechType(mech) == CLASS_BSUIT || is_aero(mech) ||
			!GetSectInt(mech, TURRET), "You don't have a turret.");
	DOCHECK(MechTankCritStatus(mech) & TURRET_JAMMED,
			"Your turret is jammed in position.");
	DOCHECK(MechTankCritStatus(mech) & TURRET_LOCKED,
			"Your turret is locked in position.");
	if(mech_parseattributes(buffer, args, 1) == 1) {
		newheading = AcceptableDegree(atoi(args[0]) - MechFacing(mech));
		MechTurretFacing(mech) = newheading;
		mech_printf(mech, MECHALL, "Turret facing changed to %d.",
					AcceptableDegree(MechTurretFacing(mech) +
									 MechFacing(mech)));
	} else {
		notify_printf(player, "Your turret is currently facing %d.",
					  AcceptableDegree(MechTurretFacing(mech) +
									   MechFacing(mech)));
	}

	MarkForLOSUpdate(mech);
}

void mech_rotatetorso(dbref player, void *data, char *buffer)
{
	MECH *mech = (MECH *) data;
	char *args[2];

	cch(MECH_USUALO);
	DOCHECK(MechType(mech) == CLASS_BSUIT, "Huh?");
	DOCHECK(MechType(mech) != CLASS_MECH &&
			MechType(mech) != CLASS_MW, "You don't have a torso.");
	DOCHECK(Fallen(mech),
			"You're lying flat on your face, you can't rotate your torso.");
	DOCHECK((MechType(mech) == CLASS_MECH) &&
			(MechIsQuad(mech)), "Quads can't rotate their torsos.");
	if(mech_parseattributes(buffer, args, 2) == 1) {
		switch (args[0][0]) {
		case 'L':
		case 'l':
			DOCHECK(MechStatus(mech) & TORSO_LEFT,
					"You cannot rotate torso beyond 60 degrees!");
			if(MechStatus(mech) & TORSO_RIGHT)
				MechStatus(mech) &= ~TORSO_RIGHT;
			else
				MechStatus(mech) |= TORSO_LEFT;
			mech_notify(mech, MECHALL, "You rotate your torso left.");
			break;
		case 'R':
		case 'r':
			DOCHECK(MechStatus(mech) & TORSO_RIGHT,
					"You cannot rotate torso beyond 60 degrees!");
			if(MechStatus(mech) & TORSO_LEFT)
				MechStatus(mech) &= ~TORSO_LEFT;
			else
				MechStatus(mech) |= TORSO_RIGHT;
			mech_notify(mech, MECHALL, "You rotate your torso right.");
			break;
		case 'C':
		case 'c':
			MechStatus(mech) &= ~(TORSO_RIGHT | TORSO_LEFT);
			mech_notify(mech, MECHALL, "You center your torso.");
			break;
		default:
			notify(player, "Rotate must have LEFT RIGHT or CENTER.");
			break;
		}
	} else
		notify(player, "Invalid number of arguments!");
	MarkForLOSUpdate(mech);
}

struct {
	char *name;
	int flag;
} speed_tables[] = {
	{
	"walk", 1}, {
	"run", 2}, {
	"stop", 0}, {
	"back", -1}, {
	"cruise", 1}, {
	"flank", 2}, {
	NULL, 0.0}
};

void mech_speed(dbref player, void *data, char *buffer)
{
	MECH *mech = (MECH *) data;
	char *args[1];
	float newspeed, walkspeed, maxspeed;
	int i;

	cch(MECH_USUAL);
	if(RollingT(mech)) {
		DOCHECK(!Landed(mech), "Use thrust command instead!");
	} else if(FlyingT(mech)) {
		DOCHECK(MechType(mech) != CLASS_VTOL, "Use thrust command instead!");
	}
	DOCHECK(MechMove(mech) == MOVE_NONE,
			"This piece of equipment is stationary!");
	DOCHECK(PerformingAction(mech),
			"You are too busy at the moment to turn.");
	DOCHECK(Standing(mech), "You are currently standing up and cannot move.");
	DOCHECK((Fallen(mech)) && (MechType(mech) != CLASS_MECH &&
							   MechType(mech) != CLASS_MW),
			"Your vehicle's movement system is destroyed.");
	DOCHECK(Fallen(mech), "You are currently prone and cannot move.");
	DOCHECK(WaterBeast(mech) &&
			NotInWater(mech),
			"You are regrettably unable to move at this time. We apologize for the inconvenience.");

	if(MechType(mech) != CLASS_MECH)
		DOCHECK(RemovingPods(mech), "You are too busy removing iNARC pods!");
	DOCHECK(IsHulldown(mech), "You can not move while hulldown");
	DOCHECK(ChangingHulldown(mech),
			"You are busy changing your hulldown mode");

	if(mech_parseattributes(buffer, args, 1) != 1) {
		notify_printf(player, "Your current speed is %.2f.", MechSpeed(mech));
		return;
	}
	DOCHECK(FlyingT(mech) && AeroFuel(mech) <= 0 &&
			!AeroFreeFuel(mech), "You're out of fuel!");
	maxspeed = MMaxSpeed(mech);

	if(MechMove(mech) == MOVE_VTOL)
		maxspeed = sqrt((float) maxspeed * maxspeed -
						MechVerticalSpeed(mech) * MechVerticalSpeed(mech));

	maxspeed = maxspeed > 0.0 ? maxspeed : 0.0;

	if((MechHeat(mech) >= 9.) && (MechSpecials(mech) & TRIPLE_MYOMER_TECH))
		maxspeed = ceil((rint((maxspeed / 1.5) / MP1) + 1) * 1.5) * MP1;

	/*   if (MechStatus(mech) & MASC_ENABLED) maxspeed = (4. / 3. ) * maxspeed; */
	walkspeed = WalkingSpeed(maxspeed);
	newspeed = atof(args[0]);

	if(newspeed < 0.1) {

		/* Possibly a string speed instead? */
		for(i = 0; speed_tables[i].name; i++)
			if(!strcasecmp(speed_tables[i].name, args[0])) {
				switch (speed_tables[i].flag) {
				case 0:
					newspeed = 0.0;
					break;
				case -1:
					newspeed = -walkspeed;
					break;
				case 1:
					newspeed = walkspeed;
					break;
				case 2:
					newspeed = maxspeed;
					break;
				}
				break;
			}
	}

	if(newspeed > maxspeed)
		newspeed = maxspeed;
	if(newspeed < -walkspeed)
		newspeed = -walkspeed;

	DOCHECK((newspeed < 0) && (MechCarrying(mech) > 0) &&
			(!(MechSpecials(mech) & SALVAGE_TECH)),
			"You can not backup while towing!");

	DOCHECK((newspeed < 0) && Sprinting(mech),
			"You can not backup while sprinting!");

	if(IsRunning(newspeed, maxspeed)) {
		DOCHECK(Dumping(mech), "You can not run while dumping ammo!");
		DOCHECK(UnJammingAmmo(mech),
				"You can not run while unjamming your weapon!");

		/* Exile Stun Code Effect */
		if(MechCritStatus(mech) & MECH_STUNNED) {
			mech_notify(mech, MECHALL, "You cannot move faster than cruise"
						" speed while stunned!");
			return;
		}

		DOCHECK(CrewStunned(mech),
				"Your cannot possibly control a vehicle going this fast in your "
				"current mental state!");
		DOCHECK(MechTankCritStatus(mech) & TAIL_ROTOR_DESTROYED,
				"Your cannot possibly control a VTOL going this fast with a destroyed tail rotor!");
		DOCHECK(MechType(mech) == CLASS_MECH && ((MechZ(mech) < 0 &&
												  (MechRTerrain(mech) == WATER
												   || MechRTerrain(mech) ==
												   BRIDGE
												   || MechRTerrain(mech) ==
												   ICE))
												 || MechRTerrain(mech) ==
												 HIGHWATER),
				"You can't run through water!");
	}
	if(!Wizard(player) && In_Character(mech->mynum) &&
	   MechPilot(mech) != player) {
		if(newspeed < 0.0) {
			notify(player,
				   "Not being the Pilot of this beast, you cannot move it backwards.");
			return;
		} else if(newspeed > walkspeed) {
			notify(player,
				   "Not being the Pilot of this beast, you cannot go faster than walking speed.");
			return;
		}
	}
	MechDesiredSpeed(mech) = newspeed;
	MaybeMove(mech);
	if(fabs(newspeed) > 0.1) {
		if(MechSwarmTarget(mech) > 0) {
			StopSwarming(mech, 1);
			MechCritStatus(mech) &= ~HIDDEN;
		}
		if(Digging(mech)) {
			mech_notify(mech, MECHALL,
						"You cease your attempts at digging in.");
			StopDigging(mech);
		}
		MechTankCritStatus(mech) &= ~DUG_IN;
	}
	mech_printf(mech, MECHALL, "Desired speed changed to %d KPH",
				(int) newspeed);
}

void mech_vertical(dbref player, void *data, char *buffer)
{
	MECH *mech = (MECH *) data;
	char *args[1], buff[50];
	float newspeed, maxspeed;

	cch(MECH_USUAL);
	DOCHECK(MechType(mech) != CLASS_VTOL &&
			MechMove(mech) != MOVE_SUB, "This command is for VTOLs only.");
	DOCHECK(MechType(mech) == CLASS_VTOL &&
			AeroFuel(mech) <= 0
			&& !AeroFreeFuel(mech), "You're out of fuel!");
	DOCHECK(WaterBeast(mech)
			&& NotInWater(mech),
			"You are regrettably unable to move at this time. We apologize for the inconvenience.");
	DOCHECK(mech_parseattributes(buffer, args, 1) != 1,
			tprintf("Current vertical speed is %.2f KPH.",
					(float) MechVerticalSpeed(mech)));
	newspeed = atof(args[0]);
	maxspeed = MMaxSpeed(mech);
	maxspeed =
		sqrt((float) maxspeed * maxspeed -
			 MechDesiredSpeed(mech) * MechDesiredSpeed(mech));
	if((newspeed > maxspeed) || (newspeed < -maxspeed)) {
		sprintf(buff, "Max vertical speed is + %d KPH and - %d KPH",
				(int) maxspeed, (int) maxspeed);
		notify(player, buff);
	} else {
		DOCHECK(Fallen(mech), "Your vehicle's movement system is destroyed.");
		DOCHECK(MechType(mech) == CLASS_VTOL &&
				Landed(mech), "You need to take off first.");
		MechVerticalSpeed(mech) = newspeed;
		mech_printf(mech, MECHALL,
					"Vertical speed changed to %d KPH", (int) newspeed);
		MaybeMove(mech);
	}
}

/*
 * - Only when fallen
 * - Tonnage / 3 (rounded up for .5)
 * - 5 Point groups to PA
 * - Clear or paved terrain only
 * - Automatically works
 * - Doesn't hit suits that are swarmed or jumping
 * - No weapons recycling in arms and legs
 * - Arms and legs recycle after attack
 * - Make pskill roll or take damage as if 1 level fall
 */

void mech_thrash(dbref player, void *data, char *buffer)
{
	MECH *mech = (MECH *) data;
	MECH *target;
	MAP *map = getMap(mech->mapindex);
	int terrain;
	int limbs = 4;
	int aLimbs[] = { RARM, LARM, LLEG, RLEG };
	int i;
	int tempLoc;
	char locName[50];
	int damage, tempDamage;

	cch(MECH_USUALO);
	DOCHECK(!Fallen(mech), "You need to be prone to thrash!");
	DOCHECK(!map, "Invalid map! Contact a wizard!");

	terrain = GetRTerrain(map, MechX(mech), MechY(mech));

	DOCHECK(!((terrain == GRASSLAND) || (terrain == ROAD) ||
			 (terrain == BRIDGE)),
			"Thrashing only works in clear terrain or on roads or bridges.");

	/* Check locations */
	for(i = 0; i < 4; i++) {
		tempLoc = aLimbs[i];

		if(SectIsDestroyed(mech, tempLoc)) {
			limbs--;
			continue;
		}

		ArmorStringFromIndex(tempLoc, locName, MechType(mech),
							 MechMove(mech));

		DOCHECK(SectHasBusyWeap(mech, tempLoc),
				tprintf("You have weapons recycling on your %s.", locName));
		DOCHECK(MechSections(mech)[tempLoc].recycle,
				tprintf("Your %s is still recovering from your last attack.",
						locName));
	}

	/* Can't thrash if we have no limbs */
	if(!limbs) {
		mech_notify(mech, MECHALL, "You can't thrash if you have no limbs!");
		return;
	}
#ifndef REALWEIGHT_DAMAGE
	damage = MechTons(mech) / 3;
#else
	damage = MechRealTons(mech) / 3;
#endif /* REALWEIGHT_DAMAGE */
	damage = (damage * limbs) / 4;

	mech_notify(mech, MECHALL,
				"You start to flail your arms and legs like a wild man!");
	MechLOSBroadcast(mech,
					 "starts to flail its arms and legs like a wild beast!");

	/* Let's see who we can smack around */
	for(i = 0; i < map->first_free; i++) {
		if(map->mechsOnMap[i] >= 0) {
			target = (MECH *) FindObjectsData(map->mechsOnMap[i]);

			if(!target)
				continue;

			if(MechType(target) != CLASS_BSUIT)
				continue;

			if(MechTeam(target) == MechTeam(mech))
				continue;

			if(Jumping(target) || OODing(target))
				continue;

			if(FaMechRange(mech, target) > 1.0)
				continue;

			mech_printf(mech, MECHALL, "You manage to hit %s!",
						GetMechToMechID(mech, target));
			mech_printf(target, MECHALL,
						"You get hit by %s's thrashing limbs!",
						GetMechToMechID(target, mech));

			tempDamage = damage;

			while (tempDamage > 0) {
				if(tempDamage > 5) {
					DamageMech(target, mech, 1, MechPilot(mech), Number(0,
																		NUM_BSUIT_MEMBERS
																		- 1),
							   0, 0, 5, 0, -1, 0, -1, 0, 1);
					tempDamage -= 5;
				} else {
					DamageMech(target, mech, 1, MechPilot(mech), Number(0,
																		NUM_BSUIT_MEMBERS
																		- 1),
							   0, 0, tempDamage, 0, -1, 0, -1, 0, 1);
					tempDamage = 0;
				}
			}
		}
	}

	/* Make our roll and recycle our limbs -- Removed. You gotta be prone anyways! */
/*	if(!MadePilotSkillRoll_Advanced(mech, 0, 0)) {
		MechFalls(mech, 1, 1);
	}
*/

	for(i = 0; i < 4; i++) {
		tempLoc = aLimbs[i];

		if(SectIsDestroyed(mech, tempLoc))
			continue;

		SetRecycleLimb(mech, tempLoc, PHYSICAL_RECYCLE_TIME);
	}
}

void mech_jump(dbref player, void *data, char *buffer)
{
	MECH *mech = (MECH *) data;
	MECH *tempMech = NULL;
	MAP *mech_map;
	char *args[3];
	int argc;
	int target;
	char targetID[2];
	short mapx, mapy;
	int bearing;
	float range = 0.0;
	float realx, realy;
	int sz, tz, jps;

	mech_map = getMap(mech->mapindex);
	cch(MECH_USUALO);
#ifdef BT_MOVEMENT_MODES
	DOCHECK(MoveModeLock(mech), "Movement modes disallow jumping.");
#endif
	DOCHECK(MechType(mech) != CLASS_MECH && MechType(mech) != CLASS_MW &&
			MechType(mech) != CLASS_BSUIT &&
			MechType(mech) != CLASS_VEH_GROUND, "This unit cannot jump.");
	DOCHECK(MechCarrying(mech) > 0, "You can't jump while towing someone!");
	DOCHECK((MechMaxSpeed(mech) - MMaxSpeed(mech)) > MP1,
			"No, with this cargo you won't!");
	DOCHECK(Fallen(mech), "You can't Jump from a FALLEN position");
	DOCHECK(IsHulldown(mech), "You can't Jump while hulldown");
	DOCHECK(ChangingHulldown(mech),
			"You are busy changing your hulldown mode");
	DOCHECK(Jumping(mech), "You're already jumping!");
	DOCHECK(Stabilizing(mech),
			"You haven't stabilized from your last jump yet.");
	DOCHECK(Standing(mech), "You haven't finished standing up yet.");
	DOCHECK(fabs(MechJumpSpeed(mech)) <= 0.0,
			"This mech doesn't have jump jets!");
	argc = mech_parseattributes(buffer, args, 3);
	DOCHECK(Dumping(mech), "You can not jump while dumping ammo!");
	DOCHECK(UnJammingAmmo(mech),
			"You can not jump while unjamming your weapon!");
	DOCHECK(RemovingPods(mech), "You are too busy removing iNARC pods!");
	DOCHECK(MapIsUnderground(mech_map),
			"Realize the ceiling in this grotto is a bit to low for that!");
	DOCHECK(OODing(mech), "You can't jump while orbital dropping!");

	if(Staggering(mech)) {
		mech_notify(mech, MECHALL,
					"The damage inhibits your coordination...");

		if(!MadePilotSkillRoll(mech, calcStaggerBTHMod(mech))) {
			mech_notify(mech, MECHALL,
						"... something you apparently can't handle!");
			MechLOSBroadcast(mech,
							 "engages jumpjets, rolls to the side and slams into the ground!");
			MechFalls(mech, 1, 0);
			return;
		}
	}

	if(doJettisonChecks(mech))
		return;

	DOCHECK(argc > 2, "Too many arguments to JUMP function!");
	MechStatus(mech) &= ~DFA_ATTACK;	/* By default no DFA */
	switch (argc) {
	case 0:
		/* DFA current target... */

		DOCHECK(MechType(mech) != CLASS_MECH,
				"Only mechs can do Death From Above attacks!");

		target = MechTarget(mech);
		tempMech = getMech(target);
		DOCHECK(!tempMech, "Invalid Target!");
		range = FaMechRange(mech, tempMech);
		DOCHECK(!InLineOfSight(mech, tempMech, MechX(tempMech),
							   MechY(tempMech), range),
				"Target is not in line of sight!");
		DOCHECK(MechType(tempMech) == CLASS_MW,
				"Even you can't aim your jump well enough to squish that!");
		mapx = MechX(tempMech);
		mapy = MechY(tempMech);
		MechDFATarget(mech) = MechTarget(mech);
		break;
	case 1:
		/* Jump Target */
		DOCHECK(MechType(mech) != CLASS_MECH,
				"Only mechs can do Death From Above attacks!");

		targetID[0] = args[0][0];
		targetID[1] = args[0][1];
		target = FindTargetDBREFFromMapNumber(mech, targetID);
		tempMech = getMech(target);
		DOCHECK(!tempMech, "Target is not in line of sight!");
		range = FaMechRange(mech, tempMech);
		DOCHECK(!InLineOfSight(mech, tempMech, MechX(tempMech),
							   MechY(tempMech), range),
				"Target is not in line of sight!");
		DOCHECK(MechType(tempMech) == CLASS_MW,
				"Even you can't aim your jump well enough to squish that!");
		mapx = MechX(tempMech);
		mapy = MechY(tempMech);
		MechDFATarget(mech) = tempMech->mynum;
		break;
	case 2:
		bearing = atoi(args[0]);
		range = atof(args[1]);
		FindXY(MechFX(mech), MechFY(mech), bearing, range, &realx, &realy);

		/* This is so we are jumping to the center of a hex */
		/* and the bearing jives with the target hex */
		RealCoordToMapCoord(&mapx, &mapy, realx, realy);
		break;
	}
	DOCHECK(mapx >= mech_map->map_width || mapy >= mech_map->map_height ||
			mapx < 0 || mapy < 0, "That would take you off the map!");
	DOCHECK(MechX(mech) == mapx &&
			MechY(mech) == mapy, "You're already in the target hex.");
	sz = MechZ(mech);
	tz = Elevation(mech_map, mapx, mapy);
	jps = JumpSpeedMP(mech, mech_map);
	DOCHECK(range > jps, "That target is out of range!");
	if(MechType(mech) != CLASS_BSUIT && tempMech)
		MechStatus(mech) |= DFA_ATTACK;
	/*   MechJumpTop(mech) = BOUNDED(3, (jps - range) + 2, jps - 1); */
	/* New idea: JumpTop = (JP + 1 - range / 3) - in another words,
	   SDR jumping for 1 hexes has 8 + 1 = 9 hex elevation in mid-flight,
	   SDR jumping for 8 hexes has 8 + 1 - 2 = 7 hex elevation in mid-flight,
	   TDR jumping for 4 hexes has 4 + 1 - 1 = 4 hex elevation in mid-flight

	   Come to think of it, the last SDR figure was ridiculous. New
	   value: 2 * 1 + 2 = 4
	 */
	MechJumpTop(mech) = MIN(jps + 1 - range / 3, 2 * range + 2);
	DOCHECK((tz - sz) > jps,
			"That target's high for you to reach with a single jump!");
	DOCHECK((sz - tz) > jps,
			"That target's low for you to reach with a single jump!");
	DOCHECK(sz < -1, "Glub glub glub.");
	MapCoordToRealCoord(mapx, mapy, &realx, &realy);
	bearing = FindBearing(MechFX(mech), MechFY(mech), realx, realy);

	/* TAKE OFF! */
	MechCocoon(mech) = 0;
	MechJumpHeading(mech) = bearing;
	MechStatus(mech) |= JUMPING;
	MechStartFX(mech) = MechFX(mech);
	MechStartFY(mech) = MechFY(mech);
	MechStartFZ(mech) = MechFZ(mech);
	MechJumpLength(mech) =
		length_hypotenuse((double) (realx - MechStartFX(mech)),
						  (double) (realy - MechStartFY(mech)));
	MechGoingX(mech) = mapx;
	MechGoingY(mech) = mapy;
	MechEndFZ(mech) = ZSCALE * tz;
	MechSpeed(mech) = 0.0;
	if(MechStatus(mech) & DFA_ATTACK)
		mech_notify(mech, MECHALL,
					"You engage your jump jets for a Death From Above attack!");
	else
		mech_notify(mech, MECHALL, "You engage your jump jets.");
	MechSwarmTarget(mech) = -1;
	MechLOSBroadcast(mech, "engages jumpjets!");
	MECHEVENT(mech, EVENT_JUMP, mech_jump_event, JUMP_TICK, 0);
}

static void mech_hulldown_event(MUXEVENT * e)
{
	MECH *mech = (MECH *) e->data;
	int type = (int) e->data2;

	if(!ChangingHulldown(mech))
		return;

	if(!Started(mech))
		return;

	if(type == 0) {
		MechStatus(mech) &= ~HULLDOWN;
		mech_notify(mech, MECHALL, "You finish lifting yourself up.");
		MechLOSBroadcast(mech, "finishes lifting itself up");
	} else {
		MechStatus(mech) |= HULLDOWN;
		mech_notify(mech, MECHALL,
					"You finish lowering yourself to the ground.");
		MechLOSBroadcast(mech, "finishes lowering itself to the ground.");
	}
}

#ifdef BT_MOVEMENT_MODES
void mech_sprint(dbref player, void *data, char *buffer)
{
	MECH *mech = (MECH *) data;
	int d = 0, i;

	cch(MECH_USUALO);
	DOCHECK(MechMove(mech) == MOVE_NONE,
			"This piece of equipment is stationary!");
	DOCHECK(MechCarrying(mech) > 0, "You cannot sprint while towing!");
	DOCHECK(Standing(mech), "You are currently standing up and cannot move.");
	DOCHECK(Jumping(mech), "You cannot do this while jumping.");
	DOCHECK((Fallen(mech)) && (MechType(mech) != CLASS_MECH &&
							   MechType(mech) != CLASS_MW),
			"Your vehicle's movement system is destroyed.");
	DOCHECK(Fallen(mech), "You are currently prone and cannot move.");
	DOCHECK(WaterBeast(mech) &&
			NotInWater(mech),
			"You are regrettably unable to move at this time. We apologize for the inconvenience.");
	DOCHECK(MoveModeChange(mech), "You are already changing movement modes!");
	DOCHECK(MechStatus2(mech) & (EVADING | DODGING),
			"You cannot perform multiple movement modes!");
	DOCHECK(MechSwarmTarget(mech) > 0, "You cannot sprint while mounted!");
	if(MechType(mech) == CLASS_MECH)
		DOCHECK(SectIsDestroyed(mech, RLEG) || SectIsDestroyed(mech, LLEG)
				|| (MechMove(mech) !=
					MOVE_QUAD ? 0 : SectIsDestroyed(mech, RLEG)
					|| SectIsDestroyed(mech, LLEG)),
				"That's kind of hard while limping.");

	d |= MODE_SPRINT | ((MechStatus2(mech) & SPRINTING) ? MODE_OFF : MODE_ON);
	if(d & MODE_ON) {
		if((i = MechFullNoRecycle(mech, CHECK_BOTH)) > 0) {
			mech_printf(mech, MECHALL, "You have %s recycling!",
						(i == 1 ? "weapons" : i == 2 ? "limbs" : "error"));
			return;
		}
		mech_notify(mech, MECHALL, "You begin the process of sprinting.....");
		MECHEVENT(mech, EVENT_MOVEMODE, mech_movemode_event,
				  (MechType(mech) == CLASS_BSUIT
				   || MechType(mech) == CLASS_MW) ? TURN / 2 : TURN, d);
	} else {
		mech_notify(mech, MECHALL,
					"You begin the process of ceasing to sprint.");
		MECHEVENT(mech, EVENT_MOVEMODE, mech_movemode_event,
				  (MechType(mech) == CLASS_BSUIT
				   || MechType(mech) == CLASS_MW) ? TURN / 2 : TURN, d);
	}
	return;
}

void mech_evade(dbref player, void *data, char *buffer)
{
	MECH *mech = (MECH *) data;
	int d = 0, i;

	cch(MECH_USUALO);
	DOCHECK(MechMove(mech) == MOVE_NONE,
			"This piece of equipment is stationary!");
	DOCHECK(Standing(mech), "You are currently standing up and cannot move.");
	DOCHECK(Jumping(mech), "You cannot do this while jumping.");
	DOCHECK((Fallen(mech))
			&& (MechType(mech) != CLASS_MECH
				&& MechType(mech) != CLASS_MW),
			"Your vehicle's movement system is destroyed.");
	DOCHECK(MechCarrying(mech) > 0, "You can't do that while towing");
	DOCHECK(Fallen(mech), "You are currently prone and cannot move.");
	DOCHECK(!(MechStatus2(mech) & EVADING) && MechType(mech) == CLASS_MECH
			&& (PartIsNonfunctional(mech, LLEG, 0)
				|| PartIsNonfunctional(mech, RLEG, 0)),
			"You need both hip functional to evade.");
	DOCHECK(WaterBeast(mech)
			&& NotInWater(mech),
			"You are regrettably unable to move at this time. We apologize for the inconvenience.");
	DOCHECK(MoveModeChange(mech), "You are already changing movement modes!");
	DOCHECK(MechStatus2(mech) & (SPRINTING | DODGING),
			"You cannot perform multiple movement modes!");
	DOCHECK(MechSwarmTarget(mech) > 0, "You cannot evade while mounted!");
	if(MechType(mech) == CLASS_MECH)
		DOCHECK(SectIsDestroyed(mech, RLEG) || SectIsDestroyed(mech, LLEG)
				|| (MechMove(mech) !=
					MOVE_QUAD ? 0 : SectIsDestroyed(mech, RLEG)
					|| SectIsDestroyed(mech, LLEG)),
				"That's kind of hard while limping.");

	d |= MODE_EVADE | ((MechStatus2(mech) & EVADING) ? MODE_OFF : MODE_ON);
	if(d & MODE_ON) {
		if((i = MechFullNoRecycle(mech, CHECK_BOTH)) > 0) {
			mech_printf(mech, MECHALL, "You have %s recycling!",
						(i == 1 ? "weapons" : i == 2 ? "limbs" : "error"));
			return;
		}
		mech_notify(mech, MECHALL, "You begin the process of evading.....");
		MECHEVENT(mech, EVENT_MOVEMODE, mech_movemode_event,
				  (MechType(mech) == CLASS_BSUIT
				   || MechType(mech) == CLASS_MW) ? TURN / 2 : TURN, d);
	} else {
		mech_notify(mech, MECHALL,
					"You begin the process of ceasing to evade.");
		MECHEVENT(mech, EVENT_MOVEMODE, mech_movemode_event,
				  (MechType(mech) == CLASS_BSUIT
				   || MechType(mech) == CLASS_MW) ? TURN / 2 : TURN, d);
	}
	return;
}

void mech_dodge(dbref player, void *data, char *buffer)
{
	MECH *mech = (MECH *) data;
	int d = 0, i;

	cch(MECH_USUALO);
	DOCHECK(MechMove(mech) == MOVE_NONE,
			"This piece of equipment is stationary!");
	DOCHECK(Standing(mech), "You are currently standing up and cannot move.");
	DOCHECK((Fallen(mech)) && (MechType(mech) != CLASS_MECH &&
							   MechType(mech) != CLASS_MW),
			"Your vehicle's movement system is destroyed.");
	DOCHECK(Fallen(mech), "You are currently prone and cannot move.");
	DOCHECK(WaterBeast(mech) &&
			NotInWater(mech),
			"You are regrettably unable to move at this time. We apologize for the inconvenience.");
	DOCHECK(MoveModeChange(mech), "You are already changing movement modes!");
	DOCHECK(MechStatus2(mech) & (SPRINTING | EVADING),
			"You cannot perform multiple movement modes!");
	DOCHECK(!(HasBoolAdvantage(player, "dodge_maneuver"))
			|| player != MechPilot(mech),
			"You either are not the pilot of this mech, have no Dodge Maneuver adavantage, or both.");
	d |= MODE_DODGE | ((MechStatus2(mech) & DODGING) ? MODE_OFF : MODE_ON);
	if(d & MODE_ON) {
		if((i = MechFullNoRecycle(mech, CHECK_PHYS)) > 0) {
			mech_printf(mech, MECHALL, "You have %s recycling!",
						(i == 1 ? "weapons" : i == 2 ? "limbs" : "error"));
			return;
		}
		mech_notify(mech, MECHALL, "You begin the process of dodging.....");
		MECHEVENT(mech, EVENT_MOVEMODE, mech_movemode_event, 1, d);
	} else {
		mech_notify(mech, MECHALL,
					"You begin the process of ceasing to dodge.");
		MECHEVENT(mech, EVENT_MOVEMODE, mech_movemode_event, TURN, d);
	}
	return;
}
#endif

void mech_hulldown(dbref player, void *data, char *buffer)
{
	MECH *mech = (MECH *) data;
	char *args[1];
	int argc;

	cch(MECH_USUALO);

	DOCHECK(!MechIsQuad(mech), "Only QUADs can hulldown.");
	DOCHECK(Fallen(mech), "You can't hulldown from a FALLEN position");
	DOCHECK(Jumping(mech), "You can't hulldown while jumping!");
	DOCHECK(MechSpeed(mech) > 0.5, "You can't hulldown while moving!");
	DOCHECK(Stabilizing(mech),
			"You are still stabilizing from your last jump.");
	DOCHECK(Standing(mech), "You haven't finished standing up yet.");

	argc = mech_parseattributes(buffer, args, 1);

	if(argc > 0) {
		if(!strcmp(args[0], "-")) {
			if(!IsHulldown(mech))
				mech_notify(mech, MECHALL, "You are not hulldown.");
			else if(ChangingHulldown(mech))
				mech_notify(mech, MECHALL,
							"You are busy changing your hulldown mode.");
			else {
				mech_notify(mech, MECHALL, "You start to lift yourself up.");
				MechLOSBroadcast(mech, "begins to raise up on its legs.");

				MECHEVENT(mech, EVENT_CHANGING_HULLDOWN,
						  mech_hulldown_event, StandMechTime(mech), 0);
			}
		} else if(!strcasecmp(args[0], "stop")) {
			if(!ChangingHulldown(mech))
				mech_notify(mech, MECHALL,
							"You are not currently changing your hulldown mode.");
			else {
				StopHullDown(mech);
				mech_notify(mech, MECHALL,
							"You stop changing your hulldown mode.");
			}
		} else
			mech_notify(mech, MECHALL, "Invalid argument for 'hulldown'.");

		return;
	}

	DOCHECK(IsHulldown(mech), "You are already hulldown.");
	DOCHECK(ChangingHulldown(mech),
			"You are busy changing your hulldown mode.");

	mech_notify(mech, MECHALL, "You start to lower yourself to the ground.");
	MechLOSBroadcast(mech, "begins to lower itself to the ground.");
	MechDesiredSpeed(mech) = 0;

	MECHEVENT(mech, EVENT_CHANGING_HULLDOWN, mech_hulldown_event,
			  StandMechTime(mech), 1);
}

int DropGetElevation(MECH * mech)
{
	if(MechRTerrain(mech) == BRIDGE) {
		if(MechZ(mech) < (MechElev(mech))) {
			if(Overwater(mech))
				return 0;
			return bridge_w_elevation(mech);
		}
		return MechElevation(mech);
	}
	if(Overwater(mech) || (MechRTerrain(mech) == ICE && MechZ(mech) >= 0))
		return MAX(0, MechElevation(mech));
	else
		return MechElevation(mech);
}

void DropSetElevation(MECH * mech, int wantdrop)
{
	if(MechRTerrain(mech) == BRIDGE) {
		bridge_set_elevation(mech);
		return;
	}
	MechZ(mech) = DropGetElevation(mech);
	MechFZ(mech) = MechZ(mech) * ZSCALE;
	if(wantdrop)
		if(MechRTerrain(mech) == ICE && MechZ(mech) >= 0)
			possibly_drop_thru_ice(mech);
}

void LandMech(MECH * mech)
{
	MECH *target;
	MAP *mech_map = getMap(mech->mapindex);
	int dfa = 0;
	int done = 0;

	/*
	 * Added check to see if we're actually awake when we try to land
	 * - Kipsta
	 * - 8/3/99
	 */

	if(Uncon(mech)) {
		mech_notify(mech, MECHALL,
					"Your lack of conciousness makes you fall to the ground. Not like you can read this anyway.");
		MechFalls(mech, 1, 0);
		dfa = 1;
		done = 1;
	} else {
		/* Handle DFA attack */
		if(MechStatus(mech) & DFA_ATTACK) {
			/* is the target here? */
			target = getMech(MechDFATarget(mech));
			if(target) {
				if(MechX(target) == MechX(mech) &&
				   MechY(target) == MechY(mech))
					dfa = DeathFromAbove(mech, target);
				else
					mech_notify(mech, MECHPILOT,
								"Your DFA target has moved!");
			} else
				mech_notify(mech, MECHPILOT,
							"Your target has become invalid.");
		}

		if(!dfa)
			mech_notify(mech, MECHALL, "You finish your jump.");

		/* Better reset the FZ */
		MechElev(mech) = GetElev(mech_map, MechX(mech), MechY(mech));
		MechZ(mech) = MechElev(mech) - 1;
		MechFZ(mech) = ZSCALE * MechZ(mech);
		DropSetElevation(mech, 1);

		if(Staggering(mech)) {
			mech_notify(mech, MECHALL,
						"The damage you've taken makes the landing a bit harder...");

			if(!MadePilotSkillRoll(mech, calcStaggerBTHMod(mech))) {
				mech_notify(mech, MECHALL,
							"... something you apparently can't handle!");
				MechLOSBroadcast(mech, "lands, staggers, and falls down!");
				MechFalls(mech, 1, 0);
				return;
			}
		}

		/* Check piloting rolls, etc. */
		if(MechType(mech) == CLASS_MECH) {
			if(CountDestroyedLegs(mech) > 0) {
				mech_notify(mech, MECHPILOT,
							"Your missing leg makes it harder to land");
				if(!MadePilotSkillRoll(mech, 0)) {
					mech_notify(mech, MECHALL,
								"Your missing leg has caused you to fall upon landing!");
					MechLOSBroadcast(mech,
									 "lands, unbalanced, and falls down!");
					dfa = 1;
					MechFalls(mech, 1, 0);
					done = 1;
				}
			} else if(MechSections(mech)[RLEG].basetohit ||
					  MechSections(mech)[LLEG].basetohit) {
				mech_notify(mech, MECHPILOT,
							"Your damaged leg actuators make it harder to land");
				if(!MadePilotSkillRoll(mech, 0)) {
					mech_notify(mech, MECHALL,
								"Your damaged leg actuators have caused you to fall upon landing!");
					MechLOSBroadcast(mech,
									 "lands, stumbles, and falls down!");
					dfa = 1;
					done = 1;
					MechFalls(mech, 1, 0);
				}
			} else if((MechCritStatus(mech) & GYRO_DAMAGED) || (MechCritStatus(mech) & GYRO_DESTROYED)) {
				mech_notify(mech, MECHPILOT, "Your damaged gyro makes it harder to land");
				if(!MadePilotSkillRoll(mech, 0)) {
					mech_notify(mech, MECHALL,
							"Your damaged gyro has caused you to fall upon landing!");
					MechLOSBroadcast(mech,
							"lands, twists awkwardly, and falls down!");
					dfa = 1;
					done = 1;
					MechFalls(mech,1,0);
				}
			}
		}
	}

	if((MechType(mech) == CLASS_MECH) && CountSwarmers(mech)) {
		mech_notify(mech, MECHALL,
					"The suits hanging off you make landing harder!");

		if(MadePilotSkillRoll(mech, 4)) {
			StopBSuitSwarmers(FindObjectsData(mech->mapindex), mech, 0);
		} else {
			mech_notify(mech, MECHALL,
						"You fail to properly control your unbalanced landing!");
			MechLOSBroadcast(mech,
							 "lands and crashes to the ground from the weight of the battlesuits!");
			MechFalls(mech, 1, 0);
		}
	}

	if(!dfa && !Fallen(mech) && !domino_space(mech, 1)) {
		if(MechType(mech) != CLASS_VEH_GROUND)
			MechLOSBroadcast(mech, "lands gracefully.");
		else
			MechLOSBroadcast(mech, "returns to the ground where it belongs.");
	}

	/* If we aren't jumping anymore, we already took care of the event.
	   (e.g. in MechFalls()) */
	if(Jumping(mech))
		MECHEVENT(mech, EVENT_JUMPSTABIL, mech_stabilizing_event,
				  JUMP_TO_HIT_RECYCLE, 0);
	MechStatus(mech) &= ~JUMPING;
	MechStatus(mech) &= ~DFA_ATTACK;
	MechDFATarget(mech) = -1;
	MechGoingX(mech) = MechGoingY(mech) = 0;
	MechSpeed(mech) = 0;
	StopJump(mech);				/* Kill the event for moving 'round */
	MaybeMove(mech);			/* Possibly start movin' on da ground */


	if(!done)
		possible_mine_poof(mech, MINE_LAND);

	MechFloods(mech);
	water_extinguish_inferno(mech);
	StopStaggerCheck(mech);
}

/* Flooding code. Once we're in water, this is checked
   now and then (basically when DamageMech'ed and/or
   depth changes and/or we fall) */

void MechFloodsLoc(MECH * mech, int loc, int lev)
{
	char locbuff[32];;

	if(MechStatus(mech) & COMBAT_SAFE)
		return;

	if((GetSectArmor(mech, loc) && (GetSectRArmor(mech, loc) ||
									!GetSectORArmor(mech, loc)))
	   || !GetSectInt(mech, loc))
		return;
	if(!InWater(mech))
		return;
	if(lev >= 0)
		return;
	/* No armor, and in water. */
	if(lev == -1 && (!Fallen(mech) && loc != LLEG && loc != RLEG &&
					 (!MechIsQuad(mech) || (loc != LARM && loc != RARM))))
		return;
	if(MechType(mech) != CLASS_MECH)
		return;

	if(SectIsFlooded(mech, loc))
		return;

	/* Woo, valid target. */
	ArmorStringFromIndex(loc, locbuff, MechType(mech), MechMove(mech));
	mech_printf(mech, MECHALL,
				"%%ch%%crWater floods into your %s disabling everything that was there!%%c",
				locbuff);
	MechLOSBroadcast(mech,
					 tprintf("has a gaping hole in %s, and water pours in!",
							 locbuff));

	SetSectFlooded(mech, loc);
	DestroyParts(mech, mech, loc, 1, 1);

}

void MechFloods(MECH * mech)
{
	int i;
	int elev = MechElevation(mech);

	if(!InWater(mech))
		return;

	/* Waterproof Tech - no flooding if we have this */
	if(MechSpecials2(mech) & WATERPROOF_TECH)
		return;

	if(MechType(mech) == CLASS_BSUIT) {

		if(MechSwarmTarget(mech) > 0)
			return;

		mech_notify(mech, MECHALL,
					"You somehow find yourself in water and realize this may really really suck...");
		mech_notify(mech, MECHALL,
					"Everything gets very dark as water starts to fill your suit "
					"and you sink towards the bottom!");

		MechLOSBroadcast(mech,
						 "shudders, splashes in the water for a second, then goes limp "
						 "and sinks to the bottom.");

		KillMechContentsIfIC(mech->mynum);
		DestroyMech(mech, mech, 0);
		return;
	}

	if(MechType(mech) != CLASS_MECH)
		return;

	if(MechZ(mech) >= 0)
		return;

	for(i = 0; i < NUM_SECTIONS; i++)
		MechFloodsLoc(mech, i, elev);
}

void MechFalls(MECH * mech, int levels, int seemsg)
{
	int roll, spread, i, hitloc, hitGroup = 0;
	int isrear = 0, damage, iscritical = 0;
	MAP *map;

	/* get rid of our swarmers */
	if(CountSwarmers(mech))
		StopBSuitSwarmers(FindObjectsData(mech->mapindex), mech, 0);

	/* damage pilot */
	MechCocoon(mech) = 0;
	if(MechType(mech) == CLASS_MECH || MechType(mech) == CLASS_MW || seemsg)
		mech_notify(mech, MECHPILOT,
					"You try to avoid taking damage in the fall.");
	else
		mech_notify(mech, MECHPILOT, "You try to avoid taking damage.");
	if(!MadePilotSkillRoll(mech, levels)) {
		if(MechType(mech) == CLASS_MECH || MechType(mech) == CLASS_MW ||
		   seemsg)
			mech_notify(mech, MECHPILOT,
						"You take personal injury from the fall!");
		else
			mech_notify(mech, MECHPILOT, "You take personal injury!");
		headhitmwdamage(mech, 1);
	}
	MechSpeed(mech) = 0;
	MechDesiredSpeed(mech) = 0;
	if(Jumping(mech)) {
		MechStatus(mech) &= ~JUMPING;
		MechStatus(mech) &= ~DFA_ATTACK;
		StopJump(mech);
		MECHEVENT(mech, EVENT_JUMPSTABIL, mech_stabilizing_event,
				  JUMP_TO_HIT_RECYCLE, 0);
	}
#ifdef BT_MOVEMENT_MODES
	if(MoveModeChange(mech))
		StopMoveMode(mech);
	if(MechStatus2(mech) & SPRINTING)
		MECHEVENT(mech, EVENT_MOVEMODE, mech_movemode_event,
				  (MechType(mech) == CLASS_BSUIT
				   || MechType(mech) == CLASS_MW) ? TURN / 2 : TURN,
				  MODE_SPRINT | MODE_OFF);
	if(MechStatus2(mech) & EVADING)
		MECHEVENT(mech, EVENT_MOVEMODE, mech_movemode_event,
				  (MechType(mech) == CLASS_BSUIT
				   || MechType(mech) == CLASS_MW) ? TURN / 2 : TURN,
				  MODE_EVADE | MODE_OFF);
#endif
	if(MechMove(mech) == MOVE_VTOL || MechMove(mech) == MOVE_FLY) {
		MechVerticalSpeed(mech) = 0;
		MechGoingY(mech) = 0;
		MechStartFX(mech) = 0.0;
		MechStartFY(mech) = 0.0;
		MechStartFZ(mech) = 0.0;
		MechStatus(mech) |= LANDED;
		MechStatus(mech) |= FALLEN;
		StopMoving(mech);
	} else
		MaybeMove(mech);
	if(MechType(mech) == CLASS_MECH || MechType(mech) == CLASS_MW)
		MakeMechFall(mech);

	if(seemsg)
		MechLOSBroadcast(mech, "falls down!");
	DropSetElevation(mech, 1);
	MechFZ(mech) = MechZ(mech) * ZSCALE;

	roll = Number(1, 6);
	switch (roll) {
	case 1:
		hitGroup = FRONT;
		break;
	case 2:
		AddFacing(mech, 60);
		hitGroup = RIGHTSIDE;
		break;
	case 3:
		AddFacing(mech, 120);
		hitGroup = RIGHTSIDE;
		break;
	case 4:
		AddFacing(mech, 180);
		hitGroup = BACK;
		break;
	case 5:
		AddFacing(mech, 240);
		hitGroup = LEFTSIDE;
		break;
	case 6:
		AddFacing(mech, 300);
		hitGroup = LEFTSIDE;
		break;
	}
	if(hitGroup == BACK)
		isrear = 1;
	SetFacing(mech, AcceptableDegree(MechFacing(mech)));
	MechDesiredFacing(mech) = MechFacing(mech);
	if(!InWater(mech) && MechRTerrain(mech) != HIGHWATER)
#ifndef REALWEIGHT_DAMAGE
		damage = (levels * (MechTons(mech) + 5)) / 10;
#else
		damage = (levels * (MechRealTons(mech) + 5)) / 10;
#endif /* REALWEIGHT_DAMAGE */
	else
#ifndef REALWEIGHT_DAMAGE
		damage = (levels * (MechTons(mech) + 5)) / 20;
#else
		damage = (levels * (MechRealTons(mech) + 5)) / 20;
#endif /* REALWEIGHT_DAMAGE */
	if(InSpecial(mech))
		if((map = FindObjectsData(mech->mapindex)))
			if(MapUnderSpecialRules(map))
				damage = damage * MIN(100, MapGravity(map)) / 100;

	if(MechType(mech) == CLASS_MW)
		damage *= 40;

	spread = damage / 5;

	for(i = 0; i < spread; i++) {
		hitloc = FindHitLocation(mech, hitGroup, &iscritical, &isrear);
		DamageMech(mech, mech, 0, -1, hitloc, isrear, iscritical, 5, -1,
				   -1, 0, -1, 0, 0);
		MechFloods(mech);
		water_extinguish_inferno(mech);
	}
	if(damage % 5) {
		hitloc = FindHitLocation(mech, hitGroup, &iscritical, &isrear);
		DamageMech(mech, mech, 0, -1, hitloc, isrear, iscritical,
				   (damage % 5), -1, -1, 0, -1, 0, 0);
		MechFloods(mech);
		water_extinguish_inferno(mech);
	}

	possible_mine_poof(mech, MINE_FALL);
	MarkForLOSUpdate(mech);
}

int mechs_in_hex(MAP * map, int x, int y, int friendly, int team)
{
	MECH *mech;
	int i, cnt = 0;

	for(i = 0; i < map->first_free; i++)
		if((mech = FindObjectsData(map->mechsOnMap[i]))) {
			if(MechX(mech) != x || MechY(mech) != y)
				continue;
			if(Destroyed(mech))
				continue;
			if(!(MechSpecials2(mech) & CARRIER_TECH) && IsDS(mech)
			   && (Landed(mech) || !Started(mech))) {
				cnt += 2;
				continue;
			}
			if(MechType(mech) != CLASS_MECH)
				continue;
			if(Jumping(mech) || OODing(mech))
				continue;
			if(friendly < 0 || ((MechTeam(mech) == team) == friendly))
				cnt++;
		}
	return cnt;
}

enum {
	NORMAL, PUNCH, KICK
};

void cause_damage(MECH * att, MECH * mech, int dam, int table)
{
	int hitGroup, isrear, iscrit = 0, hitloc = 0;
	int i, sp = (dam - 1) / 5;

	if(!dam)
		return;
	if(att == mech)
		hitGroup = FRONT;
	else
		hitGroup = FindAreaHitGroup(att, mech);
	isrear = (hitGroup == BACK);
	if(Fallen(mech))
		table = NORMAL;
	for(i = 0; i <= sp; i++) {
		switch (table) {
		case NORMAL:
			hitloc = FindHitLocation(mech, hitGroup, &iscrit, &isrear);
			break;
		case PUNCH:
			FindPunchLoc(mech, hitloc, hitGroup, iscrit, isrear);
			break;
		case KICK:
			FindKickLoc(mech, hitloc, hitGroup, iscrit, isrear);
			break;
		}
		if(dam <= 0)
			return;
		DamageMech(mech, att, (att == mech) ? 0 : 1,
				   (att == mech) ? -1 : MechPilot(att), hitloc, isrear,
				   iscrit, dam > 5 ? 5 : dam, 0, -1, 0, -1, 0, 0);
		dam -= 5;
	}
}

int domino_space_in_hex(MAP * map, MECH * me, int x, int y, int friendly,
						int mode, int cnt)
{
	int tar = Number(0, cnt - 1), i, head, td;
	MECH *mech = NULL;
	int team = MechTeam(me);

	for(i = 0; i < map->first_free; i++)
		if((mech = FindObjectsData(map->mechsOnMap[i]))) {
			if(MechX(mech) != x || MechY(mech) != y)
				continue;
			if(mech == me)
				continue;
			if(IsDS(mech) && (Landed(mech) || !Started(mech))) {
				tar -= 2;
			} else {
				if(!Started(mech))
					continue;
				if(MechType(mech) != CLASS_MECH)
					continue;
				if(Jumping(mech) || OODing(mech))
					continue;
				if(friendly < 0 || ((MechTeam(mech) == team) == friendly))
					tar--;
				else
					continue;
			}
			if(tar <= 0)
				break;
		}
	if(i == map->first_free)
		return 0;
	/* Now we got a mech we hit, accidentally or otherwise */
	/* Next, we figure out what'll happen */

	/* 'wannabe-charge' is entirely based on the directional difference */
	/* Multiplied by the speed - if both go in same direction at same speed,
	   nothing untoward happens (unlikely, though) */
	/* Jumping to a hex with multiple guys is BAD Thing(tm), though */

	switch (mode) {
	case 1:
	case 2:
		head = MechJumpHeading(me);
		td = JumpSpeedMP(me, map) * (MechRTons(me) / 1024 + 5) / 10;
		break;
	default:
		head = MechFacing(me) + MechLateral(me);
		td = fabs(((MechSpeed(me) - MechSpeed(mech) * cos((head -
														   (MechFacing(mech) +
															MechLateral
															(mech))) * (M_PI /
																		180.)))
				   * MP_PER_KPH) * (MechRTons(me) / 1024 + 5) / 15);
		break;
	}
	if(td > 10)
		td = 10 + (td - 10) / 3;
	if(td <= 1)					/* No point in 1pt hits */
		return 0;
	switch (mode) {
	case 1:
	case 2:
		if(mudconf.btech_stacking == 2) {
			int factor = mudconf.btech_stackdamage;
			mech_printf(me, MECHALL, "You land on %s!",
						GetMechToMechID(me, mech));
			mech_printf(mech, MECHALL, "%s lands on you!",
						GetMechToMechID(mech, me));
			MechLOSBroadcasti(me, mech, "lands on %s!");
			if(IsDS(mech)) {
				cause_damage(me, mech, MAX(1, td * factor / 500), PUNCH);
				cause_damage(me, me, MAX(1, td * factor / 100), KICK);
			} else {
				cause_damage(me, mech, MAX(1, td * factor / 100), PUNCH);
				cause_damage(me, me, MAX(1, td * factor / 500), KICK);
			}
		} else {
			mech_printf(me, MECHALL, "You nearly land on %s!",
						GetMechToMechID(me, mech));
			mech_printf(mech, MECHALL, "%s nearly lands on you!",
						GetMechToMechID(mech, me));
			MechLOSBroadcasti(me, mech, "nearly lands on %s!");
			if(!MadePilotSkillRoll(me, cnt + JumpSpeedMP(me, map) / 2))
				MechFalls(me, 1, JumpSpeedMP(me, map) / 2);
		}
		return 1;
	}
	if(mudconf.btech_stacking == 2) {
		int factor = mudconf.btech_stackdamage;
		mech_printf(me, MECHALL, "You bump into %s!",
					GetMechToMechID(me, mech));
		mech_printf(mech, MECHALL, "%s bumps into you!",
					GetMechToMechID(mech, me));
		MechLOSBroadcasti(me, mech, "bumps into %s!");
		if(IsDS(mech)) {
			cause_damage(me, mech, MAX(1, td * factor / 500), NORMAL);
			cause_damage(me, me, MAX(1, td * factor / 100), NORMAL);
		} else {
			cause_damage(me, mech, MAX(1, td * factor / 100), NORMAL);
			cause_damage(me, me, MAX(1, td * factor / 500), NORMAL);
		}
	} else {
		mech_printf(me, MECHALL, "You nearly bump into %s!",
					GetMechToMechID(me, mech));
		mech_printf(mech, MECHALL, "%s nearly bumps into you!",
					GetMechToMechID(mech, me));
		MechLOSBroadcasti(me, mech, "nearly bumps into %s!");
		if(!MadePilotSkillRoll(me, cnt))
			MechFalls(me, 1, 0);
		MechDesiredSpeed(me) = 0;
		MechSpeed(me) = 0;
	}
	MechChargeTarget(me) = -1;
	MechChargeTimer(me) = 0;
	MechChargeDistance(me) = 0;
	return 1;
}

int domino_space(MECH * mech, int mode)
{
	MAP *map = FindObjectsData(mech->mapindex);
	int cnt, fcnt;

	if(!map)
		return 0;
	if(MechType(mech) != CLASS_MECH)
		return 0;
	if(mudconf.btech_stacking == 0)
		return 0;
	cnt = mechs_in_hex(map, MechX(mech), MechY(mech), -1, 0);
	if(cnt <= 2)
		return 0;
	/* Possible nastiness */
	if((fcnt =
		mechs_in_hex(map, MechX(mech), MechY(mech), 1, MechTeam(mech))) > 2)
		return domino_space_in_hex(map, mech, MechX(mech), MechY(mech), 1,
								   mode, fcnt);
	else if(cnt > 6)
		return domino_space_in_hex(map, mech, MechX(mech), MechY(mech), 0,
								   mode, cnt - fcnt);
	return 0;
}