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
 *  Copyright (c) 2005-2006 Gregory Taylor
 *       All rights reserved
 */

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

#include "mech.h"
#include "map.h"
#include "mech.events.h"
#include "mech.physical.h"
#include "p.mech.physical.h"
#include "p.mech.combat.h"
#include "p.mech.damage.h"
#include "p.mech.utils.h"
#include "p.mech.los.h"
#include "p.mech.hitloc.h"
#include "p.bsuit.h"
#include "p.btechstats.h"
#include "p.template.h"
#include "p.mech.bth.h"

// Only allows arm physical attacks for CLASS_MECH.
#define ARM_PHYS_CHECK(a) \
DOCHECK(MechType(mech) == CLASS_MW || MechType(mech) == CLASS_BSUIT, \
  tprintf("You cannot %s without a 'mech!", a)); \
DOCHECK(MechType(mech) != CLASS_MECH, \
  tprintf("You cannot %s with this vehicle!", a));

// Checks a unit's legs for kicking.
#define GENERIC_CHECK(a,wDeadLegs) \
ARM_PHYS_CHECK(a);\
DOCHECK(!MechIsQuad(mech) && (wDeadLegs > 1), \
  "Without legs? Are you kidding?");\
DOCHECK(!MechIsQuad(mech) && (wDeadLegs > 0),\
  "With one leg? Are you kidding?");\
DOCHECK(wDeadLegs > 1,"It'd unbalance you too much in your condition..");\
DOCHECK(wDeadLegs > 2, "Exactly _what_ are you going to kick with?");

// If it's a quad, we can't play with sharp things (Swords, Axes, etc.)
#define QUAD_CHECK(a) \
DOCHECK(MechType(mech) == CLASS_MECH && MechIsQuad(mech), \
  tprintf("What are you going to %s with, your front right leg?", a))

/**
 * Checks to see if all limbs have recycled from any previous physical attacks.
 */
int all_limbs_recycled(MECH * mech)
{
	if(MechSections(mech)[LARM].recycle || MechSections(mech)[RARM].recycle) {
		mech_notify(mech, MECHALL,
					"You still have arms recovering from another attack.");
		return 0;
	}

	if(MechSections(mech)[RLEG].recycle || MechSections(mech)[LLEG].recycle) {
		mech_notify(mech, MECHALL,
					"Your legs are still recovering from your last attack.");
		return 0;
	}
	// Fall through to success.
	return 1;
}								// end all_limbs_recycled()

/**
 * Returns the correct verb for each physical attack.
 */
char *phys_form(int AttackType, int add_s)
{
	// Holds our attack verb.
	char *verb;

	// See if we need the verb with an s on the end.
	if(add_s) {
		// With the S.
		switch (AttackType) {
		case PA_PUNCH:
			verb = "punchs";
			break;
		case PA_CLUB:
			verb = "clubs";
			break;
		case PA_MACE:
			verb = "maces";
			break;
		case PA_SWORD:
			verb = "chops";
			break;
		case PA_AXE:
			verb = "axes";
			break;
		case PA_KICK:
			verb = "kicks";
			break;
		case PA_TRIP:
			verb = "trips";
			break;
		case PA_SAW:
			verb = "saws";
			break;
			// Ohboy, we're using some funky, unknown physical.
		default:
			verb = "??bugs??";
		}						// end switch()
	} else {
		// Without the S.
		switch (AttackType) {
		case PA_PUNCH:
			verb = "punch";
			break;
		case PA_CLUB:
			verb = "club";
			break;
		case PA_MACE:
			verb = "maces";
			break;
		case PA_SWORD:
			verb = "chop";
			break;
		case PA_AXE:
			verb = "axe";
			break;
		case PA_KICK:
			verb = "kick";
			break;
		case PA_TRIP:
			verb = "trip";
			break;
		case PA_SAW:
			verb = "saw";
			break;
			// Ohboy, we're using some funky, unknown physical.
		default:
			verb = "??bugs??";
		}						// end switch()
	}							// end if/else()

	return verb;
}								// end phys_form

#define phys_message(txt) \
MechLOSBroadcasti(mech,target,txt)

void phys_succeed(MECH * mech, MECH * target, int at)
{
	phys_message(tprintf("%s %%s!", phys_form(at, 1)));
}

void phys_fail(MECH * mech, MECH * target, int at)
{
	phys_message(tprintf("attempts to %s %%s!", phys_form(at, 0)));
}

/*
 * All 'mechs with arms can punch.
 */
static int have_punch(MECH * mech, int loc)
{
	return 1;
}

/**
 * Does our unit have an axe?
 */
int have_axe(MECH * mech, int loc)
{
	return FindObj(mech, loc, I2Special(AXE)) >= (MechTons(mech) / 15);
}

/**
 * Does our unit have a dual_saw?
 */
int have_saw(MECH * mech, int loc)
{
	return FindObj(mech, loc, I2Special(DUAL_SAW)) >= 7;
}

/**
 * Does our unit have a sword?
 */
int have_sword(MECH * mech, int loc)
{
	return FindObj(mech, loc,
				   I2Special(SWORD)) >= ((MechTons(mech) + 15) / 20);
}

/**
 * Does our unit have a mace?
 */
int have_mace(MECH * mech, int loc)
{
	return FindObj(mech, loc, I2Special(MACE)) >= (MechTons(mech) / 10);
}

/*
 * Carry out some checks common to all types of physical attacks.
 */
int phys_common_checks(MECH * mech)
{
	if(Jumping(mech)) {
		mech_notify(mech, MECHALL,
					"You can't perform physical attacks while in the air!");
		return 0;
	}

	if(Standing(mech)) {
		mech_notify(mech, MECHALL, "You are still trying to stand up!");
		return 0;
	}
#ifdef BT_MOVEMENT_MODES
	if(Dodging(mech) || MoveModeLock(mech)) {
		mech_notify(mech, MECHALL,
					"You cannot use physicals while using a special movement mode.");
		return 0;
	}
#endif

	if(!all_limbs_recycled(mech)) {
		return 0;
	}
	// Fall through to success.
	return 1;
}								// end phys_common_checks()

/*
 * Parse a physical attack command's arguments that allow an arm or both
 * to be specified. eg. AXE [B|L|R] [ID]
 */
static int get_arm_args(int *using, int *argc, char ***args, MECH * mech,
						int (*have_fn) (MECH * mech, int loc), char *weapon)
{

	if(*argc != 0 && args[0][0][0] != '\0' && args[0][0][1] == '\0') {
		char arm = toupper(args[0][0][0]);

		// Determine which flag we're dealing with (Both, Left, Right)
		switch (arm) {
		case 'B':
			*using = P_LEFT | P_RIGHT;
			--*argc;
			++*args;
			break;

		case 'L':
			*using = P_LEFT;
			--*argc;
			++*args;
			break;

		case 'R':
			*using = P_RIGHT;
			--*argc;
			++*args;
		}						// end switch()
	}							// end if()

	// Check for the presence of specified arms, or pick one. *using set in
	// the above switch statement.
	switch (*using) {
	case P_LEFT:
		if(!have_fn(mech, LARM)) {
			mech_printf(mech, MECHALL,
						"You don't have %s in your left arm!", weapon);
			return 1;
		}
		break;

	case P_RIGHT:
		if(!have_fn(mech, RARM)) {
			mech_printf(mech, MECHALL,
						"You don't have %s in your right arm!", weapon);
			return 1;
		}
		break;

	case P_LEFT | P_RIGHT:
		if(!have_fn(mech, LARM))
			*using &= ~P_LEFT;
		if(!have_fn(mech, RARM))
			*using &= ~P_RIGHT;
		break;
	}							// end switch()

	// Fall through to success.
	return 0;
}								// end get_arm_args()

/**
 * Performs some generic checks for arms to punch with.
 */
int punch_checkArm(MECH * mech, int arm)
{
	char *arm_used = (arm == LARM ? "left" : "right");

	if(SectIsDestroyed(mech, arm)) {
		mech_printf(mech, MECHALL,
					"Your %s arm is destroyed, you can't punch with it.",
					arm_used);
		return 0;
	} else if(!OkayCritSectS(arm, 0, SHOULDER_OR_HIP)) {
		mech_printf(mech, MECHALL,
					"Your %s shoulder is destroyed, you can't punch with that arm.",
					arm_used);
		return 0;
	} else if(MechSections(mech)[arm].specials & CARRYING_CLUB) {
		mech_printf(mech, MECHALL,
					"You're carrying a club in your %s arm and can't punch with it.",
					arm_used);
		return 0;
	}
	// Fall through to success.
	return 1;
}								// end checkArm()

/**
 * Mech punch routines.
 */
void mech_punch(dbref player, void *data, char *buffer)
{
	MECH *mech = (MECH *) data;
	MAP *mech_map = getMap(mech->mapindex);
	char *argl[5];
	char **args = argl;
	int argc, ltohit = 4, rtohit = 4;
	int punching = P_LEFT | P_RIGHT;

	// Carry out the common checks (started, on map, etc.)
	cch(MECH_USUALO);
	// Make sure we have arms to punch with.
	ARM_PHYS_CHECK("punch");
	// Disallow quads from punching.
	QUAD_CHECK("punch");

	argc = mech_parseattributes(buffer, args, 5);

	// If the directive is true, use the pilot's piloting skill. If not, we
	// use a constant BTH of 4.
	if(mudconf.btech_phys_use_pskill)
		ltohit = rtohit = FindPilotPiloting(mech) - 1;

	// Manipulate punching var to contain only the arms we're punching with.
	if(get_arm_args(&punching, &argc, &args, mech, have_punch, "")) {
		return;
	}
	// Carry out our standard physical checks. This happens in PhysicalAttack
	// but the player gets double-spammed since PhysicalAttack can be called
	// twice in here. So, we add the check before.
	if(!phys_common_checks(mech))
		return;

	// For each arm we're using, check to make sure it's good to punch with
	// and carry out the roll if it is. 
	if(punching & P_LEFT) {
		if(punch_checkArm(mech, LARM))
			PhysicalAttack(mech, 10, ltohit, PA_PUNCH, argc, args,
						   mech_map, LARM);
	}

	if(punching & P_RIGHT) {
		if(punch_checkArm(mech, RARM))
			PhysicalAttack(mech, 10, rtohit, PA_PUNCH, argc, args,
						   mech_map, RARM);
	}
}								// end mech_punch()

/**
 * Mech clubbing routines.
 */
