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.utils.c,v 1.9 2005/08/03 21:40:54 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: Fri Dec 11 00:54:46 1998 fingon
 *
 */

#include "config.h"

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

#include "mech.h"
#include "map.h"
#include "mech.events.h"
#include "p.mech.restrict.h"
#include "p.mech.utils.h"
#include "p.mech.startup.h"
#include "p.ds.bay.h"
#include "p.btechstats.h"
#include "p.mechrep.h"
#include "p.crit.h"
#include "p.mech.combat.h"
#include "p.mech.damage.h"
#include "p.template.h"
#include "p.bsuit.h"
#include "p.mech.los.h"
#include "p.aero.bomb.h"
#include "autopilot.h"

#ifdef BT_ADVANCED_ECON
#include "p.mech.custom.h"
#include "p.mech.tech.do.h"
#endif

#ifdef BT_PART_WEIGHTS
/* From template.c */
extern int internalsweight[];
extern int cargoweight[];
#endif

#ifdef BT_MOVEMENT_MODES
#include "failures.h"
#endif

extern dbref pilot_override;

const char *mechtypenames[CLASS_LAST + 1] = {
    "mech", "tank", "VTOL", "vessel", "aerofighter", "DropShip"
};

const char *mechtypename(MECH * foo)
{
    return mechtypenames[(int) MechType(foo)];
}

int MNumber(MECH * mech, int low, int high)
{
    if ((muxevent_tick / RANDOM_TICK) != MechLastRndU(mech)) {
	MechRnd(mech) = random();
	MechLastRndU(mech) = muxevent_tick / RANDOM_TICK;
    }
    return (low + MechRnd(mech) % (high - low + 1));
}

char *MechIDS(MECH * mech, int islower)
{
    static char buf[3];

    if (mech) {
	buf[0] = MechID(mech)[0];
	buf[1] = MechID(mech)[1];
    } else {
	buf[0] = '*';
	buf[1] = '*';
    }
    buf[2] = 0;

    if (islower) {
	buf[0] = tolower(buf[0]);
	buf[1] = tolower(buf[1]);
    }
    return buf;
}


char *MyToUpper(char *string)
{
    if (*string)
	*string = toupper(*string);
    return string;
}

int CritsInLoc(MECH * mech, int index)
{
    if (MechType(mech) == CLASS_MECH)
	switch (index) {
	case HEAD:
	case RLEG:
	case LLEG:
	    return 6;
	case RARM:
	case LARM:
	    if (MechIsQuad(mech))
		return 6;
    } else if (MechType(mech) == CLASS_MW)
	return 2;
    else if (MechType(mech) == CLASS_AERO && index == AERO_COCKPIT)
	return 5;
    return NUM_CRITICALS;
}

int SectHasBusyWeap(MECH * mech, int sect)
{
    int i = 0, count, critical[MAX_WEAPS_SECTION];
    unsigned char weaptype[MAX_WEAPS_SECTION];
    unsigned char weapdata[MAX_WEAPS_SECTION];

    count = FindWeapons(mech, sect, weaptype, weapdata, critical);
    for (i = 0; i < count; i++)
	if (WpnIsRecycling(mech, sect, critical[i]))
	    return 1;
    return 0;
}


MAP *ValidMap(dbref player, dbref map)
{
    char *str;
    MAP *maps;

    DOCHECKN(!Good_obj(map), "Index out of range!");
    str = silly_atr_get(map, A_XTYPE);
    DOCHECKN(!str || !*str, "That is not a valid map! (no XTYPE!)");
    DOCHECKN(strcmp("MAP", str), "That is not a valid map!");
    DOCHECKN(!(maps = getMap(map)), "The map has not been allocated!!");
    return maps;
}

dbref FindMechOnMap(MAP * map, char *mechid)
{
    int loop;
    MECH *tempMech;

    for (loop = 0; loop < map->first_free; loop++)
	if (map->mechsOnMap[loop] != -1) {
	    tempMech = getMech(map->mechsOnMap[loop]);
	    if (tempMech && !strncasecmp(MechID(tempMech), mechid, 2))
		return tempMech->mynum;
	}
    return -1;
}

dbref FindTargetDBREFFromMapNumber(MECH * mech, char *mapnum)
{
    MAP *map;

    if (mech->mapindex == -1)
	return -1;
    map = getMap(mech->mapindex);
    if (!map) {
	SendError(tprintf("FTDBREFFMN:invalid map:Mech: %d  Index: %d",
		mech->mynum, mech->mapindex));
	mech->mapindex = -1;
	return -1;
    }
    return FindMechOnMap(map, mapnum);
}

void FindComponents(float magnitude, int degrees, float *x, float *y)
{
    *x = magnitude * fcos((float) (TWOPIOVER360 * (degrees + 90)));
    *y = magnitude * fsin((float) (TWOPIOVER360 * (degrees + 90)));
    *x = -(*x);			/* because 90 is to the right */
    *y = -(*y);			/* because y increases downwards */
}


static int Leave_Hangar(MAP * map, MECH * mech)
{
    MECH *car = NULL;
    int mapob;
    mapobj *mapo;

    /* For now, leaving leads to finding yourself on the new map
       at a predetermined position */
    mapob = mech->mapindex;
    if (MechCarrying(mech) > 0)
	car = getMech(MechCarrying(mech));
    DOCHECKMA0(!map->cf, "The entrance is still filled with rubble!");
    MechLOSBroadcast(mech, "has left the hangar.");
    mech_Rsetmapindex(GOD, (void *) mech, tprintf("%d",
	    (int) map->mapobj[TYPE_LEAVE]->obj));
    if (car)
	mech_Rsetmapindex(GOD, (void *) car, tprintf("%d",
		(int) map->mapobj[TYPE_LEAVE]->obj));
    map = getMap(mech->mapindex);
    if (mech->mapindex == mapob) {
	SendError(tprintf("#%d %s attempted to leave, but no target map?",
		mech->mynum, GetMechID(mech)));
	mech_notify(mech, MECHALL,
	    "Exit of this map is.. fubared. Please contact a wizard");
	return 0;
    }
    if (!(mapo = find_entrance_by_target(map, mapob))) {
	SendError(tprintf
	    ("#%d %s attempted to leave, but no target place was found? setting the mech at 0,0 at %d.",
		mech->mynum, GetMechID(mech), mech->mapindex));
	mech_notify(mech, MECHALL,
	    "Weird bug happened during leave. Please contact a wizard. ");
	return 1;
    }

    StopBSuitSwarmers(FindObjectsData(mech->mapindex), mech, 1);
    mech_notify(mech, MECHALL, tprintf("You have left %s.",
	    structure_name(mapo)));
    mech_Rsetxy(GOD, (void *) mech, tprintf("%d %d", mapo->x, mapo->y));
    ContinueFlying(mech);
    if (car)
	MirrorPosition(mech, car, 0);
    MechLOSBroadcast(mech, tprintf("has left %s at %d,%d.",
	    structure_name(mapo), MechX(mech), MechY(mech)));
    loud_teleport(mech->mynum, mech->mapindex);
    if (car)
	loud_teleport(car->mynum, mech->mapindex);
    if (In_Character(mech->mynum) &&
	Location(MechPilot(mech)) != mech->mynum) {
	mech_notify(mech, MECHALL,
	    "%ch%cr%cf%ciINTRUDER ALERT! INTRUDER ALERT!%c");
	mech_notify(mech, MECHALL,
	    "%ch%cr%cfAutomatic self-destruct sequence initiated...%c");
	mech_shutdown(GOD, (void *) mech, "");
    }
    auto_cal_mapindex(mech);
    if (MechSpeed(mech) > MMaxSpeed(mech))
        MechSpeed(mech) = MMaxSpeed(mech);
    return 1;
}


void CheckEdgeOfMap(MECH * mech)
{
    int pinned = 0;
    int linked;
    MAP *map;

    map = getMap(mech->mapindex);

    if (!map) {
	mech_notify(mech, MECHPILOT,
	    "You are on an invalid map! Map index reset!");
	mech_shutdown(MechPilot(mech), (void *) mech, "");
	SendError(tprintf("CheckEdgeofMap:invalid map:Mech: %d  Index: %d",
		mech->mynum, mech->mapindex));
	mech->mapindex = -1;
	return;
    }
    linked = map_linked(mech->mapindex);
    /* Prevents you from going off the map */
    /* Eventually this could wrap and all that.. */
    if (MechX(mech) < 0) {
	if (linked) {
	    MechX(mech) += map->map_width;
	    pinned = -1;
	} else {
	    MechX(mech) = 0;
	    pinned = 4;
	}
    } else if (MechX(mech) >= map->map_width) {
	if (linked) {
	    MechX(mech) -= map->map_width;
	    pinned = -1;
	} else {
	    MechX(mech) = map->map_width - 1;
	    pinned = 2;
	}
    }
    if (MechY(mech) < 0) {
	if (linked) {
	    pinned = -1;
	    MechY(mech) += map->map_height;
	} else {
	    MechY(mech) = 0;
	    pinned = 1;
	}
    } else if (MechY(mech) >= map->map_height) {
	if (linked) {
	    pinned = -1;
	    MechY(mech) -= map->map_height;
	} else {
	    MechY(mech) = map->map_height - 1;
	    pinned = 3;
	}
    }
    if (pinned > 0) {
	/* This is a DS bay. First, we need to check if the bay's doors are
	   blocked, one way or another.
	 */
	if (map->onmap && IsMech(map->onmap)) {
	    if (Leave_DS(map, mech))
		return;
	} else if (map->flags & MAPFLAG_MAPO && map->mapobj[TYPE_LEAVE])
	    if (Leave_Hangar(map, mech))
		return;
    }
    if (pinned) {
	MapCoordToRealCoord(MechX(mech), MechY(mech), &MechFX(mech),
	    &MechFY(mech));
	if (pinned > 0) {
	    mech_notify(mech, MECHALL, "You cannot move off this map!");
	    if (Jumping(mech) && !is_aero(mech))
		LandMech(mech);
	    MechCocoon(mech) = 0;
	    MechSpeed(mech) = 0.0;
	    MechDesiredSpeed(mech) = 0.0;
	    if (is_aero(mech)) {
		MechStartFX(mech) = 0.0;
		MechStartFY(mech) = 0.0;
		MechStartFZ(mech) = 0.0;
		if (!Landed(mech))
		    MaybeMove(mech);
	    }
	}
    }
}
int FindZBearing(float x0, float y0, float z0, float x1, float y1, float z1)
{
float hyp, opp, deg;

hyp = FindRange(x0, y0, z0, x1, y1, z1);
if (hyp <= 0.0)
    return 0;
opp = FindRange(0, 0, 0, 0, 0, fabsf(z1 - z0));
deg = asin(opp / hyp) * (180 / PI);
return ceilf(deg);
}

int FindBearing(float x0, float y0, float x1, float y1)
{
    float deltax, deltay;
    float temp, rads;
    int degrees;

    deltax = (x0 - x1);
    deltay = (y0 - y1);
    if (deltax == 0.0) {
	/* Quick handling inserted here */
	if (deltay > 0.0)
	    return 0;
	else
	    return 180;
    }
    temp = deltay / deltax;
    if (temp < 0.0)
	temp = -temp;
    rads = fatan(temp);
    degrees = (int) (rads * 10.0 / TWOPIOVER360);
    /* Round off degrees */
    degrees = (degrees + 5) / 10;
    if (deltax < 0.0 && deltay < 0.0)
	degrees += 180;
    else if (deltax < 0.0)
	degrees = 180 - degrees;
    else if (deltay < 0.0)
	degrees = 360 - degrees;
    return AcceptableDegree(degrees - 90);
}

int InWeaponArc(MECH * mech, float x, float y)
{
    int relat;
    int bearingToTarget;
    int res = NOARC;

    bearingToTarget = FindBearing(MechFX(mech), MechFY(mech), x, y);
    relat = MechFacing(mech) - bearingToTarget;
    if (MechType(mech) == CLASS_MECH || MechType(mech) == CLASS_MW ||
	MechType(mech) == CLASS_BSUIT) {
	if (MechStatus(mech) & TORSO_RIGHT)
	    relat += 59;
	else if (MechStatus(mech) & TORSO_LEFT)
	    relat -= 59;
    }
    relat = AcceptableDegree(relat);
    if (relat >= 300 || relat <= 60)
        res |= FORWARDARC;
    if (relat > 120 && relat < 240)
        res |= REARARC;
    if (relat >= 240 && relat < 300)
        res |= RSIDEARC;
    if (relat > 60 && relat <= 120)
        res |= LSIDEARC;

    if (MechHasTurret(mech)) {
    	relat = AcceptableDegree((MechFacing(mech) + MechTurretFacing(mech))
    				 - bearingToTarget);
    	if (relat >= 330 || relat <= 30)
    	    res |= TURRETARC;
    }
    if (res == NOARC)
    	SendError(tprintf("NoArc: #%d: BearingToTarget:%d Facing:%d",
    			  mech->mynum, bearingToTarget, MechFacing(mech)));
    return res;
}

char *FindGunnerySkillName(MECH * mech, int weapindx)
{
#ifndef BT_EXILE_MW3STATS
    switch (MechType(mech)) {
    case CLASS_BSUIT:
	return "Gunnery-BSuit";
    case CLASS_MECH:
	return "Gunnery-Battlemech";
    case CLASS_VEH_GROUND:
    case CLASS_VEH_NAVAL:
	return "Gunnery-Conventional";
    case CLASS_VTOL:
    case CLASS_AERO:
	return "Gunnery-Aerospace";
    case CLASS_SPHEROID_DS:
    case CLASS_DS:
	return "Gunnery-Spacecraft";
    case CLASS_MW:
	if (weapindx >= 0) {
	    if (!strcmp(MechWeapons[weapindx].name, "PC.Sword"))
		return "Blade";
	    if (!strcmp(MechWeapons[weapindx].name, "PC.Vibroblade"))
		return "Blade";
	}
	return "Small_Arms";
    }
#else
    if (weapindx < 0)
        return NULL;
    if (MechType(mech) == CLASS_MW) {
        if (weapindx >= 0) {
            if (!strcmp(MechWeapons[weapindx].name, "PC.Blade"))
                return "Blade";
            if (!strcmp(MechWeapons[weapindx].name, "PC.Vibroblade"))
                return "Blade";
	    if (!strcmp(MechWeapons[weapindx].name, "PC.Blazer"))
		return "Support_Weapons";
	    if (!strcmp(MechWeapons[weapindx].name, "PC.HeavyGyrojetGun"))
		return "Support_Weapons";
        return "Small_Arms";
        }
    } else if (IsArtillery(weapindx))
        return "Gunnery-Artillery";
    else if (IsMissile(weapindx))
        return "Gunnery-Missile";
    else if (IsBallistic(weapindx))
        return "Gunnery-Ballistic";
    else if (IsEnergy(weapindx))
        return "Gunnery-Laser";
    else if (IsFlamer(weapindx))
        return "Gunnery-Flamer";
#endif
    return NULL;
}

