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.bth.c,v 1.2 2005/06/23 15:27:04 av1-op Exp $
 *
 * Author: Cord Awtry <kipsta@mediaone.net>
 * Author: Cord Awtry <kipsta@mediaone.net>
 *  Copyright (c) 2000-2002 Cord Awtry
 *  Copyright (c) 1999-2005 Kevin Stevens
 *       All rights reserved
 *
 * Based on work that was:
 *  Copyright (c) 1997 Markus Stenberg
 *  Copyright (c) 1998-2000 Thomas Wouters
 */

#include <math.h>

#include "mech.h"
#include "mech.events.h"
#include "p.mech.bth.h"
#include "p.mech.c3.misc.h"
#include "p.mech.combat.h"
#include "p.mech.enhanced.criticals.h"
#include "p.mech.hitloc.h"
#include "p.mech.los.h"
#include "p.mech.update.h"
#include "p.mech.utils.h"

#ifndef BTH_DEBUG
#define BTHBASE(m,t,n)  baseToHit = n;
#define BTHADD(desc,n)  baseToHit += n;
#define BTHEND(m)
#else
#define BTHBASE(m,t,n)  do { if (t) sprintf(buf, "#%d -> #%d: Base %d", m->mynum, t->mynum, n); else sprintf(buf, "#%d -> (hex): Base %d", m->mynum, n); baseToHit = n; } while (0)
#define BTHADD(desc,n)  do { i = n ; if (i) { sprintf(buf+strlen(buf), ", %s: %s%d", desc, i>0 ? "+" : "", i); baseToHit += i; } } while (0)
#define BTHEND(m)       SendBTHDebug(tprintf("%s.", buf))
#endif

int arc_override;

