btmux/autom4te.cache/
btmux/doc/.svn/
btmux/event/.svn/
btmux/game/.svn/
btmux/game/bin/.svn/
btmux/game/data/.svn/
btmux/game/logs/.svn/
btmux/game/maps/
btmux/game/maps/.svn/
btmux/game/maps/.svn/prop-base/
btmux/game/maps/.svn/props/
btmux/game/maps/.svn/text-base/
btmux/game/maps/.svn/wcprops/
btmux/game/mechs/
btmux/game/mechs/.svn/
btmux/game/mechs/.svn/prop-base/
btmux/game/mechs/.svn/props/
btmux/game/mechs/.svn/text-base/
btmux/game/mechs/.svn/wcprops/
btmux/game/text/.svn/
btmux/include/.svn/
btmux/misc/
btmux/misc/.svn/
btmux/misc/.svn/prop-base/
btmux/misc/.svn/props/
btmux/misc/.svn/text-base/
btmux/misc/.svn/wcprops/
btmux/python/
btmux/python/.svn/
btmux/python/.svn/prop-base/
btmux/python/.svn/props/
btmux/python/.svn/text-base/
btmux/python/.svn/wcprops/
btmux/src/.svn/prop-base/
btmux/src/.svn/props/
btmux/src/.svn/text-base/
btmux/src/.svn/wcprops/
btmux/src/hcode/.svn/
btmux/src/hcode/btech/
btmux/src/hcode/btech/.svn/
btmux/src/hcode/btech/.svn/prop-base/
btmux/src/hcode/btech/.svn/props/
btmux/src/hcode/btech/.svn/text-base/
btmux/src/hcode/btech/.svn/wcprops/
btmux/src/hcode/include/.svn/
/*
 * $Id: mech.move.c,v 1.6 2005/08/10 14:09:34 av1-op Exp $
 *
 * Author: Markus Stenberg <fingon@iki.fi>
 *
 *  Copyright (c) 1996 Markus Stenberg
 *  Copyright (c) 1998-2002 Thomas Wouters
 *  Copyright (c) 2000-2002 Cord Awtry
 *  Copyright (c) 1999-2005 Kevin Stevens
 *       All rights reserved
 *
 * Last modified: Mon Oct 26 20:15:47 1998 fingon
 *
 */

#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_notify(mech, MECHALL,
	tprintf("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_notify(mech, MECHALL, tprintf("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_notify(mech, MECHALL,
		    tprintf("You have weapons recycling in your %s.",
			strLocation));
		return;
	    }

	    if (MechSections(mech)[i].recycle) {
		mech_notify(mech, MECHALL,
		    tprintf
		    ("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_notify(mech, MECHALL,
	    tprintf
	    ("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_notify(mech, MECHALL,
	    tprintf
	    ("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_notify(mech, MECHALL,
	    tprintf("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 (yet)!");
    DOCHECK(MechType(mech) != CLASS_MECH &&
	MechType(mech) != CLASS_MW,
	"This vehicle cannot drop like a 'Mech.");
    DOCHECK(Fallen(mech), "You are already prone.");
    DOCHECK(Jumping(mech) ||
	OODing(mech), "You can't drop while jumping!");
    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 (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, standanyway = 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);

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

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

    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, 0)) {
            mech_notify(mech, MECHALL,
                    "You fail your attempt to stand and fall back on the ground");
            MechFalls(mech, 1, 1);
            MECHEVENT(mech, EVENT_STANDFAIL, mech_standfail_event,
                    MechType(mech) ==
                    CLASS_MW ? DROP_TO_STAND_RECYCLE / 3 : StandMechTime(mech),
                    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.");
        MECHEVENT(mech, EVENT_STAND, mech_stand_event,
                MechType(mech) ==
                CLASS_MW ? DROP_TO_STAND_RECYCLE / 3 : StandMechTime(mech), 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_notify(mech, MECHALL, tprintf("Heading changed to %d.",
		newheading));
	MaybeMove(mech);
    } else {
	notify(player, tprintf("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_notify(mech, MECHALL, tprintf("Turret facing changed to %d.",
		AcceptableDegree(MechTurretFacing(mech) +
		    MechFacing(mech))));
    } else {
	notify(player, tprintf("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(player, tprintf("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!");

    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_notify(mech, MECHALL, tprintf("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_notify(mech, MECHALL,
	    tprintf("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_notify(mech, MECHALL, tprintf("You manage to hit %s!",
		    GetMechToMechID(mech, target)));
	    mech_notify(target, MECHALL,
		tprintf("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 */
    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!");

    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_notify(mech, MECHALL, tprintf("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_notify(mech, MECHALL, tprintf("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_notify(mech, MECHALL, tprintf("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;
    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.");

	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);
		}
	    }
	}
    }

    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 */

    DropSetElevation(mech, 1);

    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 ((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_notify(mech, MECHALL,
	tprintf
	("%%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_notify(me, MECHALL, tprintf("You land on %s!",
					     GetMechToMechID(me, mech)));
	    mech_notify(mech, MECHALL, tprintf("%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_notify(me, MECHALL, tprintf("You nearly land on %s!",
					     GetMechToMechID(me, mech)));
	    mech_notify(mech, MECHALL, tprintf("%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_notify(me, MECHALL, tprintf("You bump into %s!",
					 GetMechToMechID(me, mech)));
	mech_notify(mech, MECHALL, tprintf("%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_notify(me, MECHALL, tprintf("You nearly bump into %s!",
					 GetMechToMechID(me, mech)));
	mech_notify(mech, MECHALL, tprintf("%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;
}