char *FindPilotingSkillName(MECH * mech)
{
#ifndef BT_EXILE_MW3STATS
switch (MechType(mech)) {
    case CLASS_MW:
	return "Running";
    case CLASS_BSUIT:
	return "Piloting-BSuit";
    case CLASS_MECH:
	return "Piloting-Battlemech";
    case CLASS_VEH_GROUND:
    case CLASS_VEH_NAVAL:
	return "Drive";
    case CLASS_VTOL:
    case CLASS_AERO:
	return "Piloting-Aerospace";
    case CLASS_SPHEROID_DS:
    case CLASS_DS:
	return "Piloting-Spacecraft";
    }
#else
if (MechType(mech) == CLASS_MW && MechRTerrain(mech) == WATER)
    return "Swimming";
switch (MechType(mech)) {
    case CLASS_MW:
        return "Running";
    case CLASS_BSUIT:
        return "Piloting-Bsuit";
    case CLASS_VEH_NAVAL:
        return "Piloting-Naval";
    case CLASS_DS:
    case CLASS_SPHEROID_DS:
        return "Piloting-Spacecraft";
    case CLASS_VTOL:
    case CLASS_AERO:
        return "Piloting-Aerospace";
}
switch (MechMove(mech)) {
    case MOVE_BIPED:
        return "Piloting-Biped";
    case MOVE_QUAD:
        return "Piloting-Quad";
    case MOVE_TRACK:
        return "Piloting-Tracked";
    case MOVE_HOVER:
        return "Piloting-Hover";
    case MOVE_WHEEL:
        return "Piloting-Wheeled";
}
#endif
return NULL;
}

#define MECHSKILL_PILOTING  0
#define MECHSKILL_GUNNERY   1
#define MECHSKILL_SPOTTING  2
#define MECHSKILL_ARTILLERY 3
#define NUM_MECHSKILLS      4
#define GENERIC_FIND_MECHSKILL(num,n) \
if (Quiet(mech->mynum)) \
{ str = silly_atr_get(mech->mynum, A_MECHSKILLS); \
if (*str) if (sscanf (str, "%d %d %d %d", &i[0], &i[1], &i[2], &i[3]) > num) \
return i[num] - n; }

int FindPilotPiloting(MECH * mech)
{
    char *str;
    int i[NUM_MECHSKILLS];

    GENERIC_FIND_MECHSKILL(MECHSKILL_PILOTING, 0);
    if (RGotPilot(mech))
	if ((str = FindPilotingSkillName(mech)))
	    return char_getskilltarget(MechPilot(mech), str, 0);
    return DEFAULT_PILOTING;
}

int FindSPilotPiloting(MECH * mech)
{
    return FindPilotPiloting(mech) + (MechMove(mech) ==
	MOVE_QUAD ? -2 : 0);
}

int FindPilotSpotting(MECH * mech)
{
    char *str;
    int i[NUM_MECHSKILLS];

    GENERIC_FIND_MECHSKILL(MECHSKILL_SPOTTING, 0);
    if (RGotPilot(mech))
	return (char_getskilltarget(MechPilot(mech), "Gunnery-Spotting",
		0));
    return DEFAULT_SPOTTING;
}

int FindPilotArtyGun(MECH * mech)
{
    char *str;
    int i[NUM_MECHSKILLS];

    GENERIC_FIND_MECHSKILL(MECHSKILL_ARTILLERY, 0);
    if (RGotGPilot(mech))
	return (char_getskilltarget(GunPilot(mech), "Gunnery-Artillery",
		0));
    return DEFAULT_ARTILLERY;
}


int FindPilotGunnery(MECH * mech, int weapindx)
{
    char *str;
    int i[NUM_MECHSKILLS];

    GENERIC_FIND_MECHSKILL(MECHSKILL_GUNNERY, 0);
    if (RGotGPilot(mech))
	if ((str = FindGunnerySkillName(mech, weapindx)))
	    return char_getskilltarget(GunPilot(mech), str, 0);
    return DEFAULT_GUNNERY;
}

char *FindTechSkillName(MECH * mech)
{
    switch (MechType(mech)) {
    case CLASS_MECH:
    case CLASS_BSUIT:
	return "Technician-Battlemech";
    case CLASS_VEH_GROUND:
    case CLASS_VEH_NAVAL:
	return "Technician-Mechanic";
    case CLASS_AERO:
    case CLASS_VTOL:
    case CLASS_SPHEROID_DS:
    case CLASS_DS:
	return "Technician-Aerospace";
#if 0				/* Used to be DS tech */
	return (char_getskilltarget(player, "Technician-Spacecraft", 0));
#endif
    }
    return NULL;
}

int FindTechSkill(dbref player, MECH * mech)
{
    char *skname;

    if ((skname = FindTechSkillName(mech)))
	return (char_getskilltarget(player, skname, 0));
    return 18;
}

int MadePilotSkillRoll(MECH * mech, int mods)
{
    return MadePilotSkillRoll_Advanced(mech, mods, 1);
}

int MechPilotSkillRoll_BTH(MECH *mech, int mods)
{
    mods += FindSPilotPiloting(mech) + MechPilotSkillBase(mech);
    if (In_Character(mech->mynum) &&
	Location(MechPilot(mech)) != mech->mynum)
	mods += 5;
    return mods;
}    

int MadePilotSkillRoll_Advanced(MECH * mech, int mods,
    int succeedWhenFallen)
{
    int roll, roll_needed;

    if (Fallen(mech) && succeedWhenFallen)
	return 1;
    if (Uncon(mech) || !Started(mech) || Blinded(mech))
	return 0;
    roll = Roll();
    roll_needed = MechPilotSkillRoll_BTH(mech, mods);

    SendDebug(tprintf("Attempting to make pilot skill roll. "
		      "SPilot: %d, mods: %d, MechPilot: %d, BTH: %d",
		      FindSPilotPiloting(mech), mods,
		      MechPilotSkillBase(mech), roll_needed));

    mech_notify(mech, MECHPILOT, "You make a piloting skill roll!");
    mech_notify(mech, MECHPILOT,
	tprintf("Modified Pilot Skill: BTH %d\tRoll: %d", roll_needed,
	    roll));
    if (roll >= roll_needed) {
	if (roll_needed > 2)
	    AccumulatePilXP(MechPilot(mech), mech, BOUNDED(1,
		    roll_needed - 7, MAX(2, 1 + mods)), 1);
	return 1;
    }
    return 0;
}

void FindXY(float x0, float y0, int bearing, float range, float *x1,
    float *y1)
{
    float xscale, correction;

    correction = (float) (bearing % 60) / 60.0;
    if (correction > 0.5)
	correction = 1.0 - correction;
    correction = -correction * 2.0;	/* 0 - 1 correction */
    xscale = (1.0 + XSCALE * correction) * SCALEMAP;
    *y1 =
	y0 - cos((float) bearing * 6.283185307 / 360.0) * range * SCALEMAP;
    *x1 = x0 + sin((float) bearing * 6.283185307 / 360.0) * range * xscale;
}

float FindRange(float x0, float y0, float z0, float x1, float y1, float z1)
{				/* range in hexes */
    float xscale;
    float XYrange;
    float Zrange;

    xscale = 1.0 / SCALEMAP;
    xscale = xscale * xscale;
    XYrange =
	sqrt(xscale * (x0 - x1) * (x0 - x1) + YSCALE2 * (y0 - y1) * (y0 -
	    y1));
    Zrange = (z0 - z1) / SCALEMAP;
    return sqrt(XYrange * XYrange + Zrange * Zrange);
}

float FindXYRange(float x0, float y0, float x1, float y1)
{				/* range in hexes */
    float xscale;
    float XYrange;

    xscale = 1.0 / SCALEMAP;
    xscale = xscale * xscale;
    XYrange =
	sqrt(xscale * (x0 - x1) * (x0 - x1) + YSCALE2 * (y0 - y1) * (y0 -
	    y1));
    return XYrange;
}

float FindHexRange(float x0, float y0, float x1, float y1)
{
    return FindXYRange(x0, y0, x1, y1);
}

/* CONVERSION ROUTINES courtesy Mike :) (Whoever that may be -focus) */

/* Picture blatantly ripped from the MUSH code by Dizzledorf and co. If only
   I had found it _before_ reverse-engineering the code :)
     - Focus, July 2002.
 */

/* Convert floating-point cartesian coordinates into hex coordinates.

   To do this, split the hex map into a repeatable region, which itself has
   4 distinct regions, each part of a different hex. (See picture.) The hex
   is normalized so that it is 1 unit high, and so is the repeatable region.
   It works out that the repeatable region is exactly sqrt(3) wide, and can
   be split up in six portions of each 1/6th sqrt(3), called 'alpha'. 
   Section I is 2 alpha wide at the top and bottom, and 3 alpha in the
   middle. Sections II and III are reversed, being 3 alpha at the top and
   bottom of the region, and 2 alpha in the middle. Section IV is 1 alpha in
   the middle and 0 at the top and bottom. The whole region encompasses
   exactly two x-columns and one y-row. All calculations are now done in
   'real' scale, to avoid rounding errors (isn't floating point arithmatic
   fun ?)

   Alpha also returns in the angle of the hexsides, that being 2*alpha
   (flipped or rotated when necessary) making the calculations look
   confusing. ANGLE_ALPHA is alpha (unscaled) for use in angle calculations.

         ________________________
        |        \              /|
        |         \    III     / |
        |          \          /  |
        |           \________/ IV|
        |    I      /        \   |
        |          /   II     \  |
        |         /            \ |
        |________/______________\|


   */

/* Doubles for added accuracy; most calculations are doubles internally
   anyway, so we suffer little to no performance hit. */

#define ALPHA 93.097730906827152	/* sqrt(3) * SCALEMAP */
#define ROOT3 558.58638544096289	/* ROOT3 / 6 */
#define ANGLE_ALPHA 0.28867513459481287	/* sqrt(3) / 6 */
#define FULL_Y (1 * SCALEMAP)
#define HALF_Y (0.5 * FULL_Y)

void RealCoordToMapCoord(short *hex_x, short *hex_y, float cart_x,
    float cart_y)
{
    float x, y;
    int x_count, y_count;

    if (cart_x < ALPHA) {
	/* Special case: we are in section IV of x-column 0 or off the map */
	*hex_x = cart_x < 0 ? -1 : 0;
	*hex_y = floor(cart_y / SCALEMAP);
	return;
    }

    /* 'shift' the map to the left so the repeatable box starts at 0 */
    cart_x -= ALPHA;

    /* Figure out the x-coordinate of the 'repeatable box' we're in. */
    x_count = cart_x / ROOT3;
    /* And the offset inside the box, from the left edge. */
    x = cart_x - x_count * ROOT3;

    /* The repbox holds two x-columns, we want the real X coordinate. */
    x_count *= 2;

    /* Do the same for the y-coordinate; this is easy */
    y_count = floor(cart_y / FULL_Y);
    y = cart_y - y_count * FULL_Y;

    if (x < 2 * ALPHA) {

	/* Clean in area I. Nothing to do */

    } else if (x >= 3 * ALPHA && x < 5 * ALPHA) {
	/* Clean in either area II or III. Up x one, and y if in the lower
	   half of the box. */
	x_count++;
	if (y >= HALF_Y)
	    /* Area II */
	    y_count++;

    } else if (x >= 2 * ALPHA && x < 3 * ALPHA) {
	/* Any of areas I, II and III. */
	if (y >= HALF_Y) {
	    /* Area I or II */
	    if (2 * ANGLE_ALPHA * (FULL_Y - y) <= x - 2 * ALPHA) {
		/* Area II, up both */
		x_count++;
		y_count++;
	    }
	} else {
	    /* Area I or III */
	    if (2 * ANGLE_ALPHA * y <= x - 2 * ALPHA)
		/* Area III, up only x */
		x_count++;
	}
    } else if (y >= HALF_Y) {
	/* Area II or IV. Up x at least one, maybe two, and y maybe one. */
	x_count++;
	if (2 * ANGLE_ALPHA * (y - HALF_Y) > (x - 5.0 * ALPHA))
	    /* Area II */
	    y_count++;
	else
	    /* Area IV */
	    x_count++;
    } else {
	/* Area III or IV, up x at least one, maybe two */
	x_count++;
	if (2 * ANGLE_ALPHA * y > ROOT3 - x)
	    /* Area IV */
	    x_count++;
    }

    *hex_x = x_count;
    *hex_y = y_count;
}

/* 
   If hex_x is odd, it falls smack in the middle of area III, right at the
   top edge of the repeatable box. Subtract one and multiply by one half
   sqrt(3) (or 3 alpha) to get the repeatable box coordinate, then add 5
   alpha for offset inside the box. The y coordinate is not modified.
   
   If hex_x is even, just multiply by 3 alpha to get the box coordinate, and
   add 2 alpha for offset inside the box. The center is in the middle of the
   box, so y is increased by half the box height.
   
 */

void MapCoordToRealCoord(int hex_x, int hex_y, float *cart_x,
    float *cart_y)
{

    if (hex_x % 2) {
	*cart_x = (hex_x - 1.0) * 3.0 * ALPHA + 5.0 * ALPHA;
	*cart_y = hex_y * FULL_Y;
    } else {
	*cart_x = hex_x * 3.0 * ALPHA + 2.0 * ALPHA;
	*cart_y = hex_y * FULL_Y + HALF_Y;
    }
}

/*
   Sketch a 'mech on a Navigate map. Done here since it fiddles directly
   with cartesian coords.

   Navigate is 9 rows high, and a hex is exactly 1*SCALEMAP high, so each
   row is FULL_Y/9 cartesian y-coords high.
   
   Navigate is 21 hexes wide, at its widest point. This corresponds to the
   hex width, which is 4 * ALPHA, so each column is 4*ALPHA/21 cartesian
   x-coords wide.

   The actual navigate map starts two rows from the top and four columns
   from the left.

 */

#define NAV_ROW_HEIGHT (FULL_Y / 9.0)
#define NAV_COLUMN_WIDTH (4 * ALPHA / 21.0)
#define NAV_Y_OFFSET 2
#define NAV_X_OFFSET 4
#define NAV_MAX_HEIGHT 2+9+2
#define NAV_MAX_WIDTH 4+21+2