int FindNormalBTH(MECH * mech,
    MAP * mech_map,
    int section,
    int critical,
    int weapindx, float range, MECH * target, int indirectFire,
    dbref * c3Ref)
{
    MECH *spotter = NULL;
    int baseToHit;
    int wFireMode = GetPartFireMode(mech, section, critical);
    int wAmmoMode = GetPartAmmoMode(mech, section, critical);
    int tInWater = 0;
    int tTargetInWater = 0;
    int wTargMoveMod = 0;

#ifdef BTH_DEBUG
    char buf[LBUF_SIZE];
    int i;
#endif
    int j, rbth = 0;
    float enemyX, enemyY, enemyZ;
    int wRangeBracket = RANGE_TOFAR;

    *c3Ref = -1;

    if (target) {
	tInWater = ((MechRTerrain(mech) == WATER) && (MechZ(mech) < 0));
	tTargetInWater = ((MechRTerrain(target) == WATER) &&
	    (MechZ(target) < 0));
    }

    BTHBASE(mech, target, FindPilotGunnery(mech, weapindx));

    if (indirectFire < 1000) {
	spotter = getMech(MechSpotter(mech));

	if (!spotter) {
	    mech_notify(mech, MECHALL,
		"Error finding your spotter! (notify a wiz)");
	    return 0;
	}

	BTHADD("Spotting", FindPilotSpotting(spotter) - 4);
    }

    /* Our special bother for aeros */
    if (is_aero(mech) && target && !is_aero(target) && !Landed(mech)) {
	BTHADD("Aero strafing", 2);
    };

    /* MW need +2 added per FASA */
    if (target && MechType(target) == CLASS_MW)
	BTHADD("MechWarrior", 2);

    /* add in to-hit mods from criticals */
    BTHADD("MechBTHMod", MechBTH(mech));

    /* add in to-hit mods for section damage */
    BTHADD("MechLocBTHMod", MechSections(mech)[section].basetohit);

    /* Add +1 if we're firing from water */
    if (tInWater)
	BTHADD("InWater", 1);

    /* Add in the rangebase.. */
    if (EGunRange(weapindx) < range) {
	BTHADD("OutOfRange", 1000);
    } else {
	if ((MechWeapons[weapindx].min >= range) &&
	    (MechWeapons[weapindx].min > 0)) {
	    if (!HotLoading(weapindx, GetPartFireMode(mech, section,
			critical))) {
		/* if the target is in minimum range then the BTH is as good as it will get */
		rbth = (MechWeapons[weapindx].min - range + 1);
	    } else {
		if (mudconf.btech_hotloadaddshalfbthmod) {
		    rbth = ((MechWeapons[weapindx].min - range + 2) / 2);
		}
	    }

	    BTHADD("MinRange", rbth);
	} else if (HasC3(mech) && !C3Destroyed(mech) &&
	    !AnyECMDisturbed(mech) && (MechC3NetworkSize(mech) > 0)) {
	    wRangeBracket = FindBTHByC3Range(mech, target,
		section, weapindx, range,
		findC3Range(mech, target, range, c3Ref, 1), wAmmoMode,
		&rbth);

	    BTHADD("C3Range", rbth);
	} else if (HasC3i(mech) && !C3iDestroyed(mech) &&
	    !AnyECMDisturbed(mech) && (MechC3iNetworkSize(mech) > 0)) {
	    wRangeBracket = FindBTHByC3Range(mech, target,
		section, weapindx, range,
		findC3Range(mech, target, range, c3Ref, 0), wAmmoMode,
		&rbth);

	    BTHADD("C3iRange", rbth);
	} else {
	    wRangeBracket = FindBTHByRange(mech, target, section,
		weapindx, range, wFireMode, &rbth);

	    BTHADD("Range", rbth);
	}
    }
/* I decided to put it here in this rewritten form. To add it to FindBTH*() was a bit
 * convoluted compared to original source method, Exile and 3030/btechmux went a few
 * different path's on internal representation and organization of various weapon data
 * and BTH handling. Someday I might, after I review how some of the same things were
 * done here, port some of that stuff over. (Like GunStat() and such)
 *
 * For now we just do the below stuff. Besides, it might make BTH debug more obvious
 * that putting it into FindBTH*().
 */
    if (MechTargComp(mech) == TARGCOMP_SHORT || MechTargComp(mech) == TARGCOMP_LONG) {
	int tmp_range;

	if (MechWeapons[weapindx].special & PCOMBAT)
	    tmp_range = (int) (range * 10 + 0.95);
	else
	    tmp_range = (int) (range + 0.95);

	if (tmp_range >
		(SectionUnderwater(mech, section) ? GunWaterRange(weapindx) : GunRange(weapindx)))
	    BTHADD("TargComp/Long", MechTargComp(mech) == TARGCOMP_LONG ? -1 : 1); 
	else if (tmp_range <=
		(SectionUnderwater(mech, section) ? MechWeapons[weapindx].medrange_water : MechWeapons[weapindx].medrange))
	    BTHADD("TargComp/Short", MechTargComp(mech) == TARGCOMP_SHORT ? -1 : 1);
    }

    if (target && MechInfantrySpecials(target) & STEALTH_TECH) {
	if (MechInfantrySpecials(target) & FWL_ACHILEUS_STEALTH_TECH) {
	    if (wRangeBracket == RANGE_SHORT)
		BTHADD("FWLStealthBonus", 1);
	    else if (wRangeBracket == RANGE_MED)
		BTHADD("FWLStealthBonus", 2);
	    else if (wRangeBracket == RANGE_LONG)
		BTHADD("FWLStealthBonus", 3);
	} else if (MechInfantrySpecials(target) & DC_KAGE_STEALTH_TECH) {
	    if (wRangeBracket == RANGE_MED)
		BTHADD("DCStealthBonus", 1);
	    else if (wRangeBracket == RANGE_LONG)
		BTHADD("DCStealthBonus", 2);
	} else if (MechInfantrySpecials(target) &
	    FC_INFILTRATOR_STEALTH_TECH) {
	    if (wRangeBracket == RANGE_MED)
		BTHADD("FCStealthBonus", 1);
	    else if (wRangeBracket == RANGE_LONG)
		BTHADD("FCStealthBonus", 2);
	} else if (MechInfantrySpecials(target) &
	    FC_INFILTRATORII_STEALTH_TECH) {
	    if (wRangeBracket == RANGE_SHORT)
		BTHADD("FCStealthIIBonus", 1);
	    if (wRangeBracket == RANGE_MED)
		BTHADD("FCStealthIIBonus", 1);
	    else if (wRangeBracket == RANGE_LONG)
		BTHADD("FCStealthIIBonus", 2);
	}
    }

    /* Add in the movement modifiers */
    if (MechSections(mech)[section].config & STABILIZERS_DESTROYED)
	BTHADD("AttackMoveX2", AttackMovementMods(mech) * 2);
    else
	BTHADD("AttackMove", AttackMovementMods(mech));

    /* Add mods for overheating */
    BTHADD("Overheat", OverheatMods(mech));

    /* Add special weapon mods */
    if (wAmmoMode & AC_AP_MODE)
	BTHADD("ArmorPiercing", 1);

    if (checkAllSections(mech, INARC_HAYWIRE_ATTACHED))
	BTHADD("HaywirePod", 1);

    if (target && (wAmmoMode & NARC_MODE) &&
	(!(MechWeapons[weapindx].special & NARC)) &&
	checkAllSections(target, INARC_HOMING_ATTACHED))
	BTHADD("iNARC", -1);

    if (MechWeapons[weapindx].special & PULSE)
	BTHADD("Pulse", -2);

    if (MechWeapons[weapindx].special & MRM)
	BTHADD("MRM", 1);

    if (MechWeapons[weapindx].special & HVYW)
	BTHADD("HeavyWeapon", 1);
    if (target && (wAmmoMode & STINGER_MODE)) {
	if (FlyingT(target) && !Landed(target))
	    BTHADD("Stinger (Flying)", -3);
	else if (OODing(target))
	    BTHADD("Stinger (OOD)", -1);
	else if (Jumping(target))
	    BTHADD("Stinger (Jumping)", 0);
	}

 
    if (MechWeapons[weapindx].special & ROCKET)
	BTHADD("Rocket Launcher", 1);

    if (target && (MechType(target) == CLASS_VTOL) &&
	(fabs(MechSpeed(target)) > 0.0 ||
	    fabs(MechVerticalSpeed(target)) > 0.0))
	BTHADD("TargetVTOL", 1);

    if (target && MechTargComp(mech) == TARGCOMP_AA) {
	if (!Landed(target) && (FlyingT(target) || Jumping(target) || OODing(target)))
	    BTHADD("TargComp/AA-Fly", MechSpecials(mech) & AA_TECH ? -3 : -2);
	else
	    BTHADD("TargComp/AA-Ground", 1);
    }

    /* -1 for LBX, unless it's a VTOL... then -3 */
    if (wAmmoMode & LBX_MODE)
	BTHADD("LBX", (target &&
		(MechType(target) == CLASS_VTOL) ? -3 : -1));

    /* Unstable lock */
    if (!arc_override && (!spotter && target &&
        ((MechTarget(mech) != target->mynum) ||
	    (Locking(mech) && MechTargComp(mech) != TARGCOMP_MULTI)))) {    
	if (FindTargetXY(mech, &enemyX, &enemyY, &enemyZ)) {
	    if (InWeaponArc(mech, enemyX, enemyY) & (FORWARDARC|TURRETARC))
		BTHADD("UnstableLock/Fwarc", 1);
	    else
		BTHADD("UnstableLock", 2);
	} else {
	    BTHADD("HipShot-NoLock", 2);
	}
    }

    if (MechTargComp(mech) == TARGCOMP_MULTI) {
	if (FindTargetXY(mech, &enemyX, &enemyY, &enemyZ)) {
            if (!(InWeaponArc(mech, enemyX, enemyY) & FORWARDARC))
                BTHADD("TargComp/MultiSideArc", 1);
        }
    }

    /* -4 for firing at a hex */
    if (!target &&
	(MechStatus(mech) & (LOCK_HEX | LOCK_BUILDING | LOCK_HEX_IGN |
		LOCK_HEX_CLR)))
	BTHADD("HexBonus", -4);

    /* -2 for firing at someone dropping out of the sky */
    if (target && C_OODing(target))
	BTHADD("OODbonus", -2);

    /* Indirect fire terrain modifiers */
    if (indirectFire < 1000)
	BTHADD("IDFTerrain", indirectFire);

    /* +1 if spotting */
    if (MechSpotter(mech) == mech->mynum)
	BTHADD("Spotting", 1);

    /* if our target is another unit... */
    if (target) {
	/* Add the dig-in bonus */
	if (MechDugIn(target) && (!mudconf.btech_dig_only_fs &&
		(FindAreaHitGroup(mech, target) == FRONT)) &&
	    (MechZ(target) >= MechZ(mech)))
	    BTHADD("DugIn", mudconf.btech_digbonus);

	/* -3 if it's a DS... most people can hit the broadside of a barn */
	if (IsDS(target))
	    BTHADD("DSBonus", -3);

	/* Add +1 for BSuit dispersion */
	if (MechType(target) == CLASS_BSUIT)
	    BTHADD("Bsuitbonus", 1);

	/* Let's see if we're targetting the head */
	if (target && !IsMissile(weapindx) &&
	    (((MechAim(mech) == HEAD) && ((MechType(target) == CLASS_MECH)
			|| (MechType(target) == CLASS_MW))) ||
		((MechAim(mech) == AERO_COCKPIT) &&
		    (MechType(target) == CLASS_AERO)))) {
	    if (Immobile(target))
		BTHADD("HeadTarget", 7);
	    else
		BTHADD("HeadTarget-Fake", 25);
	} else {
	    if ((GetPartFireMode(mech, section, critical) & ON_TC) &&
		!(MechCritStatus(mech) & TC_DESTROYED) &&
		!(wAmmoMode & LBX_MODE)) {
		if (MechAim(mech) != NUM_SECTIONS && !Immobile(target))
		    BTHADD("TC-Target-NotImmobile", 3);
		else
		    BTHADD("TC", -1);
	    }
	}

	/* Add aero targetting mods. TODO: Rewrite aero code :) */
	if (MechType(mech) == CLASS_AERO) {
	    wTargMoveMod = TargetMovementMods(mech, target, range) * 3 / 4;
	} else {
	    wTargMoveMod = TargetMovementMods(mech, target, range);
	}

	if (wAmmoMode & AC_PRECISION_MODE)
	    wTargMoveMod = MAX(wTargMoveMod -= 2, 0);

	BTHADD("TargetMove", wTargMoveMod);

	/* Add in the terrain modifier */
	if (indirectFire >= 1000) {
	    j = AddTerrainMod(mech, target, mech_map, range, wAmmoMode);
	    if (j < 1000)
		BTHADD("Terrain/Light(Sensor)", j);
	}

	if (mudconf.btech_moddamagewithwoods &&
	    IsForestHex(mech_map, MechX(target), MechY(target)) &&
	    ((MechZ(target) - 2) <= Elevation(mech_map, MechX(target),
		    MechY(target)))) {
	    if (GetRTerrain(mech_map, MechX(target),
		    MechY(target)) == LIGHT_FOREST)
		BTHADD("Light Woods bonus", -1);
	    else if (GetRTerrain(mech_map, MechX(target),
		    MechY(target)) == HEAVY_FOREST)
		BTHADD("Heavy Woods bonus", -2);
	}
#ifdef BT_MOVEMENT_MODES
	if (MechStatus2(target) & (SPRINTING|EVADING)) {
	    if (MechStatus2(target) & SPRINTING)
		BTHADD("SprintingTarget", -4);
	    if (!Fallen(target) && MechStatus2(target) & EVADING)
		BTHADD("EvadingTarget", 1);
/*		BTHADD("EvadingTarget", (FindPilotPiloting(target) >= 6 ? 1 :
					 FindPilotPiloting(target) >= 4 ? 2 :
					 FindPilotPiloting(target) >= 2 ? 3 : 4) +
			(HasBoolAdvantage(MechPilot(target), "speed_demon") ? 1 : 0)); */
        } else if (MoveModeChange(target)) {
            int i = MoveModeData(target);
            if (i & MODE_SPRINT)
                BTHADD("SprintingTargetChanging", -4);
            if (i & MODE_EVADE)
                BTHADD("EvadingTargetChanging", 1);
/*		BTHADD("EvadingTarget", (FindPilotPiloting(target) >= 6 ? 1 :
					 FindPilotPiloting(target) >= 4 ? 2 :
					 FindPilotPiloting(target) >= 2 ? 3 : 4) +
			(HasBoolAdvantage(MechPilot(target), "speed_demon") ? 1 : 0)); */
        }
#endif
    }

    /* Check for damage */
    BTHADD("CritDamage", getCritAddedBTH(mech, section, critical,
	    wRangeBracket));

    BTHEND(mech);
    return baseToHit;
}