void mech_club(dbref player, void *data, char *buffer)
{
	MECH *mech = (MECH *) data;
	MAP *mech_map = getMap(mech->mapindex);
	char *args[5];
	int argc;
	int clubLoc = -1;

	// Make sure unit is started, on map, etc.
	cch(MECH_USUALO);
	// Make sure we're in a biped.
	ARM_PHYS_CHECK("club");
	// Don't let quads club.
	QUAD_CHECK("club");

	if(MechSections(mech)[RARM].specials & CARRYING_CLUB)
		clubLoc = RARM;
	else if(MechSections(mech)[LARM].specials & CARRYING_CLUB)
		clubLoc = LARM;

	if(clubLoc == -1) {
		DOCHECKMA(MechRTerrain(mech) != HEAVY_FOREST &&
				  MechRTerrain(mech) != LIGHT_FOREST,
				  "You can not seem to find any trees around to club with.");
		// Since we have trees nearby, assume the club goes to right hand.
		clubLoc = RARM;
	}

	argc = mech_parseattributes(buffer, args, 5);

	DOCHECKMA(SectIsDestroyed(mech, LARM),
			  "Your left arm is destroyed, you can't club.");
	DOCHECKMA(SectIsDestroyed(mech, RARM),
			  "Your right arm is destroyed, you can't club.");
	DOCHECKMA(!OkayCritSectS(RARM, 0, SHOULDER_OR_HIP),
			  "You can't club anyone with a destroyed or missing right shoulder.");
	DOCHECKMA(!OkayCritSectS(LARM, 0, SHOULDER_OR_HIP),
			  "You can't club anyone with a destroyed or missing left shoulder.");
	DOCHECKMA(!OkayCritSectS(RARM, 3, HAND_OR_FOOT_ACTUATOR),
			  "You can't club anyone with a destroyed or missing right hand.");
	DOCHECKMA(!OkayCritSectS(LARM, 3, HAND_OR_FOOT_ACTUATOR),
			  "You can't club anyone with a destroyed or missing left hand.");

	// Clubbing is usually done with the right arm but a club may be
	// grabbed by the left hand. Clubbing requires both arms to be cycled,
	// but only one is checked by PhysicalAttack(). So, we check both
	// here just in case.
	DOCHECKMA(SectHasBusyWeap(mech, LARM) || SectHasBusyWeap(mech, RARM),
			  "You have weapons recycling on your arms.");

	PhysicalAttack(mech, 5,
				   (mudconf.btech_phys_use_pskill ? FindPilotPiloting(mech) -
					1 : 4) + 2 * MechSections(mech)[RARM].basetohit +
				   2 * MechSections(mech)[LARM].basetohit, PA_CLUB, argc,
				   args, mech_map, RARM);
}								// end mech_club()

/**
 * Check to see if the specified arm can be used to axe with.
 */
int axe_checkArm(MECH * mech, int arm)
{
	char *arm_used = (arm == RARM ? "right" : "left");

	if(SectIsDestroyed(mech, arm)) {
		mech_printf(mech, MECHALL,
					"Your %s arm is destroyed, you can't axe with it",
					arm_used);
		return 0;
	} else if(!OkayCritSectS(arm, 0, SHOULDER_OR_HIP)) {
		mech_printf(mech, MECHALL,
					"Your %s shoulder is destroyed, you can't axe with that arm.",
					arm_used);
		return 0;
	} else if(!OkayCritSectS(arm, 3, HAND_OR_FOOT_ACTUATOR)) {
		mech_printf(mech, MECHALL,
					"Your left hand is destroyed, you can't axe with that arm.",
					arm_used);
		return 0;
	}
	// Fall through to success.    
	return 1;
}								// end axe_checkArm()

/**
 * Mech axe routines.
 */
void mech_axe(dbref player, void *data, char *buffer)
{
	MECH *mech = (MECH *) data;
	MAP *mech_map = getMap(mech->mapindex);
	char *argl[5];
	char **args = argl;
	int argc, ltohit = 4, rtohit = 4;
	int using = P_LEFT | P_RIGHT;

	// Make sure we're started, on a map, etc.
	cch(MECH_USUALO);
	// Do we have arms?
	ARM_PHYS_CHECK("axe");
	// Make sure we're not a quad.
	QUAD_CHECK("axe");

	argc = mech_parseattributes(buffer, args, 5);

	// If btech_phys_use_pskill is on, use the player's piloting skill.
	// If not, assume a skill level of 4.
	if(mudconf.btech_phys_use_pskill)
		ltohit = rtohit = FindPilotPiloting(mech) - 1;

	ltohit += MechSections(mech)[LARM].basetohit;
	rtohit += MechSections(mech)[RARM].basetohit;

	// Figure out which arm to use.
	if(get_arm_args(&using, &argc, &args, mech, have_axe, "an axe")) {
		return;
	}

	if(using & P_LEFT) {
		if(axe_checkArm(mech, LARM))
			PhysicalAttack(mech, 5, ltohit, PA_AXE, argc, args, mech_map,
						   LARM);
	}
	if(using & P_RIGHT) {
		if(axe_checkArm(mech, RARM))
			PhysicalAttack(mech, 5, rtohit, PA_AXE, argc, args, mech_map,
						   RARM);
	}
	// We don't have an axe.
	DOCHECKMA(!using,
			  "You may lack the axe, but not the will! Try punch/club until you find one.");
}								// end mech_axe()

/**
 * Check to see if the specified arm can be used to saw with.
 */
int saw_checkArm(MECH * mech, int arm)
{
	char *arm_used = (arm == RARM ? "right" : "left");

	if(SectIsDestroyed(mech, arm)) {
		mech_printf(mech, MECHALL,
					"Your %s arm is destroyed, you can't saw with it",
					arm_used);
		return 0;
	} else if(!OkayCritSectS(arm, 0, SHOULDER_OR_HIP)) {
		mech_printf(mech, MECHALL,
					"Your %s shoulder is destroyed, you can't saw with that arm.",
					arm_used);
		return 0;
	}
	// Fall through to success.    
	return 1;
}								// end saw_checkArm()

/**
 * Mech dual saw routines.
 */
void mech_saw(dbref player, void *data, char *buffer)
{
	MECH *mech = (MECH *) data;
	MAP *mech_map = getMap(mech->mapindex);
	char *argl[5];
	char **args = argl;
	int argc, ltohit = 4, rtohit = 4;
	int using = P_LEFT | P_RIGHT;

	// Make sure we're started, on a map, etc.
	cch(MECH_USUALO);
	// Do we have arms?
	ARM_PHYS_CHECK("saw");
	// Make sure we're not a quad.
	QUAD_CHECK("saw");

	argc = mech_parseattributes(buffer, args, 5);

	// If btech_phys_use_pskill is on, use the player's piloting skill.
	// If not, assume a skill level of 4.
	if(mudconf.btech_phys_use_pskill)
		ltohit = rtohit = FindPilotPiloting(mech) - 1;

	ltohit += MechSections(mech)[LARM].basetohit;
	rtohit += MechSections(mech)[RARM].basetohit;

	// Figure out which arm to use.
	if(get_arm_args(&using, &argc, &args, mech, have_saw, "a saw")) {
		return;
	}

	if(using & P_LEFT) {
		if(saw_checkArm(mech, LARM))
			PhysicalAttack(mech, 7, ltohit, PA_SAW, argc, args, mech_map,
						   LARM);
	}
	if(using & P_RIGHT) {
		if(saw_checkArm(mech, RARM))
			PhysicalAttack(mech, 7, rtohit, PA_SAW, argc, args, mech_map,
						   RARM);
	}
	// We don't have a saw.
	DOCHECKMA(!using, "You don't have a dual saw!");
}								// end mech_saw()

/**
 * Check our arms to see if they can mace.
 */
int mace_checkArm(MECH * mech, int arm)
{
	char *arm_used = (arm == RARM ? "right" : "left");

	if(SectIsDestroyed(mech, arm)) {
		mech_printf(mech, MECHALL,
					"Your %s arm is destroyed, you can't use a mace with it.",
					arm_used);
		return 0;
	} else if(!OkayCritSectS(arm, 0, SHOULDER_OR_HIP)) {
		mech_printf(mech, MECHALL,
					"Your %s shoulder is destroyed, you can't use a mace with that arm.",
					arm_used);
		return 0;
	} else if(!OkayCritSectS(arm, 3, HAND_OR_FOOT_ACTUATOR)) {
		mech_printf(mech, MECHALL,
					"Your %s hand is destroyed, you can't use a mace with that arm.",
					arm_used);
		return 0;
	}
	// Fall through to success.
	return 1;
}								// end mace_checkArm()

/**
 * Mech mace routines.
 */
void mech_mace(dbref player, void *data, char *buffer)
{
	MECH *mech = (MECH *) data;
	MAP *mech_map = getMap(mech->mapindex);
	char *argl[5];
	char **args = argl;
	int argc, ltohit = 4, rtohit = 4;
	int using = P_LEFT | P_RIGHT;

	// Make sure we're started, on a map, etc.
	cch(MECH_USUALO);
	// Do we have arms?
	ARM_PHYS_CHECK("mace");
	// Make sure we're not a quad.
	QUAD_CHECK("mace");

	argc = mech_parseattributes(buffer, args, 5);

	// If btech_phys_use_pskill is on, use the player's piloting skill.
	// If not, assume a skill level of 4.
	if(mudconf.btech_phys_use_pskill)
		ltohit = rtohit = FindPilotPiloting(mech) - 1;

	ltohit += MechSections(mech)[LARM].basetohit;
	rtohit += MechSections(mech)[RARM].basetohit;

	// Figure out which arm to use.
	if(get_arm_args(&using, &argc, &args, mech, have_mace, "a mace")) {
		return;
	}

	if(using & P_LEFT) {
		if(mace_checkArm(mech, LARM))
			PhysicalAttack(mech, 4, ltohit, PA_MACE, argc, args, mech_map,
						   LARM);
	}
	if(using & P_RIGHT) {
		if(mace_checkArm(mech, RARM))
			PhysicalAttack(mech, 4, rtohit, PA_MACE, argc, args, mech_map,
						   RARM);
	}
	// We don't have a mace.
	DOCHECKMA(!using, "You don't have a mace!");
}								// end mech_mace()

/**
 * Check our arms to see if they can chop.
 */
int sword_checkArm(MECH * mech, int arm)
{
	char *arm_used = (arm == RARM ? "right" : "left");

	if(SectIsDestroyed(mech, arm)) {
		mech_printf(mech, MECHALL,
					"Your %s arm is destroyed, you can't use a sword with it.",
					arm_used);
		return 0;
	} else if(!OkayCritSectS(arm, 0, SHOULDER_OR_HIP)) {
		mech_printf(mech, MECHALL,
					"Your %s shoulder is destroyed, you can't use a sword with that arm.",
					arm_used);
		return 0;
	} else if(!OkayCritSectS(arm, 3, HAND_OR_FOOT_ACTUATOR)) {
		mech_printf(mech, MECHALL,
					"Your %s hand is destroyed, you can't use a sword with that arm.",
					arm_used);
		return 0;
	}
	// Fall through to success.
	return 1;
}								// end sword_checkArm()

/**
 * Mech sword routines.
 */
void mech_sword(dbref player, void *data, char *buffer)
{
	MECH *mech = (MECH *) data;
	MAP *mech_map = getMap(mech->mapindex);
	char *argl[5];
	char **args = argl;
	int argc, ltohit = 3, rtohit = 3;
	int using = P_LEFT | P_RIGHT;

	// Make sure we're started, on a map, etc.
	cch(MECH_USUALO);
	// Do we have arms to chop with?
	ARM_PHYS_CHECK("chop");
	// Quads can't do it.
	QUAD_CHECK("chop");

	argc = mech_parseattributes(buffer, args, 5);

	// If btech_phys_use_pskill is defined, use the pilot's piloting skill,
	// otherwise use a constant skill 3 for left hand, 2 for right.
	//
	// NOTE: This seems funky to have different skills for left/right when
	// this define is off but not on.
	if(mudconf.btech_phys_use_pskill)
		ltohit = rtohit = FindPilotPiloting(mech) - 2;

	ltohit += MechSections(mech)[LARM].basetohit;
	rtohit += MechSections(mech)[RARM].basetohit;

	// Which arm(s) have sword crits?
	if(get_arm_args(&using, &argc, &args, mech, have_sword, "a sword")) {
		return;
	}

	if(using & P_LEFT) {
		if(sword_checkArm(mech, LARM))
			PhysicalAttack(mech, 10, ltohit, PA_SWORD, argc, args, mech_map,
						   LARM);
	}

	if(using & P_RIGHT) {
		if(sword_checkArm(mech, RARM))
			PhysicalAttack(mech, 10, rtohit, PA_SWORD, argc, args, mech_map,
						   RARM);
	}
	// Ninja what?
	DOCHECKMA(!using, "You have no sword to chop people with!");
}								// end mech_sword()