void navigate_sketch_mechs(MECH * mech, MAP * map, int x, int y,
    char buff[NAVIGATE_LINES][MBUF_SIZE])
{
    float corner_fx, corner_fy, fx, fy;
    int i, row, column;
    MECH *other;

    MapCoordToRealCoord(x, y, &corner_fx, &corner_fy);
    corner_fx -= 2 * ALPHA;
    corner_fy -= HALF_Y;

    for (i = 0; i < map->first_free; i++) {
	if (map->mechsOnMap[i] < 0)
	    continue;
	if (!(other = FindObjectsData(map->mechsOnMap[i])))
	    continue;
	if (other == mech)
	    continue;
	if (MechX(other) != x || MechY(other) != y)
	    continue;
	if (!InLineOfSight(mech, other, x, y, 0.5))
	    continue;

	fx = MechFX(other) - corner_fx;
	column = fx / NAV_COLUMN_WIDTH + NAV_X_OFFSET;

	fy = MechFY(other) - corner_fy;
	row = fy / NAV_ROW_HEIGHT + NAV_Y_OFFSET;

        if (column < 0 || column > NAV_MAX_WIDTH ||
            row < 0 || row > NAV_MAX_HEIGHT)
            continue;

	buff[row][column] = MechSeemsFriend(mech, other) ? 'x' : 'X';
    }

    /* Draw 'mech last so we always see it. */

    fx = MechFX(mech) - corner_fx;
    column = fx / NAV_COLUMN_WIDTH + NAV_X_OFFSET;

    fy = MechFY(mech) - corner_fy;
    row = fy / NAV_ROW_HEIGHT + NAV_Y_OFFSET;

    if (column < 0 || column > NAV_MAX_WIDTH ||
        row < 0 || row > NAV_MAX_HEIGHT)
        return;

    buff[row][column] = '*';
}

int FindTargetXY(MECH * mech, float *x, float *y, float *z)
{
    MECH *tempMech;

    if (MechTarget(mech) != -1) {
	tempMech = getMech(MechTarget(mech));
	if (tempMech) {
	    *x = MechFX(tempMech);
	    *y = MechFY(tempMech);
	    *z = MechFZ(tempMech);
	    return 1;
	}
    } else if (MechTargX(mech) != -1 && MechTargY(mech) != -1) {
	MapCoordToRealCoord(MechTargX(mech), MechTargY(mech), x, y);
	*z = (float) ZSCALE *(MechTargZ(mech));

	return 1;
    }
    return 0;
}

int global_silence = 0;

#define UGLYTEST \
	  if (num_crits) \
	    { \
	      if (num_crits != (i = GetWeaponCrits (mech, lastweap))) \
		{ \
		  if (whine && !global_silence) \
		    SendError (tprintf ("Error in the numcriticals for weapon on #%d! (Should be: %d, is: %d)", mech->mynum, i, num_crits)); \
		  return -1; \
		} \
	      num_crits = 0; \
	    }


/* ASSERTION: Weapons must be located next to each other in criticals */

/* This is a hacked function. Sorry. */

int FindWeapons_Advanced(MECH * mech, int index, unsigned char *weaparray,
    unsigned char *weapdataarray, int *critical, int whine)
{
    int loop;
    int weapcount = 0;
    int temp, data, lastweap = -1;
    int num_crits = 0, i;

    for (loop = 0; loop < MAX_WEAPS_SECTION; loop++) {
	temp = GetPartType(mech, index, loop);
	data = GetPartData(mech, index, loop);
	if (IsWeapon(temp)) {
	    temp = Weapon2I(temp);
	    if (weapcount == 0) {
		lastweap = temp;
		weapdataarray[weapcount] = data;
		weaparray[weapcount] = temp;
		critical[weapcount] = loop;
		weapcount++;
		num_crits = 1;
		continue;
	    }
	    if (!num_crits || temp != lastweap ||
		(num_crits == GetWeaponCrits(mech, temp))) {
		UGLYTEST;
		weaparray[weapcount] = temp;
		weapdataarray[weapcount] = data;
		critical[weapcount] = loop;
		lastweap = temp;
		num_crits = 1;
		weapcount++;
	    } else
		num_crits++;
	} else
	    UGLYTEST;
    }
    UGLYTEST;
    return (weapcount);
}

int FindAmmunition(MECH * mech, unsigned char *weaparray,
    unsigned short *ammoarray, unsigned short *ammomaxarray,
    unsigned int *modearray)
{
    int loop;
    int weapcount = 0;
    int temp, data, mode;
    int index, i, j, duplicate;

    for (index = 0; index < NUM_SECTIONS; index++)
	for (loop = 0; loop < MAX_WEAPS_SECTION; loop++) {
	    temp = GetPartType(mech, index, loop);
	    if (IsAmmo(temp)) {
		data = GetPartData(mech, index, loop);
		mode = (GetPartAmmoMode(mech, index, loop) & AMMO_MODES);
		temp = Ammo2Weapon(temp);
		duplicate = 0;

		for (i = 0; i < weapcount; i++) {
		    if (temp == weaparray[i] && mode == modearray[i]) {
			if (!(PartIsNonfunctional(mech, index, loop)))
			    ammoarray[i] += data;
			ammomaxarray[i] += FullAmmo(mech, index, loop);
			duplicate = 1;
		    }
		}

		if (!duplicate) {
		    weaparray[weapcount] = temp;

		    if (!(PartIsNonfunctional(mech, index, loop)))
			ammoarray[weapcount] = data;
		    else
			ammoarray[weapcount] = 0;

		    ammomaxarray[weapcount] = FullAmmo(mech, index, loop);
		    modearray[weapcount] = mode;

		    weapcount++;
		}
	    }
	}
    /* Then, prune entries with 0 ammo left */
    for (i = 0; i < weapcount; i++)
	if (!ammoarray[i]) {
	    for (j = i + 1; j < weapcount; j++) {
		weaparray[j - 1] = weaparray[j];
		ammoarray[j - 1] = ammoarray[j];
		ammomaxarray[j - 1] = ammomaxarray[j];
		modearray[j - 1] = modearray[j];
	    }
	    i--;
	    weapcount--;
	}
    return (weapcount);
}

int FindLegHeatSinks(MECH * mech)
{
    int loop;
    int heatsinks = 0;

    for (loop = 0; loop < NUM_CRITICALS; loop++) {
	if (GetPartType(mech, LLEG, loop) == I2Special((HEAT_SINK)) &&
	    !PartIsNonfunctional(mech, LLEG, loop))
	    heatsinks++;
	if (GetPartType(mech, RLEG, loop) == I2Special((HEAT_SINK)) &&
	    !PartIsNonfunctional(mech, RLEG, loop))
	    heatsinks++;
	/*
	 * Added by Kipsta on 8/5/99
	 * Quads can get 'arm' HS in the water too
	 */

	if (MechIsQuad(mech)) {
	    if (GetPartType(mech, LARM, loop) == I2Special((HEAT_SINK)) &&
		!PartIsNonfunctional(mech, LARM, loop))
		heatsinks++;
	    if (GetPartType(mech, RARM, loop) == I2Special((HEAT_SINK)) &&
		!PartIsNonfunctional(mech, RARM, loop))
		heatsinks++;
	}
    }
    return (heatsinks);
}

/* Added for tic support. */

/* returns the weapon index- -1 for not found, -2 for destroyed, -3, -4 */

/* for reloading/recycling */
int FindWeaponNumberOnMech_Advanced(MECH * mech, int number, int *section,
    int *crit, int sight)
{
    int loop;
    unsigned char weaparray[MAX_WEAPS_SECTION];
    unsigned char weapdata[MAX_WEAPS_SECTION];
    int critical[MAX_WEAPS_SECTION];
    int running_sum = 0;
    int num_weaps;
    int index;

    for (loop = 0; loop < NUM_SECTIONS; loop++) {
	num_weaps = FindWeapons(mech, loop, weaparray, weapdata, critical);

	if (num_weaps <= 0)
	    continue;

	if (number < running_sum + num_weaps) {
	    /* we found it... */
	    index = number - running_sum;
	    if (PartIsNonfunctional(mech, loop, critical[index])) {
		*section = loop;
		*crit = critical[index];
		return TIC_NUM_DESTROYED;
	    } else if (weapdata[index] > 0 && !sight) {
		*section = loop;
		*crit = critical[index];
		return (MechWeapons[weaparray[index]].type ==
		    TBEAM) ? TIC_NUM_RECYCLING : TIC_NUM_RELOADING;
	    } else {
            
            if (MechSections(mech)[loop].recycle &&
                    (MechType(mech) == CLASS_MECH ||
                     MechType(mech) == CLASS_VEH_GROUND ||
                     MechType(mech) == CLASS_VTOL) && !sight) {

                *section = loop;
                *crit = critical[index];
                /* just did a physical attack */
                return TIC_NUM_PHYSICAL;
            }
            
		/* The recylce data for the weapon is clear- it is ready to fire! */
		*section = loop;
		*crit = critical[index];
		return weaparray[index];
	    }
	} else
	    running_sum += num_weaps;
    }
    return -1;
}

int FindWeaponNumberOnMech(MECH * mech, int number, int *section,
    int *crit)
{
    return FindWeaponNumberOnMech_Advanced(mech, number, section, crit, 0);
}

int FindWeaponFromIndex(MECH * mech, int weapindx, int *section, int *crit)
{
    int loop;
    unsigned char weaparray[MAX_WEAPS_SECTION];
    unsigned char weapdata[MAX_WEAPS_SECTION];
    int critical[MAX_WEAPS_SECTION];
    int num_weaps;
    int index;

    for (loop = 0; loop < NUM_SECTIONS; loop++) {
	num_weaps = FindWeapons(mech, loop, weaparray, weapdata, critical);
	for (index = 0; index < num_weaps; index++)
	    if (weaparray[index] == weapindx) {
		*section = loop;
		*crit = critical[index];
		if (!PartIsNonfunctional(mech, loop, index) &&
		    !WpnIsRecycling(mech, loop, index))
		    return 1;
		/* Return if not Recycling/Destroyed */
		/* Otherwise keep looking */
	    }
    }
    return 0;
}

int FindWeaponIndex(MECH * mech, int number)
{
    int loop;
    unsigned char weaparray[MAX_WEAPS_SECTION];
    unsigned char weapdata[MAX_WEAPS_SECTION];
    int critical[MAX_WEAPS_SECTION];
    int running_sum = 0;
    int num_weaps;
    int index;

    if (number < 0)
	return -1;		/* Anti-crash */
    for (loop = 0; loop < NUM_SECTIONS; loop++) {
	num_weaps = FindWeapons(mech, loop, weaparray, weapdata, critical);
	if (num_weaps <= 0)
	    continue;
	if (number < running_sum + num_weaps) {
	    /* we found it... */
	    index = number - running_sum;
	    return weaparray[index];
	}
	running_sum += num_weaps;
    }
    return -1;
}

int findAmmoInSection(MECH * mech, int section, int type, int nogof,
    int gof)
{
    int wIter;

    /* Can't use LBX ammo as normal, but can use Narc and Artemis as normal */
    for (wIter = 0; wIter < NUM_CRITICALS; wIter++) {
	if (GetPartType(mech, section, wIter) == type &&
	    !PartIsNonfunctional(mech, section, wIter) && (!nogof ||
		!(GetPartAmmoMode(mech, section, wIter) & nogof)) && (!gof
		|| (GetPartAmmoMode(mech, section, wIter) & gof))) {

	    if (!PartIsNonfunctional(mech, section, wIter) &&
		GetPartData(mech, section, wIter) > 0)
		return wIter;
	}
    }

    return -1;
}

int FindAmmoForWeapon_sub(MECH * mech, int weapSection, int weapCritical,
    int weapindx, int start, int *section, int *critical, int nogof,
    int gof)
{
    int loop;
    int foundSlot;
    int desired;
    int wCritType = 0;
    int wWeapSize = 0;
    int wFirstCrit = 0;
    int wDesiredLoc = -1;

    desired = I2Ammo(weapindx);


    /* The data on the desired location */
    if ((weapSection > -1) && (weapCritical > -1)) {
	wCritType = GetPartType(mech, weapSection, weapCritical);
	wWeapSize = GetWeaponCrits(mech, Weapon2I(wCritType));
	wFirstCrit =
	    FindFirstWeaponCrit(mech, weapSection, weapCritical, 0,
	    wCritType, wWeapSize);

	wDesiredLoc = GetPartDesiredAmmoLoc(mech, weapSection, wFirstCrit);

	if (wDesiredLoc >= 0) {
	    foundSlot =
		findAmmoInSection(mech, wDesiredLoc, desired, nogof, gof);

	    if (foundSlot >= 0) {
		*section = wDesiredLoc;
		*critical = foundSlot;

		return 1;
	    }
	}
    }

    /* Now lets search the current section */
    foundSlot = findAmmoInSection(mech, start, desired, nogof, gof);

    if (foundSlot >= 0) {
	*section = start;
	*critical = foundSlot;

	return 1;
    }

    /* If all else fails, start hunting for ammo */
    for (loop = 0; loop < NUM_SECTIONS; loop++) {
	if ((loop == start) || (loop == wDesiredLoc))
	    continue;

	foundSlot = findAmmoInSection(mech, loop, desired, nogof, gof);

	if (foundSlot >= 0) {
	    *section = loop;
	    *critical = foundSlot;

	    return 1;
	}
    }

    return 0;
}

int FindAmmoForWeapon(MECH * mech, int weapindx, int start, int *section,
    int *critical)
{
    return FindAmmoForWeapon_sub(mech, -1, -1, weapindx, start, section,
	critical, AMMO_MODES, 0);
}

int CountAmmoForWeapon(MECH * mech, int weapindx)
{
    int wSecIter;
    int wSlotIter;
    int wcAmmo = 0;
    int wAmmoIdx;

    wAmmoIdx = I2Ammo(weapindx);

    for (wSecIter = 0; wSecIter < NUM_SECTIONS; wSecIter++) {
	for (wSlotIter = 0; wSlotIter < NUM_CRITICALS; wSlotIter++) {
	    if ((GetPartType(mech, wSecIter, wSlotIter) == wAmmoIdx) &&
		!PartIsNonfunctional(mech, wSecIter, wSlotIter) &&
		(GetPartData(mech, wSecIter, wSlotIter) > 0))
		wcAmmo += GetPartData(mech, wSecIter, wSlotIter);
	}
    }

    return wcAmmo;
}

int FindArtemisForWeapon(MECH * mech, int section, int critical)
{
    int critloop;
    int desired;

    desired = I2Special(ARTEMIS_IV);
    for (critloop = 0; critloop < NUM_CRITICALS; critloop++)
	if (GetPartType(mech, section, critloop) == desired &&
	    !PartIsNonfunctional(mech, section, critloop)) {
	    if (GetPartData(mech, section, critloop) == critical)
		return 1;
	}
    return 0;
}