int FindArtilleryBTH(MECH * mech,
    int section, int weapindx, int indirect, float range)
{
    int baseToHit = 11;
    MECH *spotter;

    if (SectionUnderwater(mech, section))
	return 5000;

    if (EGunRange(weapindx) < range)
	return 1000;

    baseToHit += (FindPilotArtyGun(mech) - 4);
    if (indirect) {
	spotter = getMech(MechSpotter(mech));
	if (spotter && spotter != mech)
	    baseToHit += (FindPilotSpotting(spotter) - 4) / 2;
	/* the usual +2, added by +1 make +3 */
	if (indirect && (MechSpotter(mech) == -1 ||
		MechSpotter(mech) == mech->mynum))
	    baseToHit += 1;
    } else
	baseToHit -= 2;
    return baseToHit - MechFireAdjustment(mech);
}

int FindBTHByRange(MECH * mech, MECH * target, int section,
    int weapindx, float frange, int mode, int *wBTH)
{
    int range;
    int wTargetStealth = 0;

    if (target)
	wTargetStealth = (StealthArmorActive(target) ||
	    NullSigSysActive(target));

    if (MechWeapons[weapindx].special & PCOMBAT)
	range = (int) (frange * 10 + 0.95);
    else
	range = (int) (frange + 0.95);

    if (SectionUnderwater(mech, section)) {
	if (MechWeapons[weapindx].shortrange_water <= 0) {
	    *wBTH = 5000;
	    return RANGE_NOWATER;
	}

	/* Out of range range */
	if (range > EGunWaterRange(weapindx)) {
	    *wBTH = 1000;
	    return RANGE_TOFAR;
	}

	/* Very long range */
	if (range > GunWaterRange(weapindx)) {
	    *wBTH = wTargetStealth ? 12 : 8;
	    return RANGE_EXTREME;
	}

	/* Long range... */
	if (range > MechWeapons[weapindx].medrange_water) {
	    *wBTH = wTargetStealth ? 6 : 4;
	    return RANGE_LONG;
	}

	/* Medium range */
	if (range > MechWeapons[weapindx].shortrange_water) {
	    *wBTH = wTargetStealth ? 3 : 2;
	    return RANGE_MED;
	}

	/* Short range */
	if (range > MechWeapons[weapindx].min_water) {
	    *wBTH = 0;
	    return RANGE_SHORT;
	}

	if (range == 0) {
	    if (MechWeapons[weapindx].min_water == 0) {
		*wBTH = 0;
		return RANGE_SHORT;
	    } else {
		*wBTH = MechWeapons[weapindx].min_water - range;
		return RANGE_SHORT;
	    }
	}

	/* Less than or equal to minimum range */
	*wBTH = MechWeapons[weapindx].min_water - range + 1;
    }

    /* Beyond range */
    if (range > EGunRange(weapindx)) {
	*wBTH = 1000;
	return RANGE_TOFAR;
    }

    /* V. Long range */
    if (range > GunRange(weapindx)) {
	*wBTH = wTargetStealth ? 12 : 8;
	return RANGE_EXTREME;
    }

    /* Long range... */
    if (range > MechWeapons[weapindx].medrange) {
	*wBTH = wTargetStealth ? 6 : 4;
	return RANGE_LONG;
    }

    /* Medium range */
    if (range > MechWeapons[weapindx].shortrange) {
	*wBTH = wTargetStealth ? 3 : 2;
	return RANGE_MED;
    }

    /* Short range */
    if (range > MechWeapons[weapindx].min) {
	*wBTH = 0;
	return RANGE_SHORT;
    }
    /* If we are at range 0.0

     * Added 8/3/99 by Kipsta (to fix a 0.0 bug)
     */

    if (range == 0) {
	if (MechWeapons[weapindx].min == 0) {
	    *wBTH = 0;
	    return RANGE_SHORT;
	} else {
	    if (!HotLoading(weapindx, mode)) {
		*wBTH = MechWeapons[weapindx].min - range;
	    } else {
		if (mudconf.btech_hotloadaddshalfbthmod)
		    *wBTH = ((MechWeapons[weapindx].min - range + 1) / 2);
		else
		    *wBTH = 0;
	    }

	    return RANGE_SHORT;
	}
    }


    if (HotLoading(weapindx, mode)) {
	if (mudconf.btech_hotloadaddshalfbthmod)
	    *wBTH = ((MechWeapons[weapindx].min - range + 1) / 2);
	else
	    *wBTH = 0;

	return RANGE_SHORT;
    }

    /* Less than or equal to minimum range */
    *wBTH = MechWeapons[weapindx].min - range + 1;
    return RANGE_SHORT;
}