/**
 * Mech tripping command hook.
 */
void mech_trip(dbref player, void *data, char *buffer)
{
	mech_kickortrip(player, data, buffer, PA_TRIP);
}								// end mech_trip()

/**
 * Mech kick command hook.
 */
void mech_kick(dbref player, void *data, char *buffer)
{
	mech_kickortrip(player, data, buffer, PA_KICK);
}								// end mech_trip()

/**
 * Mech kick/trip routines.
 */
void mech_kickortrip(dbref player, void *data, char *buffer, int AttackType)
{
	MECH *mech = (MECH *) data;
	MAP *mech_map = getMap(mech->mapindex);
	char *argl[5];
	char **args = argl;
	int argc;
	int rl = RLEG, ll = LLEG;
	int leg;
	int using = P_RIGHT;

	// Make sure we're started, on a map, etc.
	cch(MECH_USUALO);
	// If we're a quad, re-map front legs.
	if(MechIsQuad(mech)) {
		rl = RARM;
		ll = LARM;
	}
	// See if we have enough usable legs to kick/trip with.
	GENERIC_CHECK("kick", CountDestroyedLegs(mech));

	argc = mech_parseattributes(buffer, args, 5);

	// Figure out which leg we're using.
	if(get_arm_args(&using, &argc, &args, mech, have_punch, "")) {
		return;
	}

	switch (using) {
	case P_LEFT:
		leg = ll;
		break;

	case P_RIGHT:
		leg = rl;
		break;

	default:
	case P_LEFT | P_RIGHT:
		mech_notify(mech, MECHALL,
					"What, yer gonna LEVITATE? I Don't Think So.");
		return;
	}

	if((MechCritStatus(mech) & HIP_DAMAGED))
	{
		mech_printf(mech, MECHALL,
					"You can't %s with a destroyed hip.",
					phys_form(AttackType, 0));
		return;
	}

	PhysicalAttack(mech, 5,
				   (mudconf.btech_phys_use_pskill ? FindPilotPiloting(mech) -
					2 : 3), AttackType, argc, args, mech_map, leg);
}								// end mech_kickortrip()

/**
 * Mech/tank charge routines
 */
void mech_charge(dbref player, void *data, char *buffer)
{
	MECH *mech = (MECH *) data, *target;
	MAP *mech_map = getMap(mech->mapindex);
	int targetnum;
	char targetID[5];
	char *args[5];
	int argc;
	int wcDeadLegs = 0;

	// Make sure we're started, on a map, etc.
	cch(MECH_USUALO);

	// Mechwarriors can't chage.
	DOCHECK(MechType(mech) == CLASS_MW ||
			MechType(mech) == CLASS_BSUIT,
			"You cannot charge without a 'mech!");

	// Salvage vehicles can't charge.
	DOCHECK(MechType(mech) != CLASS_MECH &&
			(MechType(mech) != CLASS_VEH_GROUND ||
			 MechSpecials(mech) & SALVAGE_TECH),
			"You cannot charge with this vehicle!");

	// Figure out if we have enough legs to kick with.
	if(MechType(mech) == CLASS_MECH) {
		/* set the number of dead legs we have */
		wcDeadLegs = CountDestroyedLegs(mech);

		DOCHECK(!MechIsQuad(mech) && (wcDeadLegs > 0),
				"With one leg? Are you kidding?");
		DOCHECK(!MechIsQuad(mech) && (wcDeadLegs > 1),
				"Without legs? Are you kidding?");
		DOCHECK(wcDeadLegs > 1,
				"It'd unbalance you too much in your condition..");
		DOCHECK(wcDeadLegs > 2, "Exactly _what_ are you going to kick with?");
	}							// end if() - Dead leg counting.

	argc = mech_parseattributes(buffer, args, 2);

	switch (argc) {
		// No arguments given with charge. Assume default target.
	case 0:
		DOCHECKMA(MechTarget(mech) == -1,
				  "You do not have a default target set!");

		target = getMech(MechTarget(mech));

		if(!target) {
			mech_notify(mech, MECHALL, "Invalid default target!");
			MechTarget(mech) = -1;
			return;
		}
		// Don't allow charging Mechwarriors.
		if(MechType(target) == CLASS_MW) {
			mech_notify(mech, MECHALL,
						"You can't charge THAT sack of bones and squishy bits!");
			return;
		}

		MechChargeTarget(mech) = MechTarget(mech);
		mech_notify(mech, MECHALL, "Charge target set to default target.");
		break;

		// We've supplied an argument, either a '-' or an ID.
	case 1:
		if(args[0][0] == '-') {
			MechChargeTarget(mech) = -1;
			MechChargeTimer(mech) = 0;
			MechChargeDistance(mech) = 0;
			mech_notify(mech, MECHPILOT, "You are no longer charging.");
			return;
		}

		targetID[0] = args[0][0];
		targetID[1] = args[0][1];
		targetnum = FindTargetDBREFFromMapNumber(mech, targetID);

		DOCHECKMA(targetnum == -1, "Target is not in line of sight!");

		target = getMech(targetnum);
		DOCHECKMA(!InLineOfSight_NB(mech, target, MechX(target),
									MechY(target), FaMechRange(mech, target)),
				  "Target is not in line of sight!");

		if(!target) {
			mech_notify(mech, MECHALL, "Invalid target data!");
			return;
		}
		// Don't allow charging mechwarriors.
		if(MechType(target) == CLASS_MW) {
			mech_notify(mech, MECHALL,
						"You can't charge THAT sack of bones and squishy bits!");
			return;
		}

		MechChargeTarget(mech) = targetnum;

		mech_printf(mech, MECHALL, "%s target set to %s.",
					MechType(mech) == CLASS_MECH ? "Charge" : "Ram",
					GetMechToMechID(mech, target));
		break;

		// Something other than 0-1 arguments.
	default:
		notify(player, "Invalid number of arguments!");
	}
}								// end mech_charge()

/*
 * Home to the code to carry out physical attacks.
 *
 * NOTE: Do NOT put any logic/checker code in here that is specific to a
 * certain type of attack if possible. Put it in its respective function.
 * Only things that are generic and on-specific to an attack type go here.
 */