int FindDestructiveAmmo(MECH * mech, int *section, int *critical)
{
    int loop;
    int critloop;
    int maxdamage = 0;
    int damage;
    int weapindx;
    int i;
    int type, data;

    for (loop = 0; loop < NUM_SECTIONS; loop++)
	for (critloop = 0; critloop < NUM_CRITICALS; critloop++)
	    if (IsAmmo(GetPartType(mech, loop, critloop)) &&
		!PartIsDestroyed(mech, loop, critloop)) {
		data = GetPartData(mech, loop, critloop);
		type = GetPartType(mech, loop, critloop);
		weapindx = Ammo2WeaponI(type);
		damage = data * MechWeapons[weapindx].damage;
		if (MechWeapons[weapindx].special & GAUSS)
		    continue;
		if (IsMissile(weapindx) || IsArtillery(weapindx)) {
		    for (i = 0; MissileHitTable[i].key != -1; i++)
			if (MissileHitTable[i].key == weapindx)
			    damage *= MissileHitTable[i].num_missiles[10];
		}
		if (damage > maxdamage) {
		    *section = loop;
		    *critical = critloop;
		    maxdamage = damage;
		}
	    }
    return (maxdamage);
}

int FindRoundsForWeapon(MECH * mech, int weapindx)
{
    int loop;
    int critloop;
    int desired;
    int found = 0;

    desired = I2Ammo(weapindx);
    for (loop = 0; loop < NUM_SECTIONS; loop++)
	for (critloop = 0; critloop < NUM_CRITICALS; critloop++)
	    if (GetPartType(mech, loop, critloop) == desired &&
		!PartIsNonfunctional(mech, loop, critloop))
		found += GetPartData(mech, loop, critloop);
    return found;
}

const char *quad_locs[NUM_SECTIONS + 1] = {
    "Front Left Leg",
    "Front Right Leg",
    "Left Torso",
    "Right Torso",
    "Center Torso",
    "Rear Left Leg",
    "Rear Right Leg",
    "Head",
    NULL
};

const char *mech_locs[NUM_SECTIONS + 1] = {
    "Left Arm",
    "Right Arm",
    "Left Torso",
    "Right Torso",
    "Center Torso",
    "Left Leg",
    "Right Leg",
    "Head",
    NULL
};

const char *bsuit_locs[NUM_BSUIT_MEMBERS + 1] = {
    "Suit 1",
    "Suit 2",
    "Suit 3",
    "Suit 4",
    "Suit 5",
    "Suit 6",
    "Suit 7",
    "Suit 8",
    NULL
};

const char *veh_locs[NUM_VEH_SECTIONS + 1] = {
    "Left Side",
    "Right Side",
    "Front Side",
    "Aft Side",
    "Turret",
    "Rotor",
    NULL
};

const char *aero_locs[NUM_AERO_SECTIONS + 1] = {
    "Nose",
    "Left Wing",
    "Right Wing",
    "Fuselage",
    "Cockpit",
    "Engine",
    NULL
};

const char *ds_locs[NUM_DS_SECTIONS + 1] = {
    "Right Wing",
    "Left Wing",
    "Left Rear Wing",
    "Right Rear Wing",
    "Aft",
    "Nose",
    NULL
};


const char *ds_spher_locs[NUM_DS_SECTIONS + 1] = {
    "Front Right Side",
    "Front Left Side",
    "Rear Left Side",
    "Rear Right Side",
    "Aft",
    "Nose",
    NULL
};

const char **ProperSectionStringFromType(int type, int mtype)
{
    switch (type) {
        case CLASS_BSUIT:
            return bsuit_locs;
        case CLASS_MECH:
        case CLASS_MW:
            if (mtype == MOVE_QUAD)
                return quad_locs;
            return mech_locs;
        case CLASS_VEH_GROUND:
        case CLASS_VEH_NAVAL:
        case CLASS_VTOL:
            return veh_locs;
        case CLASS_AERO:
            return aero_locs;
        case CLASS_SPHEROID_DS:
            return ds_spher_locs;
        case CLASS_DS:
            return ds_locs;
    }
    return NULL;
}

void ArmorStringFromIndex(int index, char *buffer, char type, char mtype)
{
    const char **locs = ProperSectionStringFromType(type, mtype);
    int high = 0;

    switch (type) {
    case CLASS_MECH:
    case CLASS_MW:
	high = NUM_SECTIONS;
	break;
    case CLASS_VEH_GROUND:
    case CLASS_VEH_NAVAL:
	high = (NUM_VEH_SECTIONS - 1);
	break;
    case CLASS_VTOL:
	high = NUM_VEH_SECTIONS;
	break;
    case CLASS_AERO:
	high = NUM_AERO_SECTIONS;
	break;
    case CLASS_SPHEROID_DS:
	high = NUM_DS_SECTIONS;
    case CLASS_DS:
	high = NUM_DS_SECTIONS;
	break;
    case CLASS_BSUIT:
	high = NUM_BSUIT_MEMBERS;
	break;
    default:
	strcpy(buffer, "Invalid!!");
	return;
    }
    if (high > 0 && index < high && locs) {
	strcpy(buffer, locs[index]);
	return;
    }
    strcpy(buffer, "Invalid!!");
}

int IsInWeaponArc(MECH * mech, float x, float y, int section, int critical)
{
    int weaponarc, isrear;
    int wantarc = NOARC;

    if (MechType(mech) == CLASS_MECH && (section == LLEG || section == RLEG
	  || (MechIsQuad(mech) && (section == LARM || section == RARM)))) {
	int ts = MechStatus(mech) & (TORSO_LEFT | TORSO_RIGHT);
	MechStatus(mech) &= ~(ts);
	weaponarc = InWeaponArc(mech, x, y);
	MechStatus(mech) |= ts;
    } else
	weaponarc = InWeaponArc(mech, x, y);

    switch (MechType(mech)) {
    case CLASS_MECH:
    case CLASS_BSUIT:
    case CLASS_MW:
	if (GetPartFireMode(mech, section, critical) & REAR_MOUNT)
	    wantarc = REARARC;
	else if (section == LARM && (MechStatus(mech) & FLIPPED_ARMS))
	    wantarc = REARARC | LSIDEARC;
	else if (section == LARM)
	    wantarc = FORWARDARC | LSIDEARC;
	else if (section == RARM && (MechStatus(mech) & FLIPPED_ARMS))
	    wantarc = REARARC | RSIDEARC;
	else if (section == RARM)
	    wantarc = FORWARDARC | RSIDEARC;
	else
	    wantarc = FORWARDARC;
	break;
    case CLASS_VEH_GROUND:
    case CLASS_VEH_NAVAL:
    case CLASS_VTOL:
	switch (section) {
	case TURRET:
	    wantarc = TURRETARC;
	    break;
	case FSIDE:
	    wantarc = FORWARDARC;
	    break;
	case LSIDE:
	    wantarc = LSIDEARC;
	    break;
	case RSIDE:
	    wantarc = RSIDEARC;
	    break;
	case BSIDE:
	    wantarc = REARARC;
	    break;
	}
	break;
    case CLASS_DS:
	switch (section) {
	case DS_NOSE:
	    wantarc = FORWARDARC;
	    break;
	case DS_LWING:
	case DS_LRWING:
	    wantarc = LSIDEARC;
	    break;
	case DS_RWING:
	case DS_RRWING:
	    wantarc = RSIDEARC;
	    break;
	case DS_AFT:
	    wantarc = REARARC;
	    break;
	}
	break;
    case CLASS_SPHEROID_DS:
	switch (section) {
	case DS_NOSE:
	    wantarc = FORWARDARC;
	    break;
	case DS_LWING:
	    wantarc = FORWARDARC|LSIDEARC;
	    break;
	case DS_LRWING:
	    wantarc = REARARC|LSIDEARC;
	    break;
	case DS_RWING:
	    wantarc = FORWARDARC|RSIDEARC;
	    break;
	case DS_RRWING:
	    wantarc = REARARC|RSIDEARC;
	    break;
	case DS_AFT:
	    wantarc = REARARC;
	    break;
	}
	break;

    case CLASS_AERO:
	isrear = (GetPartFireMode(mech, section, critical) & REAR_MOUNT);
	switch (section) {
	case AERO_NOSE:
	    wantarc = FORWARDARC | LSIDEARC | RSIDEARC;
	    break;
	case AERO_FUSEL:
	    wantarc = FORWARDARC | REARARC | LSIDEARC | RSIDEARC;
	    break;
	case AERO_LWING:
	    wantarc = LSIDEARC | (isrear ? REARARC : FORWARDARC);
	    break;
	case AERO_RWING:
	    wantarc = RSIDEARC | (isrear ? REARARC : FORWARDARC);
	    break;
	case AERO_ENGINE:
	    wantarc = REARARC;
	    break;
	}
	break;
    }
    return wantarc ? (wantarc & weaponarc) : 0;
}

int GetWeaponCrits(MECH * mech, int weapindx)
{
    return (MechType(mech) ==
	CLASS_MECH) ? (MechWeapons[weapindx].criticals) : 1;
}

int listmatch(char **foo, char *mat)
{
    int i;

    for (i = 0; foo[i]; i++)
	if (!strcasecmp(foo[i], mat))
	    return i;
    return -1;
}

/* Takes care of :
   JumpSpeed
   Numsinks

   TODO: More support(?)
 */

void do_sub_magic(MECH * mech, int loud)
{
    int jjs = 0;
    int hses = 0;
    int wanths, wanths_f;
    int shs_size = HS_Size(mech);
    int hs_eff = HS_Efficiency(mech);
    int i, j;
    int inthses = MechEngineSize(mech) / 25;
    int dest_hses = 0;
    int maxjjs = (int) ((float) MechMaxSpeed(mech) * MP_PER_KPH * 2 / 3);

    if (MechSpecials(mech) & ICE_TECH)
	inthses = 0;
    for (i = 0; i < NUM_SECTIONS; i++)
	for (j = 0; j < CritsInLoc(mech, i); j++)
	    switch (Special2I(GetPartType(mech, i, j))) {
	    case HEAT_SINK:
		hses++;
		if (PartIsNonfunctional(mech, i, j))
		    dest_hses++;
		break;
	    case JUMP_JET:
		jjs++;
		break;
	    }
    hses +=
	MIN(MechRealNumsinks(mech) * shs_size / hs_eff,
	inthses * shs_size);
    if (jjs > maxjjs) {
	if (loud)
	    SendError(tprintf
		("Error in #%d (%s): %d JJs, yet %d maximum available (due to walk MPs)?",
		    mech->mynum, MechType_Ref(mech), jjs, maxjjs));

	jjs = maxjjs;
    }
    MechJumpSpeed(mech) = MP1 * jjs;
    wanths_f = (hses / shs_size) * hs_eff;
    wanths = wanths_f - (dest_hses * hs_eff / shs_size);
    if (loud)
	MechNumOsinks(mech) =
	    wanths - MIN(MechRealNumsinks(mech), inthses * hs_eff);
    if (wanths != MechRealNumsinks(mech) && loud) {
	SendError(tprintf
	    ("Error in #%d (%s): Set HS: %d. Existing HS: %d. Difference: %d. Please %s.",
		mech->mynum, MechType_Ref(mech), MechRealNumsinks(mech),
		wanths, MechRealNumsinks(mech) - wanths,
		wanths <
		MechRealNumsinks(mech) ? "add the extra HS critical(s)" :
		"fix the template"));
    } else
	MechRealNumsinks(mech) = wanths;
    MechNumOsinks(mech) = wanths_f;
}

#define CV(fun) fun(mech) = fun(&opp)

/* Values to take care of:
   - JumpSpeed
   - MaxSpeed
   - Numsinks
   - EngineHeat
   - PilotSkillBase
   - LRS/Tac/ScanRange
   - BTH

   Status:
   - Destroyed

   Critstatus:
   - kokonaan paitsi

   section(s) / basetohit
 */

void do_magic(MECH * mech)
{
    MECH opp;
    int i, j, t;
    int mask = 0;
    int tankCritMask = 0;

    if (MechType(mech) != CLASS_MECH)
	tankCritMask =
	    (TURRET_LOCKED | TURRET_JAMMED | TAIL_ROTOR_DESTROYED |
	    CREW_STUNNED);

    /* stop the burning */
    StopBurning(mech);
    StopPerformingAction(mech);

    memcpy(&opp, mech, sizeof(MECH));
    mech_loadnew(GOD, &opp, MechType_Ref(mech));
    MechEngineSizeV(mech) = MechEngineSizeC(&opp);	/* From intact template */
    opp.mynum = -1;
    /* Ok.. It's at perfect condition. Start inflicting some serious crits.. */
    for (i = 0; i < NUM_SECTIONS; i++)
	for (j = 0; j < CritsInLoc(mech, i); j++) {
	    SetPartType(&opp, i, j, GetPartType(mech, i, j));
	    SetPartBrand(&opp, i, j, GetPartBrand(mech, i, j));
	    SetPartData(&opp, i, j, 0);
	    SetPartFireMode(&opp, i, j, 0);
	    SetPartAmmoMode(&opp, i, j, 0);
	}
    if (MechType(mech) == CLASS_MECH)
	do_sub_magic(&opp, 0);
    MechNumOsinks(mech) = MechNumOsinks(&opp);
    for (i = 0; i < NUM_SECTIONS; i++) {
	if (MechType(mech) == CLASS_MECH) {
	    for (j = 0; j < CritsInLoc(mech, i); j++) {
		if (PartIsDestroyed(mech, i, j)) {
		    if (!PartIsDestroyed(&opp, i, j)) {
			if (!IsAmmo((t = GetPartType(mech, i, j)))) {
			    if (!IsWeapon(t))
				HandleMechCrit(&opp, NULL, 0, i, j, t,
				    GetPartData(mech, i, j));
			}
		    }
		} else {
		    t = GetPartType(mech, i, j);
		    if (IsAMS(Weapon2I(t))) {
			if (MechWeapons[Weapon2I(t)].special & CLAT)
			    MechSpecials(mech) |= CL_ANTI_MISSILE_TECH;
			else
			    MechSpecials(mech) |= IS_ANTI_MISSILE_TECH;
		    }
		    GetPartFireMode(mech, i, j) &=
		    	~(OS_USED|ROCKET_FIRED|IS_JETTISONED_MODE);
		}
	    }
	}

	MechSections(mech)[i].config &= ~STABILIZERS_DESTROYED;

	if (SectIsDestroyed(mech, i))
	    DestroySection(&opp, NULL, 0, i);
	if (MechStall(mech) > 0)
	    UnSetSectBreached(mech, i);	/* Just in case ; this leads to 'unbreachable' legs once you've 'done your time' once */
    }
    CV(MechJumpSpeed);
    CV(MechMaxSpeed);
    CV(MechRealNumsinks);
    CV(MechEngineHeat);
    CV(MechPilotSkillBase);
    CV(MechLRSRange);
    CV(MechTacRange);
    CV(MechScanRange);
    CV(MechBTH);
    MechCritStatus(mech) &= mask;
    MechCritStatus(mech) |= MechCritStatus(&opp) & (~mask);

    MechTankCritStatus(mech) &= tankCritMask;
    MechTankCritStatus(mech) |= MechTankCritStatus(&opp) & (~tankCritMask);

    for (i = 0; i < NUM_SECTIONS; i++) {
	MechSections(mech)[i].basetohit = MechSections(&opp)[i].basetohit;
	MechSections(mech)[i].specials = MechSections(&opp)[i].specials;
	MechSections(mech)[i].specials &=
	    ~(INARC_HOMING_ATTACHED | INARC_HAYWIRE_ATTACHED |
	    INARC_ECM_ATTACHED | INARC_NEMESIS_ATTACHED);
    }

    /* Case of undestroying */
    if (!Destroyed(&opp) && Destroyed(mech))
	MechStatus(mech) &= ~DESTROYED;
    else if (Destroyed(&opp) && !Destroyed(mech))
	MechStatus(mech) |= DESTROYED;
    if (!Destroyed(mech) && MechType(mech) != CLASS_MECH)
	EvalBit(MechStatus(mech), FALLEN, Fallen(&opp));
    update_specials(mech);
}