int FindBTHByC3Range(MECH * mech, MECH * target, int section,
    int weapindx, float realRange, float c3Range, int mode, int *wBTH)
{
    int realRangeAdj = 0.0;
    int c3RangeAdj = 0.0;
    int wTargetStealth = 0;

    if (target)
	wTargetStealth = (StealthArmorActive(target) ||
	    NullSigSysActive(target));

    if (MechWeapons[weapindx].special & PCOMBAT) {
	realRangeAdj = (int) (realRange * 10 + 0.95);
	c3RangeAdj = (int) (c3Range * 10 + 0.95);
    } else {
	realRangeAdj = (int) (realRange + 0.95);
	c3RangeAdj = (int) (c3Range + 0.95);
    }

    if (SectionUnderwater(mech, section)) {
	if (MechWeapons[weapindx].shortrange_water <= 0) {
	    *wBTH = 5000;
	    return RANGE_NOWATER;
	}

	/* Out of range. No ERange in C3 */
	if (realRangeAdj > GunWaterRange(weapindx)) {
	    *wBTH = 1000;
	    return RANGE_TOFAR;
	}

	/* Long range... */
	if (c3RangeAdj > MechWeapons[weapindx].medrange_water) {
	    *wBTH = wTargetStealth ? 6 : 4;
	    return RANGE_LONG;
	}

	/* Medium range */
	if (c3RangeAdj > MechWeapons[weapindx].shortrange_water) {
	    *wBTH = wTargetStealth ? 3 : 2;
	    return RANGE_MED;
	}

	/* Short range */
	*wBTH = 0;
	return RANGE_SHORT;
    }

    /* Beyond range */
    if (realRangeAdj > GunRange(weapindx)) {
	*wBTH = 1000;
	return RANGE_TOFAR;
    }

    /* No V. Long range in a C3 network */
    /* Long range... */
    if (c3RangeAdj > MechWeapons[weapindx].medrange) {
	*wBTH = wTargetStealth ? 6 : 4;
	return RANGE_LONG;
    }

    /* Medium range */
    if (c3RangeAdj > MechWeapons[weapindx].shortrange) {
	*wBTH = wTargetStealth ? 3 : 2;
	return RANGE_MED;
    }

    /* Short range */
    if (realRange > MechWeapons[weapindx].min) {
	*wBTH = 0;
	return RANGE_SHORT;
    }

    /* Check for range 0.0 */
    if (c3RangeAdj == 0) {
	if (MechWeapons[weapindx].min == 0) {
	    *wBTH = 0;
	    return RANGE_SHORT;
	}
    }

    /* We don't care about min range if we're Hotloading */
    if (!HotLoading(weapindx, mode)) {
	if (mudconf.btech_hotloadaddshalfbthmod)
	    *wBTH = ((MechWeapons[weapindx].min - realRange + 1) / 2);
	else
	    *wBTH = 0;

	return RANGE_SHORT;
    }

    /* Less than or equal to minimum PHYSICAL range */
    *wBTH = MechWeapons[weapindx].min - realRange + 1;
    return RANGE_SHORT;
}