void PhysicalAttack(MECH * mech, int damageweight, int baseToHit,
					int AttackType, int argc, char **args, MAP * mech_map,
					int sect)
{
	MECH *target;
	float range;
	float maxRange = 1;
	char targetID[2];
	int targetnum, roll, swarmingUs;
	char location[20];
	int ts = 0, iwa;
	int RbaseToHit, glance = 0;
	

	/*
	 * Common Checks
	 */

	// Since we can punch with two arms, often back to back, we want to run
	// these generic checks in mech_punch() -BEFORE- PhysicalAttack() is called
	// twice (if we have two working arms).
	if(AttackType != PA_PUNCH)
		if(!phys_common_checks(mech))
			return;

#define Check(num,okval,mod) \
  if (AttackType == PA_PUNCH) \
    if (MechType(mech) == CLASS_MECH) \
      if (PartIsNonfunctional(mech, sect, num) || \
          GetPartType(mech, sect, num) != \
          I2Special(okval)) \
              baseToHit += mod;

	Check(1, UPPER_ACTUATOR, 2);
	Check(2, LOWER_ACTUATOR, 2);
	Check(3, HAND_OR_FOOT_ACTUATOR, 1);

	// All weapons must be cycled in the target limb.
	if(SectHasBusyWeap(mech, sect)) {
		ArmorStringFromIndex(sect, location, MechType(mech), MechMove(mech));
		mech_printf(mech, MECHALL,
					"You have weapons recycling on your %s.", location);
		return;
	}
	// Figure out what to do with the arguments provided with the physical
	// command.
	switch (argc) {
	case -1:
	case 0:
		// No argument
		DOCHECKMA(MechTarget(mech) == -1, "You do not have a target set!");

		// Populate target variable with current lock.
		target = getMech(MechTarget(mech));
		DOCHECKMA(!target, "Invalid default target!");

		break;
	default:
		// In this case, default means user has specified an argument
		// with the physical attack.

		// Populate target variable from user input.
		targetID[0] = args[0][0];
		targetID[1] = args[0][1];
		targetnum = FindTargetDBREFFromMapNumber(mech, targetID);
		target = getMech(targetnum);

		DOCHECKMA(targetnum == -1, "Target is not in line of sight!");
		DOCHECKMA(!target, "Invalid default target!");
	}							// end switch() - argc checking

	// Is the target swarming us?
	swarmingUs = (MechSwarmTarget(target) == mech->mynum ? 1 : 0);

	/*
	 * Common checks.
	 */

	// If we're attacking something while fallen that isn't swarming us,
	// no-go it. Kicks/trips are automatically stopped.
	if(Fallen(mech) && (AttackType == PA_KICK || AttackType == PA_TRIP)) {
		mech_printf(mech, MECHALL, "You can't %s from a prone position.",
					phys_form(AttackType, 0));

		return;
		// If we are fallen AND
		//   The target is not a BSuit AND We're not punching
	} else if(Fallen(mech) &&
			  (MechType(target) != CLASS_VEH_GROUND &&
			   MechType(target) != CLASS_BSUIT)) {
		mech_printf(mech, MECHALL,
					"You can't %s from a prone position.",
					phys_form(AttackType, 0));

		return;
	} else if(Fallen(mech) && MechType(target) == CLASS_BSUIT && !swarmingUs) {
		mech_notify(mech, MECHALL,
					"You may only physical suits that are swarming you while prone.");
		return;
	} else if(Fallen(mech) && MechType(target) == CLASS_VEH_GROUND &&
			  AttackType != PA_PUNCH) {
		mech_notify(mech, MECHALL,
					"You may only punch vehicles while prone.");
		return;
	}							// end if() - Physical while fallen.

	range = FaMechRange(mech, target);

	DOCHECKMA(!InLineOfSight_NB(mech, target, MechX(target),
								MechY(target), range),
			  "Target is not in line of sight!");

	// BSuits have to be <= 0.5 hexes to attack units.
	if((MechType(target) == CLASS_BSUIT) || (MechType(target) == CLASS_MW))
		maxRange = 0.5;

	DOCHECKMA(range >= maxRange, "Target out of range!");

	DOCHECKMA(Jumping(target),
			  "You can't perform physical attacks on airborne mechs!");

    DOCHECKMA(MechTeam(target) == MechTeam(mech) && 
            MechNoFriendlyFire(mech),
            "You can't attack a teammate with FFSafeties on!");

    DOCHECKMA(MechTeam(target) == MechTeam(mech) && 
            MapNoFriendlyFire(mech_map),
            "Friendly Fire? I don't think so...");

	DOCHECKMA(MechType(target) == CLASS_MW && !MechPKiller(mech),
			  "That's a living, breathing person! Switch off the safety first, "
			  "if you really want to assassinate the target.");

	DOCHECKMA(MechCritStatus(mech) & MECH_STUNNED,
		"You are still recovering from your stunning experience!");
	/*
	 * Attack-Specific checks.
	 */
	DOCHECKMA(AttackType == PA_PUNCH &&
			  (MechType(target) == CLASS_VEH_GROUND) &&
			  !Fallen(mech),
			  "You can't punch vehicles unless you are prone!");

	// As per BMR, can only trip mechs.
	DOCHECKMA(AttackType == PA_TRIP && MechType(target) != CLASS_MECH,
			  "You can only trip mechs!");

	// Can't trip mechs that are fallen or in the process of standing.
	DOCHECKMA(AttackType == PA_TRIP && (Fallen(target) || Standing(target)),
			  "Your target is already down!");

	// We're attacking a ground/naval unit.    
	if(MechMove(target) != MOVE_VTOL && MechMove(target) != MOVE_FLY) {

		if((AttackType != PA_KICK && AttackType != PA_TRIP) &&
		   (MechZ(mech) >= MechZ(target))) {
			int isTooLow = 0;	// Track whether we're too low or not.

			// If it's a fallen mech, too low.
			if(MechType(target) == CLASS_MECH && Fallen(target))
				isTooLow = 1;

			// If it's not a mech, bsuit, or DS, too low.
			if(MechType(target) != CLASS_MECH &&
			   MechType(target) != CLASS_BSUIT && !IsDS(target))
				isTooLow = 1;

			// If it's a ground vehicle and we're fallen, then we can
			// punch as per BMR.
			if(AttackType == PA_PUNCH &&
			   MechType(target) == CLASS_VEH_GROUND && Fallen(mech))
				isTooLow = 0;

			// If it's a suit that's not on us, we can't physical it.
			if(MechType(target) == CLASS_BSUIT && swarmingUs == 0) {
				mech_printf(mech, MECHALL,
							"You can't directly physical suits that are swarmed or mounted on another mech!");
				return;
			}					// end if() - Disallow physicals on swarmed/mounted suits.

			if(isTooLow == 1) {
				mech_printf(mech, MECHALL,
							"The target is too low in elevation for you to %s.",
							phys_form(AttackType, 0));
				return;
			}					// end if() - Check isTooLow
		}						// end if() - Target is too low checks.

		DOCHECKMA((AttackType == PA_KICK || AttackType == PA_TRIP) &&
				  MechZ(mech) < MechZ(target),
				  "The target is too high in elevation for you to kick at.");

		DOCHECKMA(MechZ(mech) - MechZ(target) > 1 ||
				  MechZ(target) - MechZ(mech) > 1,
				  "You can't attack, the elevation difference is too large.");

		DOCHECKMA((AttackType == PA_KICK || AttackType == PA_TRIP) &&
				  (MechZ(target) < MechZ(mech) &&
				   (((MechType(target) == CLASS_MECH) && Fallen(target)) ||
					(MechType(target) == CLASS_VEH_GROUND) ||
					(MechType(target) == CLASS_BSUIT) ||
					(MechType(target) == CLASS_MW))),
				  "The target is too low in elevation for you to kick.")

	} else {					// We're attacking a VTOL/Aero.

		if((AttackType != PA_KICK) && MechZ(target) - MechZ(mech) > 3) {
			mech_printf(mech, MECHALL,
						"The target is too far away for you to %s.",
						phys_form(AttackType, 0));
		}

		if((AttackType == PA_KICK || AttackType == PA_TRIP) &&
		   MechZ(mech) != MechZ(target)) {
			mech_printf(mech, MECHALL,
						"The target is too far away for you to %s.",
						phys_form(AttackType, 0));
			return;
		}

		DOCHECKMA(!(MechZ(target) - MechZ(mech) > -1 &&
					MechZ(target) - MechZ(mech) < 4),
				  "You can't attack, the elevation difference is too large.");
	}							// end if/else() - Ground/VTOL + Physical Z comparisons

	/* Check weapon arc! */
	/* Theoretically, physical attacks occur only to 'real' forward
	   arc, not rottorsoed one, but we let it pass this time */
	/* This is wrong according to BMR 
	 *
	 * Which states that the Torso twist is taken into account
	 * as well as punching/axing/swords can attack in their
	 * respective arcs - Dany
	 *
	 * So I went and changed it according to FASA rules */
	if(AttackType == PA_KICK || AttackType == PA_TRIP) {

		ts = MechStatus(mech) & (TORSO_LEFT | TORSO_RIGHT);
		MechStatus(mech) &= ~ts;
		iwa = InWeaponArc(mech, MechFX(target), MechFY(target));
		MechStatus(mech) |= ts;

		DOCHECKMA(!(iwa & FORWARDARC),
				  "Target is not in your 'real' forward arc!");

	} else {					// We're punching, clubbing, or other sharp things.

		iwa = InWeaponArc(mech, MechFX(target), MechFY(target));

		if(AttackType == PA_CLUB) {
			// Clubs are a frontal attack. Go off of the forward arc, don't
			// take arms into account.
			DOCHECKMA(!(iwa & FORWARDARC) && swarmingUs != 1,
					  "Target is not in your forward arc!");
		} else {
			// For other attacks, check on a per-arm basis.
			if(sect == RARM) {
				// We're attacking with right arm. Forward or right will do.
				DOCHECKMA(!
						  ((iwa & FORWARDARC) || (iwa & RSIDEARC)
						   || swarmingUs),
						  "Target is not in your forward or right side arc!");
			} else {
				// We're attacking with left arm. Forward or left will do.
				DOCHECKMA(!((iwa & FORWARDARC) || (iwa & LSIDEARC))
						  || swarmingUs,
						  "Target is not in your forward or left side arc!");

			}					// end 

		}						// end if/else() - club/punch arc check

	}							// end if/else() - kick/punch arc check

	/**
     * Add in the movement modifiers 
     */

	// If we have melee_specialist advantage, knock -1 off the BTH.
	baseToHit += HasBoolAdvantage(MechPilot(mech), "melee_specialist") ?
		MIN(0, AttackMovementMods(mech) - 1) : AttackMovementMods(mech);

	baseToHit += TargetMovementMods(mech, target, 0.0);

	// BSuits get +1 BTH
	baseToHit += MechType(target) == CLASS_BSUIT ? 1 : 0;

	// Kicking a BSuit is +3 BTH
	baseToHit += ((MechType(target) == CLASS_BSUIT) &&
				  (AttackType == PA_KICK)) ? 3 : 0;

#ifdef MOVEMENT_MODES
	// A dodging unit is +2, requires maneuvering_ace.
	if(Dodging(target))
		baseToHit += 2;
#endif

	// Saws get a +1 BTH.
	if(AttackType == PA_SAW)
		baseToHit += 1;

	// Maces get a +2 BTH.
	if(AttackType == PA_MACE)
		baseToHit += 2;

	// If we're axing or chopping a bsuit, add +3 to BTH, else (punching) +5.
	if(AttackType != PA_PUNCH &&
	   MechType(target) == CLASS_BSUIT && MechSwarmTarget(target) > 0)
		baseToHit += (AttackType != PA_PUNCH) ? 3 : 5;

	// As per BMR, can only physical bsuits with punches, axes, or swords.
	// Added saw since it's the same idea.
	DOCHECKMA(AttackType == PA_KICK &&
			  MechType(target) == CLASS_BSUIT &&
			  MechSwarmTarget(target) > 0,
			  "You can't hit a swarmed suit with that, try a hand-held weapon!");

	roll = Roll();

	// Carry out the attack.
	mech_printf(mech, MECHALL,
				"You try to %s %s.  BTH:  %d,\tRoll:  %d",
				phys_form(AttackType, 0),
				GetMechToMechID(mech, target), baseToHit, roll);

	mech_printf(target, MECHSTARTED, "%s tries to %s you!",
				GetMechToMechID(target, mech), phys_form(AttackType, 0));

	// We send to MechAttacks channel
	SendAttacks(tprintf("#%i attacks #%i (%s) (%i/%i)",
						mech->mynum,
						target->mynum,
						phys_form(AttackType, 0), baseToHit, roll));

	// Set the appropriate section(s) to recycle.
	SetRecycleLimb(mech, sect, PHYSICAL_RECYCLE_TIME);

	/*
	 * Attack-specific recycles and flags.
	 */
	if(AttackType == PA_AXE || AttackType == PA_SWORD || AttackType == PA_SAW
	   || AttackType == PA_MACE)
		MechSections(mech)[sect].config |= AXED;

	if(AttackType == PA_PUNCH)
		MechSections(mech)[sect].config &= ~AXED;

	// Clubbing recycles both arms. 
	if(AttackType == PA_CLUB)
		SetRecycleLimb(mech, LARM, PHYSICAL_RECYCLE_TIME);

	RbaseToHit = baseToHit;
	if(mudconf.btech_glancing_blows == 2)
		RbaseToHit = baseToHit - 1;
	// We've successfully hit the target.
	if(roll >= RbaseToHit) {
		phys_succeed(mech, target, AttackType);
		if (mudconf.btech_glancing_blows && (roll == RbaseToHit)) {
			MechLOSBroadcast(target,"is nicked by a glancing blow!");
			mech_notify(target, MECHALL, "You are nicked by a glancing blow!");
			glance = 1 ;
		}
		if(AttackType == PA_CLUB) {
			int clubLoc = -1;

			if(MechSections(mech)[RARM].specials & CARRYING_CLUB)
				clubLoc = RARM;
			else if(MechSections(mech)[LARM].specials & CARRYING_CLUB)
				clubLoc = LARM;

			if(clubLoc > -1) {
				mech_notify(mech, MECHALL, "Your club shatters on contact.");
				MechLOSBroadcast(mech,
								 "'s club shatters with a loud *CRACK*!");

				MechSections(mech)[clubLoc].specials &= ~CARRYING_CLUB;
			}
		}						// End if() - Club shattering

		// Do the deed - Damage the victim. If we're tripping, we don't do
		// damage but try to make a skill roll.
		if(AttackType != PA_TRIP)
			PhysicalDamage(mech, target, damageweight, AttackType, sect, glance);
		else
			PhysicalTrip(mech, target);

	} else {					// We have failed!
		phys_fail(mech, target, AttackType);

		if(MechType(target) == CLASS_BSUIT &&
		   MechSwarmTarget(target) == mech->mynum) {

			if(!MadePilotSkillRoll(mech, 4)) {
				mech_notify(mech, MECHALL,
							"Uh oh. You miss the little buggers, but hit yourself!");
				MechLOSBroadcast(mech, "misses, and hits itself!");

				PhysicalDamage(mech, mech, damageweight, AttackType, sect, glance);
			}					// If we really screw up against suits swarmed on ourselves,
			// nail us for damage.
		}						// end if() - Suit + Swarmed + Physical + Self Damage checks

		if(AttackType == PA_KICK || AttackType == PA_CLUB ||
		   AttackType == PA_MACE) {
			int failRoll = (AttackType == PA_KICK ? 0 : 2);

			mech_notify(mech, MECHALL,
						"You miss and try to remain standing!");

			// We fail the piloting skill roll and flop on our face.
			if(!MadePilotSkillRoll(mech, failRoll)) {
				mech_notify(mech, MECHALL,
							"You lose your balance and fall down!");
				MechFalls(mech, 1, 1);
			}					// end if() - Miss/fall.
		}						// end if() - Miss kick/club and risk falling.
	}							// end if() - Physical failure handling.
}								//end PhysicalAttack()

extern int global_physical_flag;

#define MyDamageMech(a,b,c,d,e,f,g,h,i) \
        global_physical_flag = 1 ; DamageMech(a,b,c,d,e,f,g,h,i,-1,0,-1,0,0); \
        global_physical_flag = 0
#define MyDamageMech2(a,b,c,d,e,f,g,h,i) \
        global_physical_flag = 2 ; DamageMech(a,b,c,d,e,f,g,h,i,-1,0,-1,0,0); \
        global_physical_flag = 0

/*
 * Try to trip the victim.
 */