void mech_RepairPart(MECH * mech, int loc, int pos)
{
    int t = GetPartType(mech, loc, pos);

    UnDestroyPart(mech, loc, pos);
    if (IsWeapon(t) || IsAmmo(t)) {
	SetPartData(mech, loc, pos, 0);
	GetPartFireMode(mech, loc, pos) &=
	    ~(OS_USED | IS_JETTISONED_MODE | ROCKET_FIRED);
    } else if (IsSpecial(t)) {
	switch (Special2I(t)) {
	case TARGETING_COMPUTER:
	case HEAT_SINK:
	case LIFE_SUPPORT:
	case COCKPIT:
	case SENSORS:
	case JUMP_JET:
	case ENGINE:
	case GYRO:
	case SHOULDER_OR_HIP:
	case LOWER_ACTUATOR:
	case UPPER_ACTUATOR:
	case HAND_OR_FOOT_ACTUATOR:
	case C3_MASTER:
	case C3_SLAVE:
	case C3I:
	case ECM:
	case ANGELECM:
	case NULL_SIGNATURE_SYSTEM:
	case BEAGLE_PROBE:
	case ARTEMIS_IV:
	case TAG:
	case BLOODHOUND_PROBE:
	    /* Magic stuff here :P */
	    if (MechType(mech) == CLASS_MECH)
		do_magic(mech);
	    break;
	}
    }
}

int no_locations_destroyed(MECH * mech)
{
    int i;

    for (i = 0; i < NUM_SECTIONS; i++)
	if (GetSectOInt(mech, i) && SectIsDestroyed(mech, i))
	    return 0;
    return 1;
}

void mech_ReAttach(MECH * mech, int loc)
{
    if (!SectIsDestroyed(mech, loc))
	return;
    UnSetSectDestroyed(mech, loc);
    UnSetSectFlooded(mech, loc);
    SetSectInt(mech, loc, GetSectOInt(mech, loc));
    if (is_aero(mech))
	SetSectInt(mech, loc, 1);
    if (MechType(mech) != CLASS_MECH) {
	if (no_locations_destroyed(mech) && IsDS(mech))
	    MechStatus(mech) &= ~DESTROYED;
	return;
    }
}

void mech_ReplaceSuit(MECH * mech, int loc)
{
    if (!SectIsDestroyed(mech, loc))
	return;

    UnSetSectDestroyed(mech, loc);
    SetSectInt(mech, loc, GetSectOInt(mech, loc));
}

/*
 * Added for new flood code by Kipsta
 * 8/4/99
 */

void mech_ReSeal(MECH * mech, int loc)
{
    int i;

    if (SectIsDestroyed(mech, loc))
	return;
    if (!SectIsFlooded(mech, loc))
	return;

    UnSetSectFlooded(mech, loc);

    for (i = 0; i < CritsInLoc(mech, loc); i++) {
	if (PartIsDisabled(mech, loc, i)) {
	    if (!PartIsBroken(mech, loc, i) &&
		!PartIsDamaged(mech, loc, i))
		mech_RepairPart(mech, loc, i);
	    else
		UnDisablePart(mech, loc, i);
	}
    }
}

void mech_Detach(MECH * mech, int loc)
{
    if (SectIsDestroyed(mech, loc))
	return;
    DestroySection(mech, NULL, 0, loc);
}

/* Figures out how much ammo there is when we're 'fully loaded', and
   fills it */
void mech_FillPartAmmo(MECH * mech, int loc, int pos)
{
    int t, to;

    t = GetPartType(mech, loc, pos);

    if (!IsAmmo(t))
	return;
    if (!(to = MechWeapons[Ammo2Weapon(t)].ammoperton))
	return;
    SetPartData(mech, loc, pos, FullAmmo(mech, loc, pos));
}

int AcceptableDegree(int d)
{
    while (d < 0)
	d += 360;
    while (d >= 360)
	d -= 360;
    return d;
}

void MarkForLOSUpdate(MECH * mech)
{
    MAP *mech_map;

    if (!(mech_map = getMap(mech->mapindex)))
	return;
    mech_map->moves++;
    mech_map->mechflags[mech->mapnumber] = 1;
    /* We need to remove this baby from the calculated ranges list.. *sniff* */
    RCache_Remove(mech);
}

void multi_weap_sel(MECH * mech, dbref player, char *buffer, int bitbybit,
    int (*foo) (MECH *, dbref, int, int))
{
    /* Insight: buffer contains stuff in form:
       <num>
       <num>-<num>
       <num>,..
       <num>-<num>,..
     */
    /* Ugly recursive piece of code :> */
    char *c;
    int i1, i2, i3;
    int section, critical;

    skipws(buffer);
    if ((c = strstr(buffer, ","))) {
	*c = 0;
	c++;
    }
    if (sscanf(buffer, "%d-%d", &i1, &i2) == 2) {
	DOCHECK(i1 < 0 ||
	    i1 >= MAX_WEAPONS_PER_MECH,
	    tprintf("Invalid first number in range (%d)", i1));
	DOCHECK(i2 < 0 ||
	    i2 >= MAX_WEAPONS_PER_MECH,
	    tprintf("Invalid second number in range (%d)", i2));
	if (i1 > i2) {
	    i3 = i1;
	    i1 = i2;
	    i2 = i3;
	}
    } else {
	DOCHECK(Readnum(i1, buffer), tprintf("Invalid value: %s", buffer));
	DOCHECK(i1 < 0 ||
	    i1 >= MAX_WEAPONS_PER_MECH,
	    tprintf("Invalid weapon number: %d", i1));
	i2 = i1;
    }
    if (bitbybit / 2) {
	DOCHECK(i2 >= NUM_TICS, tprintf("There are only %d tics!", i2));
    } else {
	DOCHECK(!(FindWeaponNumberOnMech(mech, i2, &section,
		    &critical) != -1),
	    tprintf("Error: the mech doesn't HAVE %d weapons!", i2 + 1));
    }
    if (bitbybit % 2) {
	for (i3 = i1; i3 <= i2; i3++)
	    if (foo(mech, player, i3, i3))
		return;
    } else if (foo(mech, player, i1, i2))
	return;
    if (c)
	multi_weap_sel(mech, player, c, bitbybit, foo);
}

int Roll()
{
    int i = Number(1, 6) + Number(1, 6);

    rollstat.rolls[i - 2]++;
    rollstat.totrolls++;
    return i;
}

int MyHexDist(int x1, int y1, int x2, int y2, int tc)
{
    int xd = abs(x2 - x1);
    int yd = abs(y2 - y1);
    int hm;

    /* _the_ base case */
    if (x1 == x2)
	return yd;
    /*
       +
       +
       +
       +
     */
    if ((hm = (xd / 2)) <= yd)
	return (yd - hm) + tc + xd;

    /*
       +     +
       +   +
       + +
       +
     */
    if (!yd)
	return (xd + tc);
    /*
       +
       +
       +   +
       + +
       +
     */
    /* For now, same as above */
    return (xd + tc);
}

int CountDestroyedLegs(MECH * objMech)
{
    int wcDeadLegs = 0;

    if (MechType(objMech) != CLASS_MECH)
	return 0;

    if (MechIsQuad(objMech)) {
	if (IsLegDestroyed(objMech, LARM))
	    wcDeadLegs++;

	if (IsLegDestroyed(objMech, RARM))
	    wcDeadLegs++;
    }

    if (IsLegDestroyed(objMech, LLEG))
	wcDeadLegs++;

    if (IsLegDestroyed(objMech, RLEG))
	wcDeadLegs++;

    return wcDeadLegs;
}

int IsLegDestroyed(MECH * objMech, int wLoc)
{
    return (SectIsDestroyed(objMech, wLoc) || SectIsBreached(objMech, wLoc)
	|| SectIsFlooded(objMech, wLoc));
}

int IsMechLegLess(MECH * objMech)
{
    int wcMaxLegs = 0;

    if (MechType(objMech) != CLASS_MECH)
	return 0;

    if (MechIsQuad(objMech))
	wcMaxLegs = 4;
    else
	wcMaxLegs = 2;

    if (CountDestroyedLegs(objMech) >= wcMaxLegs)
	return 1;

    return 0;
}

int FindFirstWeaponCrit(MECH * objMech, int wLoc, int wSlot,
    int wStartSlot, int wCritType, int wMaxCrits)
{
    int wCritsInLoc = 0;
    int wCritIter, wFirstCrit;

    /*
     * First let's count the number of crits in this loc, incase
     * we have two of the same weapon
     */

    wFirstCrit = -1;

    for (wCritIter = wStartSlot; wCritIter < NUM_CRITICALS; wCritIter++) {
	if (GetPartType(objMech, wLoc, wCritIter) == wCritType) {
	    wCritsInLoc++;

	    if (wFirstCrit == -1)
		wFirstCrit = wCritIter;
	}
    }

    if ((wFirstCrit > -1) && (wSlot == -1))
	return wFirstCrit;

    /*
     * Now, if there are more crits than our max crit, then we have
     * two of the same weapon in this location. We need to figure
     * out which weapon this crit actually belongs to.
     */
    if (wCritsInLoc > wMaxCrits) {
	/*
	 * Well, we have thje first crit of the first instance, so
	 * let's see if our crit falls out of that range.. if so, then
	 * we need to figure out what range it actually falls into.
	 */
	if ((wFirstCrit + wMaxCrits) <= wSlot)
	    wFirstCrit =
		FindFirstWeaponCrit(objMech, wLoc, wSlot,
		(wFirstCrit + wMaxCrits), wCritType, wMaxCrits);
    }

    return wFirstCrit;
}

int checkAllSections(MECH * mech, int specialToFind)
{
    int i;

    for (i = 0; i < NUM_SECTIONS; i++) {
	if (checkSectionForSpecial(mech, specialToFind, i))
	    return 1;
    }

    return 0;
}

int checkSectionForSpecial(MECH * mech, int specialToFind, int wSec)
{
    if (SectIsDestroyed(mech, wSec))
	return 0;

    if (MechSections(mech)[wSec].specials & specialToFind)
	return 1;

    return 0;
}

int getRemainingInternalPercent(MECH * mech)
{
    int i;
    float wMax = 0;
    float wRemaining = 0;

    for (i = 0; i < NUM_SECTIONS; i++) {
	wMax += GetSectOInt(mech, i);

	wRemaining += GetSectInt(mech, i);
    }

    if (wMax == 0)
	return 0;

    return ((wRemaining / wMax) * 100);
}

int getRemainingArmorPercent(MECH * mech)
{
    int i;
    float wMax = 0;
    float wRemaining = 0;

    for (i = 0; i < NUM_SECTIONS; i++) {
	wMax += GetSectOArmor(mech, i);
	wMax += GetSectORArmor(mech, i);

	wRemaining += GetSectArmor(mech, i);
	wRemaining += GetSectRArmor(mech, i);
    }

    if (wMax == 0)
	return 0;

    return ((wRemaining / wMax) * 100);
}

int FindObj(MECH * mech, int loc, int type)
{
    int count = 0, i;

    for (i = 0; i < NUM_CRITICALS; i++)
	if (GetPartType(mech, loc, i) == type)
	    if (!PartIsNonfunctional(mech, loc, i))
		count++;
    return count;
}

int FindObjWithDest(MECH * mech, int loc, int type)
{
    int count = 0, i;

    for (i = 0; i < NUM_CRITICALS; i++)
	if (GetPartType(mech, loc, i) == type)
	    count++;
    return count;
}

/* Usage:
   mech      = Mech who's looking for people
   mech_map  = Map mech's on
   x,y       = Target hex
   needlos   = Bitvector
   1 = Require LOS
   2 = We actually want a mech that is friendly and has LOS to hex
 */
MECH *find_mech_in_hex(MECH * mech,
    MAP * mech_map, int x, int y, int needlos)
{
    int loop;
    MECH *target;

    for (loop = 0; loop < mech_map->first_free; loop++)
	if (mech_map->mechsOnMap[loop] != mech->mynum &&
	    mech_map->mechsOnMap[loop] != -1) {
	    target = (MECH *) FindObjectsData(mech_map->mechsOnMap[loop]);
	    if (!target)
		continue;
	    if (!(MechX(target) == x && MechY(target) == y) &&
		!(needlos & 2))
		continue;
	    if (needlos) {
		if (needlos & 1)
		    if (!InLineOfSight(mech, target, x, y,
			    FlMechRange(mech_map, mech, target)))
			continue;
		if (needlos & 2) {
		    if (MechTeam(mech) != MechTeam(target))
			continue;
		    if (!(MechSeesHex(target, mech_map, x, y)))
			continue;
		    if (mech == target)
			continue;
		}
	    }
	    return target;
	}
    return NULL;
}