int AttackMovementMods(MECH * mech)
{
    float maxspeed;
    float speed;
    int base = 0;

    if (MechType(mech) == CLASS_BSUIT)
	return 0;

    maxspeed = MechMaxSpeed(mech);
    if ((MechHeat(mech) >= 9.) &&
	(MechSpecials(mech) & TRIPLE_MYOMER_TECH))
	maxspeed += 1.5 * MP1;
    if (Jumping(mech))
	return 3;

    /* quads don't suffer the +2 BTH firing while prone if they have all 4 legs */
    if ((!MechIsQuad(mech) || (MechIsQuad(mech) &&
		CountDestroyedLegs(mech) > 0)) && Fallen(mech) &&
	!IsDS(mech))
	return 2;

    if (!Jumping(mech) && (Stabilizing(mech) || Standing(mech)))
	return 2;

    if (fabs(MechSpeed(mech)) > fabs(MechDesiredSpeed(mech)))
	speed = MechSpeed(mech);
    else
	speed = MechDesiredSpeed(mech);

    if (mudconf.btech_fasaturn)
	if (MechFacing(mech) != MechDesiredFacing(mech))
	    base++;

    if (!(fabs(speed) > 0.0))
	return base + 0;
    if (IsRunning(speed, maxspeed))
	return 2;
    return base + 1;
}