void PhysicalTrip(MECH * mech, MECH * target)
{
	// If we trip our target (who is a mech), make a roll to see if he falls.
	if(!MadePilotSkillRoll(target, 0) && !Fallen(target)) {

		// Emit to Attacker
		mech_printf(mech, MECHALL,
					"You trip %s!", GetMechToMechID(mech, target));

		// Emit to victim and LOS.
		mech_notify(target, MECHSTARTED,
					"You are tripped and fall to the ground!");
		MechLOSBroadcast(target, "trips up and falls down!");

		MechFalls(target, 1, 0);
	} else {
		MechLOSBroadcast(target, "manages to stay upright!");
	}
}								// end PhysicalTrip()

/*
 * Damage the victim.
 */
void PhysicalDamage(MECH * mech, MECH * target, int weightdmg,
					int AttackType, int sect, int glance)
{
	int hitloc = 0, damage, hitgroup = 0, isrear, iscritical, i;

	// If we're hitting with a sword, adjust damage differently from
	// a typical physical.
	if(AttackType == PA_SWORD)
		damage = (MechTons(mech) + 5) / weightdmg + 1;
	else if(AttackType == PA_SAW)
		// Saws do a constant 7 damage due to their mechanical nature.
		damage = 7;
	else
		damage = (MechTons(mech) + weightdmg / 2) / weightdmg;

	// Figure in TSM damage bonus.    
	if((MechHeat(mech) >= 9.) && (MechSpecials(mech) & TRIPLE_MYOMER_TECH))
		damage = damage * 2;

	// If we have melee_specialist, add a point of damage.    
	if(HasBoolAdvantage(MechPilot(mech), "melee_specialist"))
		damage++;

	switch (AttackType) {
	case PA_PUNCH:
		// If we have damaged/missing actuators, lose damage.
		if(!OkayCritSectS(sect, 2, LOWER_ACTUATOR))
			damage = damage / 2;
		if(!OkayCritSectS(sect, 1, UPPER_ACTUATOR))
			damage = damage / 2;

		hitgroup = FindAreaHitGroup(mech, target);

		if(MechType(mech) == CLASS_MECH) {
			// Hit locs for fallen units. Currently not even allowed
			// but we'll leave it in, someone may want to enable it later.
			// EXCEPTION: You may punch vehicles in same hex while proned.
			if(Fallen(mech)) {
				if((MechType(target) != CLASS_MECH) || (Fallen(target) &&
														(MechElevation(mech)
														 ==
														 MechElevation
														 (target))))
					hitloc =
						FindTargetHitLoc(mech, target, &isrear, &iscritical);
				else if(!Fallen(target)
						&& (MechElevation(mech) > MechElevation(target)))
					hitloc = FindPunchLocation(hitgroup);
				else if(MechElevation(mech) == MechElevation(target))
					hitloc = FindKickLocation(hitgroup);
			} else if(MechElevation(mech) < MechElevation(target)) {
				if(Fallen(target) || MechType(target) != CLASS_MECH)
					hitloc = FindTargetHitLoc(mech, target, &isrear,
											  &iscritical);
				else
					hitloc = FindKickLocation(hitgroup);
			} else
				hitloc = FindPunchLocation(hitgroup);
		} else {
			isrear = hitgroup == REAR;
			hitloc = FindTargetHitLoc(mech, target, &isrear, &iscritical);
		}
		break;
		// End punch hitloc code.
	case PA_SWORD:
	case PA_AXE:
	case PA_MACE:
	case PA_CLUB:
		hitgroup = FindAreaHitGroup(mech, target);

		if(MechType(mech) == CLASS_MECH) {
			if(MechElevation(mech) < MechElevation(target)) {
				if(Fallen(target) || MechType(target) != CLASS_MECH)
					hitloc =
						FindTargetHitLoc(mech, target, &isrear, &iscritical);
				else
					hitloc = FindKickLocation(hitgroup);
			} else if(MechElevation(mech) > MechElevation(target)) {
				hitloc = FindPunchLocation(hitgroup);
			} else {
				hitloc = FindTargetHitLoc(mech, target, &isrear, &iscritical);
			}
		} else {
			isrear = hitgroup == REAR;
			hitloc = FindTargetHitLoc(mech, target, &isrear, &iscritical);
		}
		break;
		// End club hitloc code.

	case PA_KICK:
		// Reduce damage if actuators are missing/damaged.
		if(!OkayCritSectS(sect, 2, LOWER_ACTUATOR))
			damage = damage / 2;

		if(!OkayCritSectS(sect, 1, UPPER_ACTUATOR))
			damage = damage / 2;

		if(Fallen(target) || MechType(target) != CLASS_MECH)
			hitloc = FindTargetHitLoc(mech, target, &isrear, &iscritical);
		else {
			hitgroup = FindAreaHitGroup(mech, target);

			if(MechElevation(mech) > MechElevation(target))
				hitloc = FindPunchLocation(hitgroup);
			else {
				hitloc = FindKickLocation(hitgroup);

				if(!GetSectInt(target, hitloc) &&
				   GetSectInt(target, (i = BOUNDED(0, 5 + (6 - hitloc),
												   NUM_SECTIONS - 1))))
					hitloc = i;
			}
		}
		break;
		// End kick hitloc code.
	}							// end switch() - hitloc selection.

	if(glance)
		damage = (damage + 1) / 2;
	// Damage the target.
	MyDamageMech(target, mech, 1, MechPilot(mech), hitloc,
				 (hitgroup == BACK) ? 1 : 0, 0, damage, 0);

	// If we've successfully hit a suit, knock him off.
	if(MechType(target) == CLASS_BSUIT && MechSwarmTarget(target) > 0 &&
	   AttackType != PA_KICK)
		StopSwarming(target, 0);

	// If we kick our target (who is a mech), make a roll to see if he falls.
	if(MechType(target) == CLASS_MECH && AttackType == PA_KICK)
		if(!MadePilotSkillRoll(target, 0) && !Fallen(target)) {
			mech_notify(target, MECHSTARTED,
						"The kick knocks you to the ground!");
			MechLOSBroadcast(target, "stumbles and falls down!");
			MechFalls(target, 1, 0);
		}
}								// end PhysicalDamage()

#define CHARGE_SECTIONS 6
#define DFA_SECTIONS    4

/* 4 if pure FASA */

const int resect[CHARGE_SECTIONS] =
	{ LARM, RARM, LLEG, RLEG, LTORSO, RTORSO };

/*
 * Executed at the end of a DFA
 */
int DeathFromAbove(MECH * mech, MECH * target)
{
	int baseToHit = 5;
	int roll;
	int hitGroup;
	int hitloc;
	int isrear = 0;
	int iscritical = 0;
	int target_damage;
	int mech_damage;
	int spread;
	int i, tmpi;
	char location[50];

	/* Weapons recycling check on each major section */
	for(i = 0; i < DFA_SECTIONS; i++)
		if(SectHasBusyWeap(mech, resect[i])) {
			ArmorStringFromIndex(resect[i], location, MechType(mech),
								 MechMove(mech));
			mech_printf(mech, MECHALL,
						"You have weapons recycling on your %s.", location);
			return 0;
		}
	// Our target is no longer on the map.
	DOCHECKMA0((mech->mapindex != target->mapindex),
			   "Your target is no longer valid.");

#ifdef BT_MOVEMENT_MODES
	DOCHECKMA0(Dodging(mech) || MoveModeLock(mech),
			   "You cannot use physicals while using a special movement mode.");
#endif

	DOCHECKMA0(MechSections(mech)[LLEG].recycle ||
			   MechSections(mech)[RLEG].recycle,
			   "Your legs are still recovering from your last attack.");
	DOCHECKMA0(MechSections(mech)[RARM].recycle ||
			   MechSections(mech)[LARM].recycle,
			   "Your arms are still recovering from your last attack.");

	DOCHECKMA0(Jumping(target),
			   "Your target is airborne, you cannot land on it.");

	if((MechType(target) == CLASS_VTOL) || (MechType(target) == CLASS_AERO) ||
	   (MechType(target) == CLASS_DS))
		DOCHECKMA0(!Landed(target),
				   "Your target is airborne, you cannot land on it.");

	if(mudconf.btech_phys_use_pskill)
		baseToHit = FindPilotPiloting(mech);

	baseToHit += (HasBoolAdvantage(MechPilot(mech), "melee_specialist") ?
				  MIN(0,
					  AttackMovementMods(mech)) -
				  1 : AttackMovementMods(mech));
	baseToHit += TargetMovementMods(mech, target, 0.0);
	baseToHit += MechType(target) == CLASS_BSUIT ? 1 : 0;

#ifdef BT_MOVEMENT_MODES
	if(Dodging(target))
		baseToHit += 2;
#endif

	DOCHECKMA0(baseToHit > 12,
			   tprintf
			   ("DFA: BTH %d\tYou choose not to attack and land from your jump.",
				baseToHit));

	roll = Roll();
	mech_printf(mech, MECHALL, "DFA: BTH %d\tRoll: %d", baseToHit, roll);

	MechStatus(mech) &= ~JUMPING;
	MechStatus(mech) &= ~DFA_ATTACK;

	if(roll >= baseToHit) {
		/* OUCH */
		mech_printf(target, MECHSTARTED,
					"DEATH FROM ABOVE!!!\n%s lands on you from above!",
					GetMechToMechID(target, mech));
		mech_notify(mech, MECHALL, "You land on your target legs first!");
		MechLOSBroadcasti(mech, target, "lands on %s!");

		hitGroup = FindAreaHitGroup(mech, target);
		if(hitGroup == BACK)
			isrear = 1;

		target_damage = (3 * MechRealTons(mech)) / 10;

		if(MechTons(mech) % 10)
			target_damage++;

		if(HasBoolAdvantage(MechPilot(mech), "melee_specialist"))
			target_damage++;

		spread = target_damage / 5;

		for(i = 0; i < spread; i++) {
			if(Fallen(target) || MechType(target) != CLASS_MECH)
				hitloc =
					FindHitLocation(target, hitGroup, &iscritical, &isrear);
			else
				hitloc = FindPunchLocation(hitGroup);

			MyDamageMech(target, mech, 1, MechPilot(mech), hitloc, isrear,
						 iscritical, 5, 0);
		}

		if(target_damage % 5) {
			if(Fallen(target) || (MechType(target) != CLASS_MECH))
				hitloc =
					FindHitLocation(target, hitGroup, &iscritical, &isrear);
			else
				hitloc = FindPunchLocation(hitGroup);

			MyDamageMech(target, mech, 1, MechPilot(mech), hitloc, isrear,
						 iscritical, (target_damage % 5), 0);
		}

		mech_damage = MechTons(mech) / 5;

		spread = mech_damage / 5;

		for(i = 0; i < spread; i++) {
			hitloc = FindKickLocation(FRONT);
			MyDamageMech2(mech, mech, 0, -1, hitloc, 0, 0, 5, 0);
		}

		if(mech_damage % 5) {
			hitloc = FindKickLocation(FRONT);
			MyDamageMech2(mech, mech, 0, -1, hitloc, 0, 0,
						  (mech_damage % 5), 0);
		}

		if(!Fallen(mech)) {
			if(!MadePilotSkillRoll(mech, 4)) {
				mech_notify(mech, MECHALL,
							"Your piloting skill fails and you fall over!!");
				MechLOSBroadcast(mech, "stumbles and falls down!");
				MechFalls(mech, 1, 0);
			}
			if(MechType(target) == CLASS_MECH &&
			   !MadePilotSkillRoll(target, 2)) {
				mech_notify(target, MECHSTARTED,
							"Your piloting skill fails and you fall over!!");
				MechLOSBroadcast(target, "stumbles and falls down!");
				MechFalls(target, 1, 0);
			}
		}

	} else {
		/* Missed DFA attack */
		if(!Fallen(mech)) {
			mech_notify(mech, MECHALL,
						"You miss your DFA attack and fall on your back!!");
			MechLOSBroadcast(mech, "misses DFA and falls down!");
		}

		mech_damage = MechTons(mech) / 5;
		spread = mech_damage / 5;

		for(i = 0; i < spread; i++) {
			hitloc = FindHitLocation(mech, BACK, &iscritical, &tmpi);
			MyDamageMech2(mech, mech, 0, -1, hitloc, 1, iscritical, 5, 0);
		}

		if(mech_damage % 5) {
			hitloc = FindHitLocation(mech, BACK, &iscritical, &tmpi);
			MyDamageMech2(mech, mech, 0, -1, hitloc, 1, iscritical,
						  (mech_damage % 5), 0);
		}

		/* now damage pilot */
		if(!MadePilotSkillRoll(mech, 2)) {
			mech_notify(mech, MECHALL,
						"You take personal injury from the fall!");
			headhitmwdamage(mech, 1);
		}

		MechSpeed(mech) = 0.0;
		MechDesiredSpeed(mech) = 0.0;

		MakeMechFall(mech);
		MechZ(mech) = MechElevation(mech);
		MechFZ(mech) = MechZ(mech) * ZSCALE;

		if(MechZ(mech) < 0)
			MechFloods(mech);

	}

	for(i = 0; i < DFA_SECTIONS; i++)
		SetRecycleLimb(mech, resect[i], PHYSICAL_RECYCLE_TIME);

	return 1;
}								// end DeathFromAbove()