int FindAndCheckAmmo(MECH * mech,
    int weapindx,
    int section,
    int critical,
    int *ammoLoc,
    int *ammoCrit, int *ammoLoc1, int *ammoCrit1, int *wGattlingShots)
{
    int mod, nmod = 0;
    int wMaxShots = 0;
    int wRoundsToCheck = 1;
    int wWeapMode = GetPartFireMode(mech, section, critical);
    int tResetMode = 0;
    dbref player = GunPilot(mech);

    /* Return if it's an energy or PC weapon */
    if (MechWeapons[weapindx].type == TBEAM ||
	MechWeapons[weapindx].type == THAND)
	return 1;

    /* Check for rocket launchers */
    if (MechWeapons[weapindx].special == ROCKET) {
	DOCHECK0(wWeapMode & ROCKET_FIRED,
	    "That weapon has already been used!");
	return 1;
    }

    /* Check for One-Shots */
    if (wWeapMode & OS_MODE) {
	DOCHECK0(GetPartFireMode(mech, section, critical) & OS_USED,
	    "That weapon has already been used!");
	return 1;
    }
    /* Check RACs - No special ammo type possible */
    if (MechWeapons[weapindx].special & RAC) {
	wMaxShots = CountAmmoForWeapon(mech, weapindx);

	if ((wWeapMode & RAC_TWOSHOT_MODE) && (wMaxShots < 2)) {
	    GetPartFireMode(mech, section, critical) &= ~RAC_TWOSHOT_MODE;

	    return 1;
	}

	if ((wWeapMode & RAC_FOURSHOT_MODE) && (wMaxShots < 4)) {
	    GetPartFireMode(mech, section, critical) &= ~RAC_FOURSHOT_MODE;

	    return 1;
	}

	if ((wWeapMode & RAC_SIXSHOT_MODE) && (wMaxShots < 6)) {
	    GetPartFireMode(mech, section, critical) &= ~RAC_SIXSHOT_MODE;

	    return 1;
	}
    }
    /* Check GMGs */
    if (wWeapMode & GATTLING_MODE) {
	wMaxShots = CountAmmoForWeapon(mech, weapindx);

	/*
	   * Gattling MGs suck up damage * 3 in ammo
	 */

	if ((wMaxShots / 3) < *wGattlingShots)
	    *wGattlingShots = MAX((wMaxShots / 3), 1);
    }
    /* If we're an ULTRA or RFAC, we need to check for multiple rounds */
    if ((wWeapMode & ULTRA_MODE) || (wWeapMode & RFAC_MODE))
	wRoundsToCheck = 2;

    mod = GetPartAmmoMode(mech, section, critical) & AMMO_MODES;

    if (!mod) {
	DOCHECK0(!FindAmmoForWeapon_sub(mech, section, critical, weapindx,
		section, ammoLoc, ammoCrit, AMMO_MODES, 0),
	    "You don't have any ammo for that weapon stored on this mech!");

	DOCHECK0(!GetPartData(mech, *ammoLoc, *ammoCrit),
	    "You are out of ammo for that weapon!");

	if (wRoundsToCheck > 1) {
	    GetPartData(mech, *ammoLoc, *ammoCrit)--;

	    if (FindAmmoForWeapon_sub(mech, section, critical, weapindx,
		    section, ammoLoc1, ammoCrit1, AMMO_MODES, 0)) {
		if (!GetPartData(mech, *ammoLoc1, *ammoCrit1))
		    tResetMode = 1;
	    } else
		tResetMode = 1;

	    if (tResetMode)
		GetPartFireMode(mech, section, critical) &= ~wWeapMode;

	    GetPartData(mech, *ammoLoc, *ammoCrit)++;
	}
    } else {
	if (IsArtillery(weapindx))
	    nmod = (~mod) & ARTILLERY_MODES;
	else
	    nmod = (~mod) & AMMO_MODES;
	mod = (mod & AMMO_MODES);

	DOCHECK0(!FindAmmoForWeapon_sub(mech, section, critical, weapindx,
		section, ammoLoc, ammoCrit, nmod, mod),
	    "You don't have any ammo for that weapon stored on this mech!");

	DOCHECK0(!GetPartData(mech, *ammoLoc, *ammoCrit),
	    "You are out of the special ammo type for that weapon!");

	if (wRoundsToCheck > 1) {
	    GetPartData(mech, *ammoLoc, *ammoCrit)--;

	    if (FindAmmoForWeapon_sub(mech, section, critical, weapindx,
		    section, ammoLoc1, ammoCrit1, nmod, mod)) {
		if (!GetPartData(mech, *ammoLoc1, *ammoCrit1))
		    tResetMode = 1;
	    } else
		tResetMode = 1;

	    if (tResetMode)
		GetPartFireMode(mech, section, critical) &= ~wWeapMode;

	    GetPartData(mech, *ammoLoc, *ammoCrit)++;
	}
    }

    return 1;
}

void ChannelEmitKill(MECH * mech, MECH * attacker)
{
    if (!attacker)
        attacker = mech;

    SendDebug(tprintf("#%d has been killed by #%d", mech->mynum,
                      attacker->mynum));
    if (IsDS(mech))
        SendDSInfo(tprintf("#%d has been killed by #%d", mech->mynum,
                           attacker->mynum));
   if (mech->mynum > 0 && attacker->mynum > 0)
        did_it(attacker->mynum, mech->mynum, 0, NULL, 0, NULL, A_AMECHDEST, (char **) NULL, 0);
}

#define NUM_NEIGHBORS	6
int dirs[6][2] = {
    {0, -1},
    {1, 0},
    {1, 1},
    {0, 1},
    {-1, 1},
    {-1, 0}
};

void visit_neighbor_hexes(MAP * map, int tx, int ty,
	void (*callback)(MAP *, int, int))
{
    int x1, y1;
    int i;

    for (i = 0; i < NUM_NEIGHBORS; i++) {
	x1 = tx + dirs[i][0];
	y1 = ty + dirs[i][1];
	if (tx % 2 && !(x1 % 2))
	    y1--;
	if (x1 < 0 || x1 >= map->map_width ||
	    y1 < 0 || y1 >= map->map_height )
	    continue;
	callback(map, x1, y1);
    }
}

int GetPartWeight(int part)
{
    if (IsWeapon(part))
	return 10.24 * MechWeapons[Weapon2I(part)].weight;
    else if (IsAmmo(part))
	return 1024;
    else if (IsBomb(part))
	return 102 * BombWeight(Bomb2I(part));
#ifndef BT_PART_WEIGHTS
    else if (IsSpecial(part) && part <= I2Special(CLAW))
	return 1024;
#else
    else if (IsSpecial(part))      /* && i <= I2Special(LAMEQUIP) */
	return internalsweight[Special2I(part)];
    else if (IsCargo(part))
	return cargoweight[Cargo2I(part)];
#endif                          /* BT_PART_WEIGHTS */
    else
/* hmm.. tricky, suppose we'll make things light */
	return 102;
}

#ifdef BT_ADVANCED_ECON
unsigned long long int GetPartCost(int p)
{
    extern unsigned long long int specialcost[SPECIALCOST_SIZE];
    extern unsigned long long int ammocost[AMMOCOST_SIZE];
    extern unsigned long long int weapcost[WEAPCOST_SIZE];
    extern unsigned long long int cargocost[CARGOCOST_SIZE];
    extern unsigned long long int bombcost[BOMBCOST_SIZE];

    if (IsWeapon(p))
	return weapcost[Weapon2I(p)];
    else if (IsAmmo(p))
	return ammocost[Ammo2I(p)];
    else if (IsSpecial(p))
	return specialcost[Special2I(p)];
    else if (IsBomb(p))
	return bombcost[Bomb2I(p)];
    else if (IsCargo(p))
	return cargocost[Cargo2I(p)];
    else
	return 0;
}

void SetPartCost(int p, unsigned long long int cost)
{
    extern unsigned long long int specialcost[SPECIALCOST_SIZE];
    extern unsigned long long int ammocost[AMMOCOST_SIZE];
    extern unsigned long long int weapcost[WEAPCOST_SIZE];
    extern unsigned long long int cargocost[CARGOCOST_SIZE];
    extern unsigned long long int bombcost[BOMBCOST_SIZE];

    if (IsWeapon(p))
	weapcost[Weapon2I(p)] = cost;
    else if (IsAmmo(p))
	ammocost[Ammo2I(p)] = cost;
    else if (IsSpecial(p))
	specialcost[Special2I(p)] = cost;
    else if (IsBomb(p))
	bombcost[Bomb2I(p)] = cost;
    else if (IsCargo(p))
	cargocost[Cargo2I(p)] = cost;
}

#define COST_DEBUG      0
#if COST_DEBUG
#define ADDPRICE(desc, add) \
    { SendDebug(tprintf("AddPrice - %s %d", desc, add)); \
    total += add; }
#else
#define ADDPRICE(desc, add) \
    total += add;
#endif

#define DoArmMath(loc) \
for (i = 0; i < NUM_CRITICALS; i++) { \
    part = GetPartType(mech, loc, i); \
    if (!IsActuator(part)) \
        continue; \
    else if (Special2I(part) == SHOULDER_OR_HIP || Special2I(part) == UPPER_ACTUATOR) \
        ADDPRICE("Shoulder/Upper Actuator", (MechTons(mech) * 100)) \
    else if (Special2I(part) == LOWER_ACTUATOR) \
        ADDPRICE("LowerArm Actuator", (MechTons(mech) * 50)) \
    else if (Special2I(part) == HAND_OR_FOOT_ACTUATOR) \
        ADDPRICE("Hand Actuator", (MechTons(mech) * 80)) \
    }

#define DoLegMath(loc) \
for (i = 0; i < NUM_CRITICALS; i++) { \
    part = GetPartType(mech, loc, i); \
    if (!IsActuator(part)) \
        continue; \
    else if (Special2I(part) == SHOULDER_OR_HIP || Special2I(part) == UPPER_ACTUATOR) \
        ADDPRICE("Hip/Upper Actuator", (MechTons(mech) * 150)) \
    else if (Special2I(part) == LOWER_ACTUATOR) \
        ADDPRICE("LowerLeg Actuator", (MechTons(mech) * 80)) \
    else if (Special2I(part) == HAND_OR_FOOT_ACTUATOR) \
        ADDPRICE("Foot Actuator", (MechTons(mech) * 120)) \
    }

/* Some would say it's better for scode. I prolly would do. But since it's the FASA cals, let's put it in binary. Plus I'm lazy today */
unsigned long long int CalcFasaCost(MECH * mech)
{
int ii, i, part;
unsigned long long int total = 0;
float mod = 1.0;

if (!mech)
    return -1;

if (!(MechType(mech) == CLASS_MECH || MechType(mech) == CLASS_VEH_GROUND || MechType(mech) == CLASS_VEH_NAVAL || MechType(mech) == CLASS_VTOL ) ||
        is_aero(mech) || IsDS(mech))
    return 0;

if (MechType(mech) == CLASS_MECH) {
/* Cockpit */
#if 0
/* NULLTODO : Port any of these techs ASAP */
    if (MechSpecials2(mech) & SMALLCOCKPIT_TECH)
        ADDPRICE("SmallCockpit", 175000)
    else if (MechSpecials2(mech) & TORSOCOCKPIT_TECH)
        ADDPRICE("TorsoCockpit", 750000)
    else
#endif
        ADDPRICE("Cockpit", 200000)
/* Life Support */
    ADDPRICE("LifeSupport", 50000)
/* Sensors */
    ADDPRICE("Sensors", (MechTons(mech) * 2000))
/* Myomer stuffage */
    if (MechSpecials(mech) & TRIPLE_MYOMER_TECH)
        ADDPRICE("TripleMyomer", (MechTons(mech) * 16000))
    else
        ADDPRICE("Myomer", (MechTons(mech) * 2000))
/* Internal Structure */
    if (MechSpecials(mech) & ES_TECH || MechSpecials(mech) & COMPI_TECH)
        ADDPRICE("ES/CO  Internal", (MechTons(mech) * 1600))
    else if (MechSpecials(mech) & REINFI_TECH)
        ADDPRICE("RE Internal", (MechTons(mech) * 6400))
    else
        ADDPRICE("Internal", (MechTons(mech) * 400))
/* Actuators */
    DoArmMath(RARM)
    DoArmMath(LARM)
    DoLegMath(LLEG)
    DoLegMath(RLEG)
/* Gyro */
    i = MechEngineSize(mech);
    if (i % 100)
        i += (100 - (MechEngineSize(mech) % 100));
    i /= 100;

/* NULLTODO : Port any of these techs ASAP */
    if (MechSpecials2(mech) & XLGYRO_TECH)
        ADDPRICE("XLGyro", i * 750000)
    else if (MechSpecials2(mech) & CGYRO_TECH)
        ADDPRICE("Compact Gyro", i * 400000)
    else if (MechSpecials2(mech) & HDGYRO_TECH)
        ADDPRICE("HD Gyro", i * 500000)
    else
        ADDPRICE("Gyro", i * 300000)
} else {
    int pamp = 0, turret = 0;
    for (i = 0; i < NUM_SECTIONS; i++)
        for (ii = 0; ii < NUM_CRITICALS; ii++) {
            if (!(part = GetPartType(mech, i, ii)))
                continue;
            if (!IsWeapon(part))
                continue;
            if (i == TURRET)
                turret += crit_weight(mech, part);
            if (IsEnergy(part))
                pamp += crit_weight(mech, part);
            }
/* Internals */
    ADDPRICE("TankInternals", MechTons(mech) * 10000)
/* Control Components */
    ADDPRICE("Control Components", (float) 10000 * (float) ((float) 0.05 * (float) MechTons(mech)))
/* Power Amp */
    if (MechSpecials(mech) & ICE_TECH)
        ADDPRICE("Power Amplifiers",  20000 * (float) (((float) pamp / (float) 10) / (float) 1024))
/* Turret */
    ADDPRICE("Turret", (float) 5000 * (float) (((float) turret / (float) 10) / (float) 1024))
/* Lift/Dive Equip */
    if (MechMove(mech) == MOVE_HOVER || MechMove(mech) == MOVE_FOIL || MechMove(mech) == MOVE_SUB)
        ADDPRICE("Lift/Dive Equipment", (float) 20000 * (float) ((float) 0.1 * (float) MechTons(mech)))
    if (MechMove(mech) == MOVE_VTOL)
        ADDPRICE("VTOL Equipment", (float) 40000 * (float) ((float) 0.1 * (float) MechTons(mech)))
}
/* Engine Math */
i = (MechSpecials(mech) & CE_TECH ? 10000 : MechSpecials(mech) & LE_TECH ? 15000 : MechSpecials(mech) & XL_TECH ? 20000 :
        MechSpecials(mech) & XXL_TECH ? 100000 : MechSpecials(mech) & ICE_TECH ? 1250 : 5000);
ADDPRICE("Engine", ((i * MechEngineSize(mech) * MechTons(mech)) / 75))

/* Jump Jets */
i = MechJumpSpeed(mech) * MP_PER_KPH;
if (i > 0)
    ADDPRICE("JumpJets", MechTons(mech) * (i * i) * 200)

/* Heat Sinks */
i = MechRealNumsinks(mech);
ii = (MechSpecials(mech) & DOUBLE_HEAT_TECH || MechSpecials(mech) & CLAN_TECH ? 6000 : MechSpecials2(mech) & COMPACT_HS_TECH ? 3000 : 2000);
if (!(MechSpecials(mech) & ICE_TECH || MechSpecials(mech) & DOUBLE_HEAT_TECH || MechSpecials(mech) & CLAN_TECH))
        i = BOUNDED(0, i - 10, 500);
ADDPRICE("Heat Sinks",  i * ii)

ii = 0;
for (i = 0; i < NUM_SECTIONS; ++i)
    ii += GetSectOArmor(mech, i);
i = (MechSpecials(mech) & FF_TECH ? 20000 : MechSpecials(mech) & HARDA_TECH ? 15000 : MechSpecials2(mech) & LT_FF_ARMOR_TECH ? 15000 :
        MechSpecials2(mech) & HVY_FF_ARMOR_TECH ? 25000 : 10000);
#if COST_DEBUG
SendDebug(tprintf("Armor Total %d - Armor Cost %d", ii, i));
#endif
ADDPRICE("Armor", (i / 16) * ii)

/* Parts */
for (i = 0; i < NUM_SECTIONS; i++)
    for (ii = 0; ii < NUM_CRITICALS; ii++) {
        part = GetPartType(mech, i, ii);
        if (IsActuator(part) || part == EMPTY)
            continue;
        if (IsSpecial(part))
            switch (Special2I(part)) {
                case LIFE_SUPPORT:
                case SENSORS:
                case COCKPIT:
                case ENGINE:
                case GYRO:
                case HEAT_SINK:
                case JUMP_JET:
                case FERRO_FIBROUS:
                case ENDO_STEEL:
                case TRIPLE_STRENGTH_MYOMER:
#if 0
/* NULLTODO : Port any of these techs ASAP */
                case HARDPOINT:
                    continue;
#endif
		default:
                    break;
                }
        if (IsAmmo(part)) {
            part = FindAmmoType(mech, i, ii);
            ADDPRICE(part_name(part, 0), GetPartCost(part) * GetPartData(mech, i, ii));
        } else {
            ADDPRICE(part_name(part, 0), GetPartCost(part))
        }
        }

if (MechType(mech) != CLASS_MECH) {
    switch (MechMove(mech)) {
        case MOVE_TRACK:
            mod = (float) 1 + (float) ((float) MechTons(mech) / (float) 100);
            break;
        case MOVE_WHEEL:
            mod = (float) 1 + (float) ((float) MechTons(mech) / (float) 200);
            break;
        case MOVE_HOVER:
            mod = (float) 1 + (float) ((float) MechTons(mech) / (float) 50);
            break;
        case MOVE_VTOL:
            mod = (float) 1 + (float) ((float) MechTons(mech) / (float) 30);
            break;
        case MOVE_HULL:
            mod = (float) 1 + (float) ((float) MechTons(mech) / (float) 200);
            break;
        case MOVE_FOIL:
            mod = (float) 1 + (float) ((float) MechTons(mech) / (float) 75);
            break;
        case MOVE_SUB:
            mod = (float) 1 + (float) ((float) MechTons(mech) / (float) 50);
            break;
        }
    } else {
        mod = (float) 1 + (float) ((float) MechTons(mech) / (float) 100);
    }
#if COST_DEBUG
SendDebug(tprintf("Price Total - %lld Mod - %f", total, mod));
#endif

return ((float) total * (float) mod);
}
#endif