int TargetMovementMods(MECH * mech, MECH * target, float range)
{
    float target_speed = 0.0;
    int returnValue = 0;
    float m = 1.0;
    MAP *map = FindObjectsData(target->mapindex);
    MECH *swarmTarget;

    if (is_aero(target)) {
	if (is_aero(mech))
	    m = ACCEL_MOD;
	target_speed =
	    (float) length_hypotenuse((double) MechSpeed(target) / m,
	    (double) MechVerticalSpeed(target) / m);
    } else {
	if (Jumping(target)) {
	    target_speed = JumpSpeed(target, map);
	} else if (MechSwarmTarget(target) > 0) {
	    if ((swarmTarget = getMech(MechSwarmTarget(target)))) {
		if (Jumping(swarmTarget))
		    target_speed = JumpSpeed(swarmTarget, map);
		else
		    target_speed = fabs(MechSpeed(swarmTarget));
	    }
	} else {
	    target_speed = fabs(MechSpeed(target));
	}
    }

    if (MechInfantrySpecials(target) & CS_PURIFIER_STEALTH_TECH) {
	if (target_speed == 0.0) {
	    /* Mech moved 0-2 hexes */
	    returnValue = 3;
	} else if (target_speed <= MP1) {
	    /* Mech moved 3-4 hexes */
	    returnValue = 2;
	} else if (target_speed <= MP2) {
	    /* Mech moved 5-6 hexes */
	    returnValue = 1;
	} else {
	    returnValue = 0;
	}
    } else {
	if (target_speed <= MP2) {
	    /* Mech moved 0-2 hexes */
	    returnValue = 0;
	} else if (target_speed <= MP4) {
	    /* Mech moved 3-4 hexes */
	    returnValue = 1;
	} else if (target_speed <= MP6) {
	    /* Mech moved 5-6 hexes */
	    returnValue = 2;
	} else if (target_speed <= MP9) {
	    /* Mech moved 7-9 hexes */
	    returnValue = 3;
	} else {
	    /* Moving more than 9 hexes */
	    if (mudconf.btech_extendedmovemod)
	    	returnValue = 4 + (target_speed - 10*MP1) / MP4;
	    else
	    	returnValue = 4;
	}
    }

    if (Immobile(target))
	returnValue += -4;

    if (Fallen(target) && ((MechType(target) == CLASS_MECH) ||
	    (MechType(target) == CLASS_MW)))
	returnValue += (range <= 1.0) ? -2 : 1;

    if (Jumping(target))
	returnValue++;

    return (returnValue);
}