/*
 * Executed when we're ready to finish the charge.
 */
void ChargeMech(MECH * mech, MECH * target)
{
	int baseToHit = 5;
	int roll;
	int hitGroup;
	int hitloc;
	int isrear = 0;
	int iscritical = 0;
	int target_damage;
	int mech_damage;
	int received_damage;
	int inflicted_damage;
	int spread;
	int i;
	int mech_charge;
	int target_charge;
	int mech_baseToHit;
	int targ_baseToHit;
	int mech_roll;
	int targ_roll;
	int done = 0;
	char location[50];
	int ts, iwa;
	char emit_buff[LBUF_SIZE];

	/* Are they both charging ? */
	if(MechChargeTarget(target) == mech->mynum) {
		/* They are both charging each other */
		mech_charge = 1;
		target_charge = 1;

		/* Check the sections of the first unit for weapons that are cycling */
		done = 0;
		for(i = 0; i < CHARGE_SECTIONS && !done; i++) {
			if(SectHasBusyWeap(mech, resect[i])) {
				ArmorStringFromIndex(resect[i], location, MechType(mech),
									 MechMove(mech));
				mech_printf(mech, MECHALL,
							"You have weapons recycling on your %s.",
							location);
				mech_charge = 0;
				done = 1;
			}
		}

		/* Check the sections of the second unit for weapons that are cycling */
		done = 0;
		for(i = 0; i < CHARGE_SECTIONS && !done; i++) {
			if(SectHasBusyWeap(target, resect[i])) {
				ArmorStringFromIndex(resect[i], location, MechType(target),
									 MechMove(target));
				mech_printf(target, MECHALL,
							"You have weapons recycling on your %s.",
							location);
				target_charge = 0;
				done = 1;
			}
		}

		/* Is the second unit capable of charging */
		if(!Started(target) || Uncon(target) || Blinded(target))
			target_charge = 0;
		/* Is the first unit capable of charging */
		if(!Started(mech) || Uncon(mech) || Blinded(mech))
			mech_charge = 0;

		/* Is the first unit moving fast enough to charge */
		if(MechSpeed(mech) < MP1) {
			mech_notify(mech, MECHALL,
						"You aren't moving fast enough to charge.");
			mech_charge = 0;
		}

		/* Is the second unit moving fast enough to charge */
		if(MechSpeed(target) < MP1) {
			mech_notify(target, MECHALL,
						"You aren't moving fast enough to charge.");
			target_charge = 0;
		}

		/* Check to see if any sections cycling from a previous attack */
		if(MechType(mech) == CLASS_MECH) {
			/* Is the first unit's legs cycling */
			if(MechSections(mech)[LLEG].recycle ||
			   MechSections(mech)[RLEG].recycle) {
				mech_notify(mech, MECHALL,
							"Your legs are still recovering from your last attack.");
				mech_charge = 0;
			}
			/* Is the first unit's arms cycling */
			if(MechSections(mech)[RARM].recycle ||
			   MechSections(mech)[LARM].recycle) {
				mech_notify(mech, MECHALL,
							"Your arms are still recovering from your last attack.");
				mech_charge = 0;
			}
		} else {
			/* Is the first unit's front side cycling */
			if(MechSections(mech)[FSIDE].recycle) {
				mech_notify(mech, MECHALL,
							"You are still recovering from your last attack!");
				mech_charge = 0;
			}
		}

		/* Check to see if any sections cycling from a previous attack */
		if(MechType(target) == CLASS_MECH) {
			/* Is the second unit's legs cycling */
			if(MechSections(target)[LLEG].recycle ||
			   MechSections(target)[RLEG].recycle) {
				mech_notify(target, MECHALL,
							"Your legs are still recovering from your last attack.");
				target_charge = 0;
			}
			/* Is the second unit's arms cycling */
			if(MechSections(target)[RARM].recycle ||
			   MechSections(target)[LARM].recycle) {
				mech_notify(target, MECHALL,
							"Your arms are still recovering from your last attack.");
				target_charge = 0;
			}
		} else {
			/* Is the second unit's front side cycling */
			if(MechSections(target)[FSIDE].recycle) {
				mech_notify(target, MECHALL,
							"You are still recovering from your last attack!");
				target_charge = 0;
			}
		}

		/* Is the second unit jumping */
		if(Jumping(target)) {
			mech_notify(mech, MECHALL,
						"Your target is jumping, you charge underneath it.");
			mech_notify(target, MECHALL,
						"You can't charge while jumping, try death from above.");
			mech_charge = 0;
			target_charge = 0;
		}

		/* Is the first unit jumping */
		if(Jumping(mech)) {
			mech_notify(target, MECHALL,
						"Your target is jumping, you charge underneath it.");
			mech_notify(mech, MECHALL,
						"You can't charge while jumping, try death from above.");
			mech_charge = 0;
			target_charge = 0;
		}

		/* Is the second unit fallen and the first unit not a tank */
		if(Fallen(target) && (MechType(mech) != CLASS_VEH_GROUND)) {
			mech_notify(mech, MECHALL,
						"Your target's too low for you to charge it!");
			mech_charge = 0;
		}

		/* Not sure at the moment if I need this here, but I figured
		 * couldn't hurt for now */
		/* Is the first unit fallen and the second unit not a tank */
		if(Fallen(mech) && (MechType(target) != CLASS_VEH_GROUND)) {
			mech_notify(target, MECHALL,
						"Your target's too low for you to charge it!");
			target_charge = 0;
		}

		/* If the second unit is a mech it can only charge mechs */
		if((MechType(target) == CLASS_MECH) && (MechType(mech) != CLASS_MECH)) {
			mech_notify(target, MECHALL, "You can only charge mechs!");
			target_charge = 0;
		}

		/* If the first unit is a mech it can only charge mechs */
		if((MechType(mech) == CLASS_MECH) && (MechType(target) != CLASS_MECH)) {
			mech_notify(mech, MECHALL, "You can only charge mechs!");
			mech_charge = 0;
		}

		/* If the second unit is a tank, it can only charge tanks and mechs */
		if((MechType(target) == CLASS_VEH_GROUND) &&
		   ((MechType(mech) != CLASS_MECH) &&
			(MechType(mech) != CLASS_VEH_GROUND))) {
			mech_notify(target, MECHALL,
						"You can only charge mechs and tanks!");
			target_charge = 0;
		}

		/* If the first unit is a tank, it can only charge tanks and mechs */
		if((MechType(mech) == CLASS_VEH_GROUND) &&
		   ((MechType(target) != CLASS_MECH) &&
			(MechType(target) != CLASS_VEH_GROUND))) {
			mech_notify(mech, MECHALL,
						"You can only charge mechs and tanks!");
			mech_charge = 0;
		}

		/* Are they stunned ? */
		if(CrewStunned(mech)) {
			mech_notify(mech, MECHALL, "You are too stunned to ram!");
			mech_charge = 0;
		}

		if(CrewStunned(target)) {
			mech_notify(target, MECHALL, "You are too stunned to ram!");
			target_charge = 0;
		}

		/* Are they trying to unjam their turrets ? */
		if(UnjammingTurret(mech)) {
			mech_notify(mech, MECHALL,
						"You are too busy unjamming your turret!");
			mech_charge = 0;
		}

		if(UnjammingTurret(target)) {
			mech_notify(mech, MECHALL,
						"You are too busy unjamming your turret!");
			target_charge = 0;
		}

		/* Check the arcs to make sure the target is in the front arc */
		ts = MechStatus(mech) & (TORSO_LEFT | TORSO_RIGHT);
		MechStatus(mech) &= ~ts;
		if(!(InWeaponArc(mech, MechFX(target), MechFY(target)) & FORWARDARC)) {
			mech_notify(mech, MECHALL,
						"Your charge target is not in your forward arc and you are unable to charge it.");
			mech_charge = 0;
		}
		MechStatus(mech) |= ts;

		ts = MechStatus(target) & (TORSO_LEFT | TORSO_RIGHT);
		MechStatus(mech) &= ~ts;
		if(!(InWeaponArc(target, MechFX(mech), MechFY(mech)) & FORWARDARC)) {
			mech_notify(target, MECHALL,
						"Your charge target is not in your forward arc and you are unable to charge it.");
			target_charge = 0;
		}
		MechStatus(mech) |= ts;

		/* Now to calculate how much damage the first unit will do */
		if(mudconf.btech_newcharge)
			target_damage = (((((float)
								MechChargeDistance(mech)) * MP1) -
							  MechSpeed(target) * cos((MechFacing(mech) -
													   MechFacing(target)) *
													  (M_PI / 180.))) *
							 MP_PER_KPH) * (MechRealTons(mech) + 5) / 10;
		else
			target_damage =
				((MechSpeed(mech) -
				  MechSpeed(target) * cos((MechFacing(mech) -
										   MechFacing(target)) * (M_PI /
																  180.))) *
				 MP_PER_KPH) * (MechRealTons(mech) + 5) / 10;

		if(HasBoolAdvantage(MechPilot(mech), "melee_specialist"))
			target_damage++;

		/* Not able to do any damage */
		if(target_damage <= 0) {
			mech_notify(mech, MECHPILOT,
						"Your target pulls away from you and you are unable to charge it.");
			mech_charge = 0;
		}

		/* Now see how much damage the second unit will do */
		if(mudconf.btech_newcharge)
			mech_damage = (((((float)
							  MechChargeDistance(target)) * MP1) -
							MechSpeed(mech) * cos((MechFacing(target) -
												   MechFacing(mech)) * (M_PI /
																		180.)))
						   * MP_PER_KPH) * (MechRealTons(target) + 5) / 10;
		else
			mech_damage =
				((MechSpeed(target) -
				  MechSpeed(mech) * cos((MechFacing(target) -
										 MechFacing(mech)) * (M_PI / 180.))) *
				 MP_PER_KPH) * (MechRealTons(target) + 5) / 10;

		if(HasBoolAdvantage(MechPilot(target), "melee_specialist"))
			mech_damage++;

		/* Not able to do any damage */
		if(mech_damage <= 0) {
			mech_notify(target, MECHPILOT,
						"Your target pulls away from you and you are unable to charge it.");
			target_charge = 0;
		}

		/* BTH for first unit */
		mech_baseToHit = 5;
		mech_baseToHit +=
			FindPilotPiloting(mech) - FindSPilotPiloting(target);

		mech_baseToHit +=
			(HasBoolAdvantage(MechPilot(mech), "melee_specialist") ?
			 MIN(0, AttackMovementMods(mech) - 1) : AttackMovementMods(mech));

		mech_baseToHit += TargetMovementMods(mech, target, 0.0);

#ifdef BT_MOVEMENT_MODES
		if(Dodging(target))
			mech_baseToHit += 2;
#endif

		/* BTH for second unit */
		targ_baseToHit = 5;
		targ_baseToHit +=
			FindPilotPiloting(target) - FindSPilotPiloting(mech);

		targ_baseToHit +=
			(HasBoolAdvantage(MechPilot(target), "melee_specialist") ?
			 MIN(0,
				 AttackMovementMods(target) -
				 1) : AttackMovementMods(target));

		targ_baseToHit += TargetMovementMods(target, mech, 0.0);

#ifdef BT_MOVEMENT_MODES
		if(Dodging(mech))
			targ_baseToHit += 2;
#endif

		/* Now check to see if its possible for them to even charge */
		if(mech_charge)
			if(mech_baseToHit > 12) {
				mech_printf(mech, MECHALL,
							"Charge: BTH %d\tYou choose not to charge.",
							mech_baseToHit);
				mech_charge = 0;
			}

		if(target_charge)
			if(targ_baseToHit > 12) {
				mech_printf(target, MECHALL,
							"Charge: BTH %d\tYou choose not to charge.",
							targ_baseToHit);
				target_charge = 0;
			}

		/* Since neither can charge lets exit */
		if(!mech_charge && !target_charge) {
			/* MechChargeTarget(mech) and the others are set
			   after the return */
			MechChargeTarget(target) = -1;
			MechChargeTimer(target) = 0;
			MechChargeDistance(target) = 0;
			return;
		}

		/* Roll */
		mech_roll = Roll();
		targ_roll = Roll();

		if(mech_charge)
			mech_printf(mech, MECHALL,
						"Charge: BTH %d\tRoll: %d", mech_baseToHit,
						mech_roll);

		if(target_charge)
			mech_printf(target, MECHALL,
						"Charge: BTH %d\tRoll: %d", targ_baseToHit,
						targ_roll);

		/* Ok the first unit made its roll */
		if(mech_charge && mech_roll >= mech_baseToHit) {
			/* OUCH */
			mech_printf(target, MECHALL,
						"CRASH!!!\n%s charges into you!",
						GetMechToMechID(target, mech));
			mech_notify(mech, MECHALL,
						"SMASH!!! You crash into your target!");
			hitGroup = FindAreaHitGroup(mech, target);
			isrear = (hitGroup == BACK);

			/* Record the damage for debugging then dish it out */
			inflicted_damage = target_damage;
			spread = target_damage / 5;

			for(i = 0; i < spread; i++) {
				hitloc =
					FindHitLocation(target, hitGroup, &iscritical, &isrear);
				MyDamageMech(target, mech, 1, MechPilot(mech), hitloc,
							 isrear, iscritical, 5, 0);
			}

			if(target_damage % 5) {
				hitloc =
					FindHitLocation(target, hitGroup, &iscritical, &isrear);
				MyDamageMech(target, mech, 1, MechPilot(mech), hitloc,
							 isrear, iscritical, (target_damage % 5), 0);
			}

			hitGroup = FindAreaHitGroup(target, mech);
			isrear = (hitGroup == BACK);

			/* Ok now how much damage will the first unit take from
			 * charging */
			if(mudconf.btech_newcharge && mudconf.btech_tl3_charge)
				target_damage =
					(((((float) MechChargeDistance(mech)) * MP1) -
					  MechSpeed(target) *
					  cos((MechFacing(mech) -
						   MechFacing(target)) * (M_PI / 180.))) *
					 MP_PER_KPH) * (MechRealTons(mech) + 5) / 20;
			else
				target_damage = (MechRealTons(target) + 5) / 10;	/* REUSED! */

			/* Record the damage for debugging then dish it out */
			received_damage = target_damage;
			spread = target_damage / 5;

			for(i = 0; i < spread; i++) {
				hitloc =
					FindHitLocation(mech, hitGroup, &iscritical, &isrear);
				MyDamageMech2(mech, mech, 0, -1, hitloc, isrear,
							  iscritical, 5, 0);
			}

			if(target_damage % 5) {
				hitloc =
					FindHitLocation(mech, hitGroup, &iscritical, &isrear);
				MyDamageMech2(mech, mech, 0, -1, hitloc, isrear,
							  iscritical, (target_damage % 5), 0);
			}

			/* Stop him */
			MechSpeed(mech) = 0;
			MechDesiredSpeed(mech) = 0;

			/* Emit the damage for debugging purposes */
			snprintf(emit_buff, LBUF_SIZE, "#%i charges #%i (%i/%i) Distance:"
					 " %.2f DI: %i DR: %i", mech->mynum, target->mynum,
					 mech_baseToHit, mech_roll, MechChargeDistance(mech),
					 inflicted_damage, received_damage);
			SendDebug(emit_buff);

			/* Make the first unit roll for doing the charge if it is a mech */
			if(MechType(mech) == CLASS_MECH && !MadePilotSkillRoll(mech, 2)) {
				mech_notify(mech, MECHALL,
							"Your piloting skill fails and you fall over!!");
				MechFalls(mech, 1, 1);
			}
			/* Make the second unit roll for receiving the charge if it is a mech */
			if(MechType(mech) == CLASS_MECH && !MadePilotSkillRoll(target, 2)) {
				mech_notify(target, MECHALL,
							"Your piloting skill fails and you fall over!!");
				MechFalls(target, 1, 1);
			}
		}

		/* Ok the second unit made its roll */
		if(target_charge && targ_roll >= targ_baseToHit) {
			/* OUCH */
			mech_printf(mech, MECHALL,
						"CRASH!!!\n%s charges into you!",
						GetMechToMechID(mech, target));
			mech_notify(target, MECHALL,
						"SMASH!!! You crash into your target!");
			hitGroup = FindAreaHitGroup(target, mech);
			isrear = (hitGroup == BACK);

			/* Record the damage for debugging then dish it out */
			inflicted_damage = mech_damage;
			spread = mech_damage / 5;

			for(i = 0; i < spread; i++) {
				hitloc =
					FindHitLocation(mech, hitGroup, &iscritical, &isrear);
				MyDamageMech(mech, target, 1, MechPilot(target), hitloc,
							 isrear, iscritical, 5, 0);
			}

			if(mech_damage % 5) {
				hitloc =
					FindHitLocation(mech, hitGroup, &iscritical, &isrear);
				MyDamageMech(mech, target, 1, MechPilot(target), hitloc,
							 isrear, iscritical, (mech_damage % 5), 0);
			}

			hitGroup = FindAreaHitGroup(mech, target);
			isrear = (hitGroup == BACK);

			/* Ok now how much damage will the second unit take from
			 * charging */
			if(mudconf.btech_newcharge && mudconf.btech_tl3_charge)
				target_damage =
					(((((float) MechChargeDistance(target)) * MP1) -
					  MechSpeed(mech) *
					  cos((MechFacing(target) -
						   MechFacing(mech)) * (M_PI / 180.))) * MP_PER_KPH) *
					(MechRealTons(mech) + 5) / 20;
			else
				target_damage = (MechRealTons(mech) + 5) / 10;	/* REUSED! */

			/* Record the damage for debugging then dish it out */
			received_damage = target_damage;
			spread = target_damage / 5;

			for(i = 0; i < spread; i++) {
				hitloc =
					FindHitLocation(target, hitGroup, &iscritical, &isrear);
				MyDamageMech2(target, target, 0, -1, hitloc, isrear,
							  iscritical, 5, 0);
			}

			if(mech_damage % 5) {
				hitloc =
					FindHitLocation(target, hitGroup, &iscritical, &isrear);
				MyDamageMech2(target, target, 0, -1, hitloc, isrear,
							  iscritical, (mech_damage % 5), 0);
			}

			/* Stop him */
			MechSpeed(target) = 0;
			MechDesiredSpeed(target) = 0;

			/* Emit the damage for debugging purposes */
			snprintf(emit_buff, LBUF_SIZE, "#%i charges #%i (%i/%i) Distance:"
					 " %.2f DI: %i DR: %i", target->mynum, mech->mynum,
					 targ_baseToHit, targ_roll, MechChargeDistance(target),
					 inflicted_damage, received_damage);
			SendDebug(emit_buff);

			if(MechType(mech) == CLASS_MECH && !MadePilotSkillRoll(mech, 2)) {
				mech_notify(mech, MECHALL,
							"Your piloting skill fails and you fall over!!");
				MechFalls(mech, 1, 1);
			}
			if(MechType(target) == CLASS_MECH
			   && !MadePilotSkillRoll(target, 2)) {
				mech_notify(target, MECHALL,
							"Your piloting skill fails and you fall over!!");
				MechFalls(target, 1, 1);
			}
		}

		/* Cycle the sections so they can't make another attack for a while */
		if(MechType(mech) == CLASS_MECH) {
			for(i = 0; i < CHARGE_SECTIONS; i++)
				SetRecycleLimb(mech, resect[i], PHYSICAL_RECYCLE_TIME);
		} else {
			SetRecycleLimb(mech, FSIDE, PHYSICAL_RECYCLE_TIME);
			SetRecycleLimb(mech, TURRET, PHYSICAL_RECYCLE_TIME);
		}

		if(MechType(target) == CLASS_MECH) {
			for(i = 0; i < CHARGE_SECTIONS; i++)
				SetRecycleLimb(target, resect[i], PHYSICAL_RECYCLE_TIME);
		} else {
			SetRecycleLimb(target, FSIDE, PHYSICAL_RECYCLE_TIME);
			SetRecycleLimb(target, TURRET, PHYSICAL_RECYCLE_TIME);
		}

		/* MechChargeTarget(mech) and the others are set
		   after the return */
		MechChargeTarget(target) = -1;
		MechChargeTimer(target) = 0;
		MechChargeDistance(target) = 0;
		return;
	}

	/* Check to see if any weapons cycling in any of the sections */
	for(i = 0; i < CHARGE_SECTIONS; i++) {
		if(SectHasBusyWeap(mech, i)) {
			ArmorStringFromIndex(i, location, MechType(mech), MechMove(mech));
			mech_printf(mech, MECHALL,
						"You have weapons recycling on your %s.", location);
			return;
		}
	}

	/* Check if they going fast enough to charge */
	DOCHECKMA(MechSpeed(mech) < MP1,
			  "You aren't moving fast enough to charge.");

	/* Check to see if their sections cycling */
	if(MechType(mech) == CLASS_MECH) {
		DOCHECKMA(MechSections(mech)[LLEG].recycle ||
				  MechSections(mech)[RLEG].recycle,
				  "Your legs are still recovering from your last attack.");
		DOCHECKMA(MechSections(mech)[RARM].recycle ||
				  MechSections(mech)[LARM].recycle,
				  "Your arms are still recovering from your last attack.");
	} else {
		DOCHECKMA(MechSections(mech)[FSIDE].recycle,
				  "You are still recovering from your last attack!");
	}

	/* See if either the target or the attacker are jumping */
	DOCHECKMA(Jumping(target),
			  "Your target is jumping, you charge underneath it.");
	DOCHECKMA(Jumping(mech),
			  "You can't charge while jumping, try death from above.");

	/* If target is fallen make sure you in a tank */
	DOCHECKMA(Fallen(target) &&
			  (MechType(mech) != CLASS_VEH_GROUND),
			  "Your target's too low for you to charge it!");

	/* Only mechs can charge mechs */
	DOCHECKMA((MechType(mech) == CLASS_MECH) &&
			  (MechType(target) != CLASS_MECH), "You can only charge mechs!");

	/* Only tanks can charge tanks and mechs */
	DOCHECKMA((MechType(mech) == CLASS_VEH_GROUND) &&
			  ((MechType(target) != CLASS_MECH) &&
			   (MechType(target) != CLASS_VEH_GROUND)),
			  "You can only charge mechs and tanks!");

	/* Check the arc make sure target is in front arc */
	ts = MechStatus(mech) & (TORSO_LEFT | TORSO_RIGHT);
	MechStatus(mech) &= ~ts;
	iwa = InWeaponArc(mech, MechFX(target), MechFY(target));
	MechStatus(mech) |= ts;
	DOCHECKMA(!(iwa & FORWARDARC),
			  "Your charge target is not in your forward arc and you are unable to charge it.");

	/* Damage inflicted by the charge */
	if(mudconf.btech_newcharge)
		target_damage = (((((float)
							MechChargeDistance(mech)) * MP1) -
						  MechSpeed(target) * cos((MechFacing(mech) -
												   MechFacing(target)) *
												  (M_PI / 180.))) *
						 MP_PER_KPH) * (MechRealTons(mech) + 5) / 10 + 1;
	else
		target_damage =
			((MechSpeed(mech) - MechSpeed(target) * cos((MechFacing(mech) -
														 MechFacing(target)) *
														(M_PI / 180.))) *
			 MP_PER_KPH) * (MechRealTons(mech) + 5) / 10 + 1;

	if(HasBoolAdvantage(MechPilot(mech), "melee_specialist"))
		target_damage++;

	/* Not enough damage done so no charge */
	DOCHECKMP(target_damage <= 0,
			  "Your target pulls away from you and you are unable to charge it.");

	/* BTH */
	baseToHit += FindPilotPiloting(mech) - FindSPilotPiloting(target);

	baseToHit += (HasBoolAdvantage(MechPilot(mech), "melee_specialist") ?
				  MIN(0,
					  AttackMovementMods(mech) -
					  1) : AttackMovementMods(mech));

	baseToHit += TargetMovementMods(mech, target, 0.0);

#ifdef BT_MOVEMENT_MODES
	if(Dodging(target))
		baseToHit += 2;
#endif

	DOCHECKMA(baseToHit > 12,
			  tprintf("Charge: BTH %d\tYou choose not to charge.",
					  baseToHit));

	/* Roll */
	roll = Roll();
	mech_printf(mech, MECHALL, "Charge: BTH %d\tRoll: %d", baseToHit, roll);

	/* Did the charge work ? */
	if(roll >= baseToHit) {
		/* OUCH */
		MechLOSBroadcasti(mech, target, tprintf("%ss %%s!",
												MechType(mech) ==
												CLASS_MECH ? "charge" :
												"ram"));
		mech_printf(target, MECHSTARTED, "CRASH!!!\n%s %ss into you!",
					GetMechToMechID(target, mech),
					MechType(mech) == CLASS_MECH ? "charge" : "ram");
		mech_notify(mech, MECHALL, "SMASH!!! You crash into your target!");
		hitGroup = FindAreaHitGroup(mech, target);

		if(hitGroup == BACK)
			isrear = 1;
		else
			isrear = 0;

		/* Record the damage then dish it out */
		inflicted_damage = target_damage;
		spread = target_damage / 5;

		for(i = 0; i < spread; i++) {
			hitloc = FindHitLocation(target, hitGroup, &iscritical, &isrear);
			MyDamageMech(target, mech, 1, MechPilot(mech), hitloc, isrear,
						 iscritical, 5, 0);
		}

		if(target_damage % 5) {
			hitloc = FindHitLocation(target, hitGroup, &iscritical, &isrear);
			MyDamageMech(target, mech, 1, MechPilot(mech), hitloc, isrear,
						 iscritical, (target_damage % 5), 0);
		}

		hitGroup = FindAreaHitGroup(target, mech);
		isrear = (hitGroup == BACK);

		/* Damage done to the attacker for the charge */
		if(mudconf.btech_newcharge && mudconf.btech_tl3_charge)
			mech_damage =
				(((((float) MechChargeDistance(mech)) * MP1) -
				  MechSpeed(target) *
				  cos((MechFacing(mech) -
					   MechFacing(target)) * (M_PI / 180.))) * MP_PER_KPH) *
				(MechRealTons(target) + 5) / 20;
		else
			mech_damage = (MechRealTons(target) + 5) / 10;

		/* Record the damage then dish it out */
		received_damage = mech_damage;
		spread = mech_damage / 5;

		for(i = 0; i < spread; i++) {
			hitloc = FindHitLocation(mech, hitGroup, &iscritical, &isrear);
			MyDamageMech2(mech, mech, 0, -1, hitloc, isrear, iscritical, 5,
						  0);
		}

		if(mech_damage % 5) {
			hitloc = FindHitLocation(mech, hitGroup, &iscritical, &isrear);
			MyDamageMech2(mech, mech, 0, -1, hitloc, isrear, iscritical,
						  (mech_damage % 5), 0);
		}

		/* Force piloting roll for attacker if they are in a mech */
		if(MechType(mech) == CLASS_MECH && !MadePilotSkillRoll(mech, 2)) {
			mech_notify(mech, MECHALL,
						"Your piloting skill fails and you fall over!!");
			MechFalls(mech, 1, 1);
		}

		/* Force piloting roll for target if they are in a mech */
		if(MechType(target) == CLASS_MECH && !MadePilotSkillRoll(target, 2)) {
			mech_notify(target, MECHSTARTED,
						"Your piloting skill fails and you fall over!!");
			MechFalls(target, 1, 1);
		}

		/* Stop him */
		MechSpeed(mech) = 0;
		MechDesiredSpeed(mech) = 0;

		/* Emit the damage for debugging purposes */
		snprintf(emit_buff, LBUF_SIZE, "#%i charges #%i (%i/%i) Distance:"
				 " %.2f DI: %i DR: %i", mech->mynum, target->mynum, baseToHit,
				 roll, MechChargeDistance(mech), inflicted_damage,
				 received_damage);
		SendDebug(emit_buff);

	}

	/* Cycle the sections so they can't make another attack for a while */
	if(MechType(mech) == CLASS_MECH) {
		for(i = 0; i < CHARGE_SECTIONS; i++)
			SetRecycleLimb(mech, resect[i], PHYSICAL_RECYCLE_TIME);
	} else {
		SetRecycleLimb(mech, FSIDE, PHYSICAL_RECYCLE_TIME);
		SetRecycleLimb(mech, TURRET, PHYSICAL_RECYCLE_TIME);
	}
	return;
}								// end ChargeMech()