#ifdef BT_CALCULATE_BV

int FindAverageGunnery(MECH * mech)
{
#if 1
/* NULLTODO : Get the multiple skills for gunnery and such ported or working here so this is usefull again. */
return FindPilotGunnery(mech, 0);
#else
    int runtot = 0;
    int i;

    if (!mech)
	return 12;

    for (i = 0; i < 5; i++) {
	runtot += FindPilotGunnery(mech, (i == 0 ? 0 : i == 1 ? 4 : i == 2 ? 5 : i == 3 ? 6 : i == 4 ? 103 : 0));
    }
    return (runtot / 5);
#endif
}

#undef DEBUG_BV
#define HIGH_SKILL      8
#define LOW_SKILL       0
float skillmul[HIGH_SKILL][HIGH_SKILL] = {
	{ 2.05 , 2.00 , 1.95 , 1.90 , 1.85 , 1.80 , 1.75 , 1.70 },
	{ 1.85 , 1.80 , 1.75 , 1.70 , 1.65 , 1.60 , 1.55 , 1.50 },
	{ 1.65 , 1.60 , 1.55 , 1.50 , 1.45 , 1.40 , 1.35 , 1.30 },
	{ 1.45 , 1.40 , 1.35 , 1.30 , 1.25 , 1.20 , 1.15 , 1.10 },
	{ 1.25 , 1.20 , 1.15 , 1.10 , 1.05 , 1.00 , 0.95 , 0.90 },
	{ 1.15 , 1.10 , 1.05 , 1.00 , 0.95 , 0.90 , 0.85 , 0.80 },
	{ 1.05 , 1.00 , 0.95 , 0.90 , 0.85 , 0.80 , 0.75 , 0.70 },
	{ 0.95 , 0.90 , 0.85 , 0.80 , 0.75 , 0.70 , 0.65 , 0.60 }
};

#define LAZY_SKILLMUL(n)  (n < LOW_SKILL ? LOW_SKILL : n >= HIGH_SKILL - 1 ? HIGH_SKILL - 1 : n)

int CalculateBV(MECH *mech, int gunstat, int pilstat)
{
int defbv = 0, offbv = 0, i, ii, temp, temp2, deduct = 0, offweapbv = 0, defweapbv = 0, armor = 0, intern = 0, weapindx, mostheat = 0, tempheat = 0, mechspec, mechspec2, type, move, pilskl= pilstat, gunskl = gunstat;
int debug1 = 0, debug2 = 0, debug3 = 0, debug4 = 0;
float maxspeed, mul = 1.00;

if (!mech)
    return 0;

if (gunstat == 100 || pilstat == 100) {
    if (muxevent_tick - MechBVLast(mech) < 30)
        return MechBV(mech);
    else
        MechBVLast(mech) = muxevent_tick;
    }

type = MechType(mech);
move = MechMove(mech);
mechspec = MechSpecials(mech);
mechspec2 = MechSpecials2(mech);
if (gunstat == 100)
    pilskl = FindPilotPiloting(mech);
if (pilstat == 100)
    gunskl = FindAverageGunnery(mech);


for (i = 0; i < NUM_SECTIONS; i++) {
        armor += (debug1 = GetSectArmor(mech, i) * (mechspec & HARDA_TECH ? 200 : 100));
        if (type == CLASS_MECH &&  (i == CTORSO || i == LTORSO || i == RTORSO)) {
            armor += (debug2 = GetSectRArmor(mech, i) * (mechspec & HARDA_TECH ? 200 : 100));
#if 0
/* NULLTODO : Port any of these techs ASAP */
            if (mechspec2 & TORSOCOCKPIT_TECH && i == CTORSO)
                armor += (debug4 = (((GetSectArmor(mech, i) + GetSectRArmor(mech, i)) * 2) * (mechspec & HARDA_TECH ? 200 : 100)));
#endif
        }
        if (!is_aero(mech))
            intern += (debug3 = GetSectInt(mech, i) * (mechspec & COMPI_TECH ? 50 : mechspec & REINFI_TECH ? 200 : 100));
        else
            intern = (debug3 = AeroSI(mech));
#ifdef DEBUG_BV
        SendDebug(tprintf("Armoradd : %d ArmorRadd : %d Internadd : %d", debug1 / 100, debug2 / 100, debug3 / 100));
        if (mechspec2 & TORSOCOCKPIT_TECH && i == CTORSO)
            SendDebug(tprintf("TorsoCockpit Armoradd : %d", debug4));
#endif

        debug1 = debug2 = debug3 = debug4 = 0;
        for (ii = 0; ii < CritsInLoc(mech, i); ii++)
            {
            if (IsWeapon(temp = GetPartType(mech, i, ii)))
                {
                weapindx = (Weapon2I(temp));
                if (PartIsNonfunctional(mech, i, ii)) {
                    if (type == CLASS_MECH)
                        ii += (MechWeapons[weapindx].criticals - 1);
                    continue;
                }
            if (MechWeapons[weapindx].special & AMS) {
                defweapbv += (debug1 = (MechWeapons[weapindx].battlevalue * 100) * (float) (3000 / (MechWeapons[weapindx].vrt * 100)));

#ifdef DEBUG_BV
                SendDebug(tprintf("DefWeapBVadd (%s) : %d - Total : %d", MechWeapons[weapindx].name, debug1 / 100, defweapbv / 100));
#endif

            } else {
                offweapbv += (debug1 = (MechWeapons[weapindx].battlevalue * (GetPartFireMode(mech, i, ii) & REAR_MOUNT ? 50 : 100)) * (float) ((float) 3000 / (float) (MechWeapons[weapindx].vrt * 100)));
                if (MechWeapons[weapindx].type == TMISSILE)
                    if (FindArtemisForWeapon(mech, i, ii))
                        offweapbv += (MechWeapons[weapindx].battlevalue * 20);
#ifdef DEBUG_BV
                SendDebug(tprintf("OffWeapBVadd (%s) : %d - Total : %d", MechWeapons[weapindx].name, debug1 / 100, offweapbv / 100));
#endif

            }
            if (type == CLASS_MECH) {
              if (!(GetPartFireMode(mech, i, ii) & REAR_MOUNT)) {
                tempheat = ((MechWeapons[weapindx].heat * 100)  * (float) ((float) 3000 / (float) (MechWeapons[weapindx].vrt * 100)));
                if (MechWeapons[weapindx].special & ULTRA)
                    tempheat = (tempheat * 2);
                if (MechWeapons[weapindx].special & STREAK)
                    tempheat = (tempheat / 2);
                mostheat += tempheat;
#ifdef DEBUG_BV
                SendDebug(tprintf("Tempheatadded (%s) : %d - Total : %d", MechWeapons[weapindx].name, tempheat / 100, mostheat / 100));
#endif
                tempheat = 0;
                }
              }
            if (type == CLASS_MECH)
                ii += (MechWeapons[weapindx].criticals - 1);
            } else if (IsAmmo(temp)) {
                if (PartIsNonfunctional(mech, i, ii) || !GetPartData(mech, i, ii))
                    continue;
#if 0
/* NULLTODO : Port any of these techs ASAP */
             mul = ((temp2 = GetPartAmmoMode(mech, i, ii)) & AC_AP_MODE ? 4 :
                 temp2 & AC_PRECISION_MODE ? 6 :
                 temp2 & (TRACER_MODE|STINGER_MODE|SWARM_MODE|SWARM1_MODE|SGUIDED_MODE) ? 1.5 : 1);
#else
             mul = ((temp2 = GetPartAmmoMode(mech, i, ii)) & AC_AP_MODE ? 4 :
                 temp2 & AC_PRECISION_MODE ? 6 :
                 temp2 & (SWARM_MODE|SWARM1_MODE) ? 1.5 : 1);
#endif
	 	mul = (mul * ((float) ((float) GetPartData(mech, i, ii) /
         (float) MechWeapons[weapindx = Ammo2WeaponI(temp)].ammoperton)));

#ifdef DEBUG_BV
                SendDebug(tprintf("AmmoBVmul (%s) : %.2f", MechWeapons[weapindx].name, mul));
#endif

                if (MechWeapons[weapindx].special & AMS) {
                    defweapbv += (debug1 = (((MechWeapons[weapindx].battlevalue / 10) * 100) * mul) * (float) ((float) 3000 / (float) (MechWeapons[weapindx].vrt * 100)));

#ifdef DEBUG_BV
                    SendDebug(tprintf("AmmoDefWeapBVadd (%s) : %d - Total : %d", MechWeapons[weapindx].name, debug1 / 100, defweapbv / 100));
#endif

                } else {

#ifdef DEBUG_BV
                    SendDebug(tprintf("Abattlebalue (%s) : %d", MechWeapons[weapindx].name, (MechWeapons[weapindx].battlevalue / 10)));
#endif

                    offweapbv += (debug1 = (((MechWeapons[weapindx].battlevalue / 10) * 100) * mul) * (float) ((float) 3000 / (float) (MechWeapons[weapindx].vrt* 100)));

#ifdef DEBUG_BV
                    SendDebug(tprintf("AmmoOffWeapBVadd (%s)  : %d - Total : %d", MechWeapons[weapindx].name, debug1 / 100, offweapbv / 100));
#endif

                    }
                }
            if ((IsAmmo(temp) || (IsWeapon(temp) && MechWeapons[(Weapon2I(temp))].special & GAUSS)) && type == CLASS_MECH)
                {
                if (mechspec & CLAN_TECH)
                    if (i == CTORSO || i == HEAD || i == RLEG || i == LLEG) {

#ifdef DEBUG_BV
                        SendDebug("20 deduct added for ammo");
#endif
                        deduct += 2000;
                        continue;
                        }
                if (mechspec & (XL_TECH|XXL_TECH|ICE_TECH|LE_TECH)) {

#ifdef DEBUG_BV
                    SendDebug("20/2000 deduct added for ammo");
#endif

                    deduct += 2000;
                    continue;
                    }
                if ((i == CTORSO || i == RLEG || i == LLEG || i == HEAD) && !(MechSections(mech)[i].config & CASE_TECH)) {

#ifdef DEBUG_BV
                    SendDebug("20 deduct added for ammo");
#endif

                    deduct += 2000;
                    continue;
                    }
                if ((i == RARM || i == LARM) && (!(MechSections(mech)[i].config & CASE_TECH) && !(MechSections(mech)[(i == RARM ? RTORSO : LTORSO)].config & CASE_TECH))) {

#ifdef DEBUG_BV
                    SendDebug("20 deduct added for ammo");
#endif

                    deduct += 2000;
                    continue;
                    }
                }

            }
        }
if (type == CLASS_MECH) {
    mostheat += (MechJumpSpeed(mech) > 0 ? MAX((MechJumpSpeed(mech) / MP1) * 100, 300) : 200);
    if (mechspec2 & (NULLSIGSYS_TECH|STEALTH_ARMOR_TECH))
        mostheat += 1000;
    if ((temp = (mostheat - (MechActiveNumsinks(mech) * 100))) > 0) {
        deduct += temp * 5;
#ifdef DEBUG_BV
        SendDebug(tprintf("Deduct add for heat : %d", (temp * 5) / 100));
#endif
        }
    }
#ifdef DEBUG_BV
SendDebug(tprintf("DeductTotal : %d", deduct / 100));
#endif

if (mechspec & ECM_TECH)
    defweapbv += 6100;

if (mechspec & BEAGLE_PROBE_TECH) {
    if (mechspec & CLAN_TECH)
        offweapbv += 1200;
    else
        offweapbv += 1000;
    }

#if 0
/* NULLTODO : Port any of these techs ASAP */
if (mechspec2 & HDGYRO_TECH)
    defweapbv += 3000;
#endif

if (mechspec & (XL_TECH|XXL_TECH|LE_TECH)) {
    if (mechspec & (CLAN_TECH|LE_TECH))
        mul = 1.125;
    else
        mul = 0.75;
} else if (mechspec & ICE_TECH || MechType(mech) == CLASS_VEH_GROUND || MechType(mech) == CLASS_VEH_NAVAL) {
    mul = 0.5;
} else {
mul = 1.5;
}

#ifdef DEBUG_BV
SendDebug(tprintf("InternMul : %.2f", mul));
#endif

armor = (armor * (MechType(mech) == CLASS_MECH ? 2 : 1));
intern = intern * mul;
mul = 1.00;

#ifdef DEBUG_BV
SendDebug(tprintf("ArmorEnd : %d IntEnd : %d", armor / 100, intern / 100));
#endif

maxspeed = MMaxSpeed(mech);
if (mechspec & MASC_TECH || mechspec2 & SUPERCHARGER_TECH) {
    if (mechspec & MASC_TECH && mechspec2 & SUPERCHARGER_TECH)
        maxspeed = maxspeed * 2.5;
    else
        maxspeed = maxspeed * 1.5;
    }
if (mechspec & TRIPLE_MYOMER_TECH)
    maxspeed = ((WalkingSpeed(maxspeed) + MP1) * 1.5);

if (maxspeed <= MP2) {
        mul = 1.0;
    } else if (maxspeed <= MP4) {
        mul = 1.1;
    } else if (maxspeed <= MP6) {
        mul = 1.2;
    } else if (maxspeed <= MP9) {
        mul = 1.3;
    } else if (maxspeed <= MP1 * 13) {
        mul = 1.4;
    } else if (maxspeed <= MP1 * 18) {
        mul = 1.5;
    } else if (maxspeed <= MP1 * 24) {
        mul = 1.6;
    } else {
        mul = 1.7;
    }

if (IsDS(mech))
    mul = 1.0;
else if (is_aero(mech))
    mul = 1.1;

if (mechspec2 & (NULLSIGSYS_TECH|STEALTH_ARMOR_TECH))
    mul += 1.5;
if (MechInfantrySpecials(mech) & DC_KAGE_STEALTH_TECH)
    mul += .75;
if (MechInfantrySpecials(mech) & FWL_ACHILEUS_STEALTH_TECH)
    mul += 1.5;
if (MechInfantrySpecials(mech) & CS_PURIFIER_STEALTH_TECH)
    mul += 2.0;
if (MechInfantrySpecials(mech) & FC_INFILTRATOR_STEALTH_TECH)
    mul += .75;
if (MechInfantrySpecials(mech) & FC_INFILTRATOR_STEALTH_TECH)
    mul += 2.0;
    

#ifdef DEBUG_BV
SendDebug(tprintf("DefBVMul : %.2f", mul));
#endif

defbv = (armor + intern + (MechTons(mech) * 100) + defweapbv);

#ifdef DEBUG_BV
SendDebug(tprintf("DefBV Tonnage added : %d", MechTons(mech)));
#endif

if ((defbv - deduct) < 1)
    defbv = 1;
else
    defbv -= deduct;
if (type != CLASS_MECH)
    defbv = ((defbv * (move == MOVE_TRACK ? 0.8 : move == MOVE_WHEEL ? 0.7 : move == MOVE_HOVER ? 0.6 : move == MOVE_VTOL ? 0.4 : move == MOVE_FOIL || move == MOVE_SUB || move == MOVE_HULL? 0.5 : 1.0)) - deduct);
defbv = defbv * mul;

#ifdef DEBUG_BV
SendDebug(tprintf("DefBV : %d", defbv / 100));
#endif

if ((type == CLASS_MECH || is_aero(mech)) && mostheat > (MechActiveNumsinks(mech) * 100)) {
#ifdef DEBUG_BV
SendDebug(tprintf("Pre-Heat OffWeapBV : %d", offweapbv / 100));
#endif
    i = (((MechActiveNumsinks(mech) / 100) * offweapbv) / mostheat);
    ii = ((offweapbv - i) / 2);
    offweapbv = i + ii;

#ifdef DEBUG_BV
SendDebug(tprintf("Post-Heat OffWeapBV : %d", offweapbv / 100));
#endif
}
/*
mul = pow(((((MMaxSpeed(mech) / MP1) + (type == CLASS_AERO || type == CLASS_DS ? 0 : (MechJumpSpeed(mech) / MP1)) + (mechspec & MASC_TECH ? 1 : 0) + (mechspec & TRIPLE_MYOMER_TECH ? 1 : 0)+ (mechspec2 & SUPERCHARGER_TECH ? 1 : 0) - 5) / 10) + 1), 1.2);
*/
mul = pow((((((IsDS(mech) ? WalkingSpeed(MMaxSpeed(mech)) : MMaxSpeed(mech)) / MP1) + (mechspec & MASC_TECH ? 1 : 0) + (mechspec & TRIPLE_MYOMER_TECH ? 1 : 0) + (mechspec2 & SUPERCHARGER_TECH ?1 : 0) - 5) / 10) + 1), 1.2);

#ifdef DEBUG_BV
SendDebug(tprintf("DumbMul : %.2f", mul));
#endif

if (mechspec2 & OMNIMECH_TECH)
    mul += .3;

offweapbv = offweapbv * mul;
if (type != CLASS_AERO && type != CLASS_DS && MechJumpSpeed(mech) > 0)
    offweapbv += ((MechJumpSpeed(mech) / MP1) * (100 * (MechTons(mech) / 5)));
offbv = offweapbv;

#ifdef DEBUG_BV
SendDebug(tprintf("OffWeapBVAfter : %d", offweapbv / 100));
SendDebug(tprintf("DefBV : %d OffBV : %d TotalBV : %d", defbv / 100, offbv / 100, (offbv + defbv) / 100));
#endif

mul = (skillmul[LAZY_SKILLMUL(gunskl)][LAZY_SKILLMUL(pilskl)]);

#ifdef DEBUG_BV
SendDebug(tprintf("SkillMul : %.2f (%d/%d)", mul, gunskl, pilskl));
#endif
return ((offbv + defbv) / 100) * mul;
}
#endif

