public static ToHitData toHit(IGame game, int attackerId, Targetable target, int leg) { final Entity ae = game.getEntity(attackerId); if (ae == null) return new ToHitData(ToHitData.IMPOSSIBLE, "You can't attack from a null entity!");  String impossible = toHitIsImpossible(game, ae, target); if(impossible != null) { return new ToHitData(ToHitData.IMPOSSIBLE, "impossible"); }  IHex attHex = game.getBoard().getHex(ae.getPosition()); IHex targHex = game.getBoard().getHex(target.getPosition()); final int attackerElevation = ae.getElevation() + attHex.getElevation(); final int targetElevation = target.getElevation() + targHex.getElevation(); final int targetHeight = targetElevation + target.getHeight();  int mule = 0; int[] kickLegs = new int[2]; if ( ae.entityIsQuad() ) { if (leg==KickAttackAction.LEFTMULE || leg==KickAttackAction.RIGHTMULE) { kickLegs[0] = Mech.LOC_RLEG; kickLegs[1] = Mech.LOC_LLEG; mule = 1; } else { kickLegs[0] = Mech.LOC_RARM; kickLegs[1] = Mech.LOC_LARM; } } else { kickLegs[0] = Mech.LOC_RLEG; kickLegs[1] = Mech.LOC_LLEG; } final int legLoc = ( (leg == KickAttackAction.RIGHTMULE) || (leg == KickAttackAction.RIGHT) ) ? kickLegs[0] : kickLegs[1];  ToHitData toHit;    if (leg != KickAttackAction.RIGHT && leg != KickAttackAction.LEFT && leg != KickAttackAction.RIGHTMULE && leg != KickAttackAction.LEFTMULE) { throw new IllegalArgumentException("Leg must be one of LEFT, RIGHT, LEFTMULE, or RIGHTMULE"); }   if (!(ae instanceof Mech)) { return new ToHitData(ToHitData.IMPOSSIBLE, "Non-mechs can't kick"); }   if (ae.isLocationBad(kickLegs[0]) || ae.isLocationBad(kickLegs[1])) { return new ToHitData(ToHitData.IMPOSSIBLE, "Leg missing"); }   if (!ae.hasWorkingSystem(Mech.ACTUATOR_HIP, kickLegs[0]) || !ae.hasWorkingSystem(Mech.ACTUATOR_HIP, kickLegs[1])) { return new ToHitData(ToHitData.IMPOSSIBLE, "Hip destroyed"); }   for (Mounted mounted : ae.getWeaponList()) { if (mounted.isUsedThisRound() && mounted.getLocation() == legLoc) { return new ToHitData(ToHitData.IMPOSSIBLE, "Weapons fired from leg this turn"); } }   final int range = ae.getPosition().distance(target.getPosition()); if ( target instanceof Infantry && 1 == range ) {  return new ToHitData(ToHitData.IMPOSSIBLE, "Can only stomp Infantry in same hex"); }   if (attackerElevation < targetElevation || attackerElevation > targetHeight) { return new ToHitData(ToHitData.IMPOSSIBLE, "Target elevation not in range"); }    if (0 != range && mule != 1 && !Compute.isInArc(ae.getPosition(), ae.getFacing(), target.getPosition(), Compute.ARC_FORWARD)) { return new ToHitData(ToHitData.IMPOSSIBLE, "Target not in arc"); }   if (0 != range && mule == 1 && !Compute.isInArc(ae.getPosition(), ae.getFacing(), target.getPosition(), Compute.ARC_REAR) && !Compute.isInArc(ae.getPosition(), ae.getFacing(), target.getPosition(), Compute.ARC_LEFTSIDE) && !Compute.isInArc(ae.getPosition(), ae.getFacing(), target.getPosition(), Compute.ARC_RIGHTSIDE)) { return new ToHitData(ToHitData.IMPOSSIBLE, "Target not in arc"); }   if (ae.isProne()) { return new ToHitData(ToHitData.IMPOSSIBLE, "Attacker is prone"); }   if (target.getTargetType() == Targetable.TYPE_BUILDING || target.getTargetType() == Targetable.TYPE_FUEL_TANK || target instanceof GunEmplacement) { return new ToHitData( ToHitData.AUTOMATIC_SUCCESS, "Targeting adjacent building." ); }   int base = ae.getCrew().getPiloting() - 2;   toHit = new ToHitData(base, "base");  setCommonModifiers(toHit, game, ae, target);   if ( target instanceof Infantry ) { toHit.addModifier( 3, "Stomping Infantry" ); }   if (mule!=0) { toHit.addModifier(mule, "Quad Mek making a mule kick"); }   if (!ae.hasWorkingSystem(Mech.ACTUATOR_UPPER_LEG, legLoc)) { toHit.addModifier(2, "Upper leg actuator destroyed"); } if (!ae.hasWorkingSystem(Mech.ACTUATOR_LOWER_LEG, legLoc)) { toHit.addModifier(2, "Lower leg actuator destroyed"); } if (!ae.hasWorkingSystem(Mech.ACTUATOR_FOOT, legLoc)) { toHit.addModifier(1, "Foot actuator destroyed"); }   if (attackerElevation < targetHeight) { toHit.setHitTable(ToHitData.HIT_KICK); } else if (target.getHeight() > 0) { toHit.setHitTable(ToHitData.HIT_PUNCH); } else { toHit.setHitTable(ToHitData.HIT_NORMAL); }   toHit.setSideTable(Compute.targetSideTable(ae,target));    if ( 0 == range && target instanceof Tank ) { toHit.setSideTable( ToHitData.SIDE_RANDOM ); }   return toHit;
public ToHitData toHit(IGame game) { return toHit(game, getEntityId(), game.getTarget(getTargetType(), getTargetId()), getLeg());
    public static ToHitData toHit(IGame game, int attackerId,                                      Targetable target, int leg) {        final Entity ae = game.getEntity(attackerId);        if (ae == null)            return new ToHitData(ToHitData.IMPOSSIBLE, "You can't attack from a null entity!");        String impossible = toHitIsImpossible(game, ae, target);        if(impossible != null) {            return new ToHitData(ToHitData.IMPOSSIBLE, "impossible");        }        IHex attHex = game.getBoard().getHex(ae.getPosition());        IHex targHex = game.getBoard().getHex(target.getPosition());        final int attackerElevation = ae.getElevation() + attHex.getElevation();        final int targetElevation = target.getElevation() + targHex.getElevation();        final int targetHeight = targetElevation + target.getHeight();        int mule = 0;        int[] kickLegs = new int[2];        if ( ae.entityIsQuad() ) {            if (leg==KickAttackAction.LEFTMULE || leg==KickAttackAction.RIGHTMULE) {                kickLegs[0] = Mech.LOC_RLEG;                kickLegs[1] = Mech.LOC_LLEG;                mule = 1; // To-hit modifier            } else {                kickLegs[0] = Mech.LOC_RARM;                kickLegs[1] = Mech.LOC_LARM;            }        } else {            kickLegs[0] = Mech.LOC_RLEG;            kickLegs[1] = Mech.LOC_LLEG;        }        final int legLoc =             ( (leg == KickAttackAction.RIGHTMULE) || (leg == KickAttackAction.RIGHT) ) ? kickLegs[0] : kickLegs[1];        ToHitData toHit;        // arguments legal?        // By allowing mulekicks, this gets a little more complicated :(        if (leg != KickAttackAction.RIGHT && leg != KickAttackAction.LEFT            && leg != KickAttackAction.RIGHTMULE && leg != KickAttackAction.LEFTMULE) {            throw new IllegalArgumentException("Leg must be one of LEFT, RIGHT, LEFTMULE, or RIGHTMULE");        }        // non-mechs can't kick        if (!(ae instanceof Mech)) {            return new ToHitData(ToHitData.IMPOSSIBLE, "Non-mechs can't kick");        }        // check if both legs are present & working        if (ae.isLocationBad(kickLegs[0])            || ae.isLocationBad(kickLegs[1])) {            return new ToHitData(ToHitData.IMPOSSIBLE, "Leg missing");        }        // check if both hips are operational        if (!ae.hasWorkingSystem(Mech.ACTUATOR_HIP, kickLegs[0])            || !ae.hasWorkingSystem(Mech.ACTUATOR_HIP, kickLegs[1])) {            return new ToHitData(ToHitData.IMPOSSIBLE, "Hip destroyed");        }        // check if attacker has fired leg-mounted weapons        for (Mounted mounted : ae.getWeaponList()) {            if (mounted.isUsedThisRound() && mounted.getLocation() == legLoc) {                return new ToHitData(ToHitData.IMPOSSIBLE, "Weapons fired from leg this turn");            }        }        // check range        final int range = ae.getPosition().distance(target.getPosition());        if ( target instanceof Infantry && 1 == range ) {            // As per Randall in the post, http://www.classicbattletech.com/w3t/showflat.php?Cat=&Board=ask&Number=626894&page=1&view=collapsed&sb=5&o=0&fpart=            return new ToHitData(ToHitData.IMPOSSIBLE,                                 "Can only stomp Infantry in same hex");        }        // check elevation        if (attackerElevation < targetElevation || attackerElevation > targetHeight) {            return new ToHitData(ToHitData.IMPOSSIBLE, "Target elevation not in range");        }        // check facing        // Don't check arc for stomping infantry or tanks.        if (0 != range && mule != 1 &&            !Compute.isInArc(ae.getPosition(), ae.getFacing(),                     target.getPosition(), Compute.ARC_FORWARD)) {            return new ToHitData(ToHitData.IMPOSSIBLE, "Target not in arc");        }        // check facing, part 2: Mule kick        if (0 != range && mule == 1 &&            !Compute.isInArc(ae.getPosition(), ae.getFacing(),                     target.getPosition(), Compute.ARC_REAR) &&            !Compute.isInArc(ae.getPosition(), ae.getFacing(),                     target.getPosition(), Compute.ARC_LEFTSIDE) &&            !Compute.isInArc(ae.getPosition(), ae.getFacing(),                     target.getPosition(), Compute.ARC_RIGHTSIDE)) {            return new ToHitData(ToHitData.IMPOSSIBLE, "Target not in arc");        }        // can't kick while prone        if (ae.isProne()) {            return new ToHitData(ToHitData.IMPOSSIBLE, "Attacker is prone");        }        // Attacks against adjacent buildings automatically hit.        if (target.getTargetType() == Targetable.TYPE_BUILDING                || target.getTargetType() == Targetable.TYPE_FUEL_TANK                || target instanceof GunEmplacement) {            return new ToHitData( ToHitData.AUTOMATIC_SUCCESS,                                  "Targeting adjacent building." );        }        //Set the base BTH        int base = ae.getCrew().getPiloting() - 2;        // Start the To-Hit        toHit = new ToHitData(base, "base");                setCommonModifiers(toHit, game, ae, target);        // BMR(r), page 33. +3 modifier for kicking infantry.        if ( target instanceof Infantry ) {            toHit.addModifier( 3, "Stomping Infantry" );        }        // Mulekick?        if (mule!=0) {            toHit.addModifier(mule, "Quad Mek making a mule kick");        }                // damaged or missing actuators        if (!ae.hasWorkingSystem(Mech.ACTUATOR_UPPER_LEG, legLoc)) {            toHit.addModifier(2, "Upper leg actuator destroyed");        }        if (!ae.hasWorkingSystem(Mech.ACTUATOR_LOWER_LEG, legLoc)) {            toHit.addModifier(2, "Lower leg actuator destroyed");        }        if (!ae.hasWorkingSystem(Mech.ACTUATOR_FOOT, legLoc)) {            toHit.addModifier(1, "Foot actuator destroyed");        }        // elevation        if (attackerElevation < targetHeight) {            toHit.setHitTable(ToHitData.HIT_KICK);        } else if (target.getHeight() > 0) {            toHit.setHitTable(ToHitData.HIT_PUNCH);        } else {            toHit.setHitTable(ToHitData.HIT_NORMAL);        }        // factor in target side        toHit.setSideTable(Compute.targetSideTable(ae,target));        // BMRr pg. 42, "The side on which a vehicle takes damage is determined        // randomly if the BattleMech is attacking from the same hex."        if ( 0 == range && target instanceof Tank ) {            toHit.setSideTable( ToHitData.SIDE_RANDOM );        }        // done!        return toHit;    }