/*
 * Checks to see if we can grab a club with our arms.
 */
int checkGrabClubLocation(MECH * mech, int section, int emit)
{
	int tCanGrab = 1;
	char buf[100];
	char location[20];

	ArmorStringFromIndex(section, location, MechType(mech), MechMove(mech));

	if(SectIsDestroyed(mech, section)) {
		sprintf(buf, "Your %s is destroyed.", location);
		tCanGrab = 0;
	} else if(!OkayCritSectS(section, 3, HAND_OR_FOOT_ACTUATOR)) {
		sprintf(buf, "Your %s's hand actuator is destroyed or missing.",
				location);
		tCanGrab = 0;
	} else if(!OkayCritSectS(section, 0, SHOULDER_OR_HIP)) {
		sprintf(buf,
				"Your %s's shoulder actuator is destroyed or missing.",
				location);
		tCanGrab = 0;
	} else if(SectHasBusyWeap(mech, section)) {
		sprintf(buf, "Your %s is still recovering from it's last attack.",
				location);
		tCanGrab = 0;
	}

	if(!tCanGrab && emit)
		mech_notify(mech, MECHALL, buf);

	return tCanGrab;
}								// end checkGrabClubLocation()

/*
 * Handles the grabbing of a club.
 */
void mech_grabclub(dbref player, void *data, char *buffer)
{
	MECH *mech = (MECH *) data;
	int wcArgs = 0;
	int location = 0;
	char *args[1];
	char locname[20];

	cch(MECH_USUALO);

	wcArgs = mech_parseattributes(buffer, args, 1);

	// If we grabclub -, we're attempting to drop it.
	if(wcArgs >= 1 && toupper(args[0][0]) == '-') {
		if((MechSections(mech)[LARM].specials & CARRYING_CLUB) ||
		   (MechSections(mech)[RARM].specials & CARRYING_CLUB)) {
			DropClub(mech);
		} else {
			mech_notify(mech, MECHALL,
						"You aren't currently carrying a club.");
		}
		return;
	}							// end if() - Check to drop club.

	DOCHECKMA(MechIsQuad(mech), "Quads can't carry a club.");
	DOCHECKMA(Fallen(mech),
			  "You can't grab a club while lying flat on your face.");
	DOCHECKMA(Jumping(mech), "You can't grab a club while jumping!");
	DOCHECKMA(OODing(mech), "Your rapid descent prevents that.");
	DOCHECKMA(UnJammingAmmo(mech), "You are too busy unjamming a weapon!");
	DOCHECKMA(RemovingPods(mech), "You are too busy removing iNARC pods!");

	// If they already have a physical weapon, disallow the grabbing of a club.
	DOCHECKMA(have_axe(mech, LARM) || have_axe(mech, RARM),
			  "You can not grab a club if you carry an axe.");
	DOCHECKMA(have_sword(mech, LARM) || have_sword(mech, RARM),
			  "You can not grab a club if you carry a sword.");
	DOCHECKMA(have_mace(mech, LARM) || have_mace(mech, RARM),
			  "You can not grab a club if you carry an mace.");

	if(wcArgs == 0) {
		if(checkGrabClubLocation(mech, LARM, 0))
			location = LARM;
		else if(checkGrabClubLocation(mech, RARM, 0))
			location = RARM;
		else {
			mech_notify(mech, MECHALL,
						"You don't have a free arm with a working hand actuator!");
			return;
		}
	} else {

		// Figure out which arm to use.
		switch (toupper(args[0][0])) {
		case 'R':
			location = RARM;
			break;
		case 'L':
			location = LARM;
			break;
		default:
			mech_notify(mech, MECHALL, "Invalid option for 'grabclub'");
			return;
		}						// end switch() - Determine location.

		// see if we have actuators and a working arm.
		if(!checkGrabClubLocation(mech, location, 1))
			return;
	}

	DOCHECKMA(CarryingClub(mech), "You're already carrying a club.");
	DOCHECKMA(MechRTerrain(mech) != HEAVY_FOREST &&
			  MechRTerrain(mech) != LIGHT_FOREST,
			  "There don't appear to be any trees within grabbing distance.");

	ArmorStringFromIndex(location, locname, MechType(mech), MechMove(mech));

	MechLOSBroadcast(mech,
					 "reaches down and yanks a tree out of the ground!");
	mech_printf(mech, MECHALL,
				"You reach down and yank a tree out of the ground with your %s.",
				locname);

	// Grabbing a club sets a flag and recycles the arm used.
	MechSections(mech)[location].specials |= CARRYING_CLUB;
	SetRecycleLimb(mech, location, PHYSICAL_RECYCLE_TIME);
}								// end mech_grabclub()