int MechFullNoRecycle(MECH * mech, int num)
{
    int i;

    for (i = 0; i < NUM_SECTIONS; i++) {
        if (num & CHECK_WEAPS && SectHasBusyWeap(mech, i))
            return 1;
        if (num & CHECK_PHYS && MechSections(mech)[i].recycle > 0)
            return 2;
        }
    return 0;
}

#ifdef BT_COMPLEXREPAIRS
int GetPartMod(MECH * mech, int t)
{
int val, div, bound;

    div = (t && t == Special(GYRO) ? 100 : t && t == Special(ENGINE) ? 20 : 10);
    bound = (t && t == Special(GYRO) ? 3 : t && t == Special(ENGINE) ? 19 : 9);
    val = (t && (t == Special(GYRO) || t == Special(ENGINE)) ?
		MechEngineSize(mech) : MechTons(mech));

    if (val % div != 0)
        val = val + (div - (val % div));

return BOUNDED(0, (val / div) - 1, bound);
}

int ProperArmor(MECH * mech)
{
/* For now they all use the same basic cargo parts. */
return Cargo(MechSpecials(mech) & FF_TECH ? FF_ARMOR :
	     MechSpecials(mech) & HARDA_TECH ? HD_ARMOR :
	     MechSpecials2(mech) & HVY_FF_ARMOR_TECH ? HVY_FF_ARMOR :
	     MechSpecials2(mech) & LT_FF_ARMOR_TECH ? LT_FF_ARMOR :
	     MechSpecials2(mech) & STEALTH_ARMOR_TECH ? STH_ARMOR :
	     S_ARMOR);
}

int ProperInternal(MECH * mech)
{
int part = 0;

    if (mudconf.btech_complexrepair) {
        part = (MechSpecials(mech) & ES_TECH ? TON_ESINTERNAL_FIRST :
		MechSpecials(mech) & REINFI_TECH ? TON_REINTERNAL_FIRST :
		MechSpecials(mech) & COMPI_TECH ? TON_COINTERNAL_FIRST :
		TON_INTERNAL_FIRST);
        part += GetPartMod(mech, 0);
    } else {
        part = (MechSpecials(mech) & ES_TECH ? ES_INTERNAL :
		MechSpecials(mech) & REINFI_TECH ? RE_INTERNAL :
		MechSpecials(mech) & COMPI_TECH ? CO_INTERNAL :
		S_INTERNAL);
    }
return Cargo(part);
}

int alias_part(MECH * mech, int t, int loc)
{
int part = 0;

    if (!IsSpecial(t))
	return t;

    if (mudconf.btech_complexrepair) {
        int tonmod = GetPartMod(mech, t);
        int locmod;
        if (MechIsQuad(mech))
            locmod = (loc == RARM || loc == LARM || loc == RLEG || loc == LLEG ? 2 : 0);
        else
            locmod = (loc == RARM || loc == LARM ? 1 : loc == LLEG || loc == RLEG ? 2 : 0);

        part = (locmod && (t == Special(SHOULDER_OR_HIP) || t == Special(UPPER_ACTUATOR)) ? (locmod == 1 ? Cargo(TON_ARMUPPER_FIRST + tonmod) : Cargo(TON_LEGUPPER_FIRST + tonmod)) :
            locmod && t == Special(LOWER_ACTUATOR) ? (locmod == 1 ? Cargo(TON_ARMLOWER_FIRST + tonmod) : Cargo(TON_LEGLOWER_FIRST + tonmod)) :
            locmod && t == Special(HAND_OR_FOOT_ACTUATOR) ? (locmod == 1 ? Cargo(TON_ARMHAND_FIRST + tonmod) : Cargo(TON_LEGFOOT_FIRST + tonmod)) :
            t == Special(ENGINE) && MechSpecials(mech) & XL_TECH ? Cargo(TON_ENGINE_XL_FIRST + tonmod) :
            t == Special(ENGINE) && MechSpecials(mech) & ICE_TECH ? Cargo(TON_ENGINE_ICE_FIRST + tonmod) :
            t == Special(ENGINE) && MechSpecials(mech) & CE_TECH ? Cargo(TON_ENGINE_COMP_FIRST + tonmod):
            t == Special(ENGINE) && MechSpecials(mech) & XXL_TECH ? Cargo(TON_ENGINE_XXL_FIRST + tonmod) :
            t == Special(ENGINE) && MechSpecials(mech) & LE_TECH ? Cargo(TON_ENGINE_LIGHT_FIRST + tonmod) :
            t == Special(ENGINE) ? Cargo(TON_ENGINE_FIRST + tonmod) :
            t == Special(HEAT_SINK) && MechSpecials(mech) & (DOUBLE_HEAT_TECH|CLAN_TECH) ? Cargo(DOUBLE_HEAT_SINK) :
            t == Special(HEAT_SINK) && MechSpecials2(mech) & COMPACT_HS_TECH ? Cargo(COMPACT_HEAT_SINK) :
            t == Special(GYRO) && MechSpecials2(mech) & XLGYRO_TECH ? Cargo(TON_XLGYRO_FIRST + tonmod) :
            t == Special(GYRO) && MechSpecials2(mech) & HDGYRO_TECH ? Cargo(TON_HDGYRO_FIRST + tonmod) :
            t == Special(GYRO) && MechSpecials2(mech) & CGYRO_TECH ? Cargo(TON_CGYRO_FIRST + tonmod) :
            t == Special(GYRO) ? Cargo(TON_GYRO_FIRST + tonmod) :
            t == Special(SENSORS) ? Cargo(TON_SENSORS_FIRST + tonmod) :
            t == Special(JUMP_JET) ? Cargo(TON_JUMPJET_FIRST + tonmod) :
            t);
    } else {
        part = (IsActuator(t) ? Cargo(S_ACTUATOR) :
            t == Special(ENGINE) && MechSpecials(mech) & XL_TECH ? Cargo(XL_ENGINE) :
            t == Special(ENGINE) && MechSpecials(mech) & ICE_TECH ? Cargo(IC_ENGINE) :
            t == Special(ENGINE) && MechSpecials(mech) & CE_TECH ? Cargo(COMP_ENGINE) :
            t == Special(ENGINE) && MechSpecials(mech) & XXL_TECH ? Cargo(XXL_ENGINE) :
            t == Special(ENGINE) && MechSpecials(mech) & LE_TECH ? Cargo(LIGHT_ENGINE) :
            t == Special(HEAT_SINK) && MechSpecials(mech) & (DOUBLE_HEAT_TECH|CLAN_TECH) ? Cargo(DOUBLE_HEAT_SINK) :
            t == Special(HEAT_SINK) && MechSpecials2(mech) & COMPACT_HS_TECH ? Cargo(COMPACT_HEAT_SINK) :
            t == Special(GYRO) && MechSpecials2(mech) & XLGYRO_TECH ? Cargo(XL_GYRO) :
            t == Special(GYRO) && MechSpecials2(mech) & HDGYRO_TECH ? Cargo(HD_GYRO) :
            t == Special(GYRO) && MechSpecials2(mech) & CGYRO_TECH ? Cargo(COMP_GYRO) :
            t);
    }
return part;
}

int ProperMyomer(MECH * mech)
{
int part;

        part = (MechSpecials(mech) & TRIPLE_MYOMER_TECH ? TON_TRIPLEMYOMER_FIRST : TON_MYOMER_FIRST);
        part += GetPartMod(mech, 0);

return Cargo(part);
}
#endif

/* Function to return a value of how much heat a unit is putting out*/
/* TODO: Double check how Stealth Armor and Null Sig are coded */
int HeatFactor(MECH * mech) {

    int factor = 0;
    char buf[LBUF_SIZE];

    if (MechType(mech) != CLASS_MECH) {
        factor = (((MechSpecials(mech) & ICE_TECH)) ? -1 : 21);
        return factor;
    } else {
        factor = (MechPlusHeat(mech) + (2 * (MechPlusHeat(mech) - MechMinusHeat(mech))));
        return ((NullSigSysActive(mech) || HasWorkingECMSuite(mech) ||
                    StealthArmorActive(mech)) ? -1 : factor);
    }
    snprintf(buf, LBUF_SIZE, "HeatFactor : Invalid heat factor calculation on #%d.",
            mech->mynum);
    SendDebug(buf);
}

/* Function to determine if a weapon is functional or not
   Returns 0 if fully functional.
   Returns 1 if non functional.
   Returns 2 if fully damaged.
   Returns -(# of crits) if partially damaged.
   remember that values 3 means the weapon IS NOT destroyed.  */
int WeaponIsNonfunctional(MECH * mech, int section, int crit, int numcrits)
{
    int sum = 0, disabled = 0, dested = 0;

    if (numcrits <= 0)
        numcrits = GetWeaponCrits(mech, Weapon2I(GetPartType(mech, section, crit)));

    while (sum < numcrits) {
        if (PartIsDestroyed(mech, section, crit + sum))
            dested++;
        else if (PartIsDisabled(mech, section, crit + sum))
            disabled++;
        sum++;
    }

    if (disabled > 0)
        return 1;

    if ((numcrits == 1 && (dested || disabled)) || 
            (numcrits > 1 && (dested + disabled) >= numcrits / 2))
        return 2;

    if (dested)
        return 0 - (dested + disabled);

    return 0;
}