public static ToHitData toHit(IGame game, int attackerId, Targetable target) { final Entity ae = game.getEntity(attackerId); if (ae == null) return new ToHitData(ToHitData.IMPOSSIBLE, "You can't attack from a null entity!");  if(!game.getOptions().booleanOption("maxtech_new_physicals")) return new ToHitData(ToHitData.IMPOSSIBLE, "no MaxTech physicals");  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 attackerHeight = attackerElevation + ae.getHeight(); final int targetElevation = target.getElevation() + targHex.getElevation(); final int targetHeight = targetElevation + target.getHeight();  ToHitData toHit;   if (!(ae instanceof BipedMech) || !(target instanceof Mech)) { return new ToHitData(ToHitData.IMPOSSIBLE, "Only biped mechs can trip other mechs"); }     if (ae.isLocationBad(Mech.LOC_LLEG) || ae.isLocationBad(Mech.LOC_RLEG)) { return new ToHitData(ToHitData.IMPOSSIBLE, "Leg missing"); }   final int range = ae.getPosition().distance(target.getPosition());  int limb1 = Entity.LOC_NONE; int limb2 = Entity.LOC_NONE;  if (attackerHeight < targetElevation || attackerElevation > targetElevation) { return new ToHitData(ToHitData.IMPOSSIBLE, "Target elevation not in range"); }   if (!Compute.isInArc(ae.getPosition(), ae.getFacing(), target.getPosition(), Compute.ARC_FORWARD)) { return new ToHitData(ToHitData.IMPOSSIBLE, "Target not in arc"); }   if (ae.isProne()) { return new ToHitData(ToHitData.IMPOSSIBLE, "Attacker is prone"); } if(((Entity)target).isProne()) { return new ToHitData(ToHitData.IMPOSSIBLE, "Target is prone"); }   boolean usedWeapons[] = new boolean[ae.locations()]; for(int i=0;i<ae.locations();i++) { usedWeapons[i] = false; }  for (Mounted mounted : ae.getWeaponList()) { if (mounted.isUsedThisRound()) { int loc = mounted.getLocation(); if(loc != Entity.LOC_NONE) usedWeapons[loc] = true; } }   if(!ae.hasWorkingSystem(Mech.ACTUATOR_HIP, Mech.LOC_RLEG)) usedWeapons[Mech.LOC_RLEG] = true; if(!ae.hasWorkingSystem(Mech.ACTUATOR_HIP, Mech.LOC_LLEG)) usedWeapons[Mech.LOC_LLEG] = true; if(!ae.hasWorkingSystem(Mech.ACTUATOR_SHOULDER, Mech.LOC_RARM)) usedWeapons[Mech.LOC_RARM] = true; if(!ae.hasWorkingSystem(Mech.ACTUATOR_SHOULDER, Mech.LOC_LARM)) usedWeapons[Mech.LOC_LARM] = true;   if(attackerElevation < targetElevation) { if(usedWeapons[Mech.LOC_RARM] || usedWeapons[Mech.LOC_LARM]) { return new ToHitData(ToHitData.IMPOSSIBLE, "both arms unusable"); } limb1 = Mech.LOC_LARM; limb2 = Mech.LOC_RARM; } else {  if(usedWeapons[Mech.LOC_RLEG]) { if(usedWeapons[Mech.LOC_LLEG]) { return new ToHitData(ToHitData.IMPOSSIBLE, "both legs unusable"); } limb1 = Mech.LOC_LLEG; } if(usedWeapons[Mech.LOC_RARM]) { if(usedWeapons[Mech.LOC_LARM]) { return new ToHitData(ToHitData.IMPOSSIBLE, "both arms unusable"); } limb2 = Mech.LOC_LARM; } }   int base = 4;   if ( game.getOptions().booleanOption("maxtech_physical_BTH") ) { base = ae.getCrew().getPiloting() - 1; }   toHit = new ToHitData(base, "base");  setCommonModifiers(toHit, game, ae, target);   if(limb1 == Entity.LOC_NONE) { ToHitData left = getLimbModifier(Mech.LOC_LLEG, ae); ToHitData right = getLimbModifier(Mech.LOC_RLEG, ae); if(left.getValue() < right.getValue()) toHit.append(left); else toHit.append(right); } else { toHit.append(getLimbModifier(limb1, ae)); }   if(limb2 == Entity.LOC_NONE) { ToHitData left = getLimbModifier(Mech.LOC_LARM, ae); ToHitData right = getLimbModifier(Mech.LOC_RARM, ae); if(left.getValue() < right.getValue()) toHit.append(left); else toHit.append(right); } else { toHit.append(getLimbModifier(limb2, ae)); }   return toHit;
public ToHitData toHit(IGame game) { return toHit(game, getEntityId(), game.getTarget(getTargetType(), getTargetId()));
    public static ToHitData toHit(IGame game, int attackerId,                                      Targetable target) {        final Entity ae = game.getEntity(attackerId);        if (ae == null)            return new ToHitData(ToHitData.IMPOSSIBLE, "You can't attack from a null entity!");        if(!game.getOptions().booleanOption("maxtech_new_physicals"))            return new ToHitData(ToHitData.IMPOSSIBLE, "no MaxTech physicals");                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 attackerHeight = attackerElevation + ae.getHeight();        final int targetElevation = target.getElevation() + targHex.getElevation();        final int targetHeight = targetElevation + target.getHeight();        ToHitData toHit;        // non-mechs can't trip or be tripped        if (!(ae instanceof BipedMech) || !(target instanceof Mech)) {            return new ToHitData(ToHitData.IMPOSSIBLE, "Only biped mechs can trip other mechs");        }        // described as a leg hook / clothesline,        // so it should need a working leg + a working arm        // and 2 legs present        if (ae.isLocationBad(Mech.LOC_LLEG)            || ae.isLocationBad(Mech.LOC_RLEG)) {            return new ToHitData(ToHitData.IMPOSSIBLE, "Leg missing");        }        // check range        final int range = ae.getPosition().distance(target.getPosition());        int limb1 = Entity.LOC_NONE;        int limb2 = Entity.LOC_NONE;        // check elevation (target equal or 1 higher - ankle grab)        if (attackerHeight < targetElevation || attackerElevation > targetElevation) {            return new ToHitData(ToHitData.IMPOSSIBLE, "Target elevation not in range");        }         // check facing        if (!Compute.isInArc(ae.getPosition(), ae.getFacing(),                     target.getPosition(), Compute.ARC_FORWARD)) {            return new ToHitData(ToHitData.IMPOSSIBLE, "Target not in arc");        }        // can't trip while prone        if (ae.isProne()) {            return new ToHitData(ToHitData.IMPOSSIBLE, "Attacker is prone");        }        if(((Entity)target).isProne()) {            return new ToHitData(ToHitData.IMPOSSIBLE, "Target is prone");        }        // check if attacker has fired leg-mounted weapons        boolean usedWeapons[] = new boolean[ae.locations()];        for(int i=0;i<ae.locations();i++) {            usedWeapons[i] = false;        }                for (Mounted mounted : ae.getWeaponList()) {            if (mounted.isUsedThisRound()) {                int loc = mounted.getLocation();                if(loc != Entity.LOC_NONE)                    usedWeapons[loc] = true;            }        }                //check for good hips / shoulders        if(!ae.hasWorkingSystem(Mech.ACTUATOR_HIP, Mech.LOC_RLEG))            usedWeapons[Mech.LOC_RLEG] = true;        if(!ae.hasWorkingSystem(Mech.ACTUATOR_HIP, Mech.LOC_LLEG))            usedWeapons[Mech.LOC_LLEG] = true;        if(!ae.hasWorkingSystem(Mech.ACTUATOR_SHOULDER, Mech.LOC_RARM))            usedWeapons[Mech.LOC_RARM] = true;        if(!ae.hasWorkingSystem(Mech.ACTUATOR_SHOULDER, Mech.LOC_LARM))            usedWeapons[Mech.LOC_LARM] = true;                //to ankle grab, need both arms        if(attackerElevation < targetElevation) {             if(usedWeapons[Mech.LOC_RARM] || usedWeapons[Mech.LOC_LARM]) {                return new ToHitData(ToHitData.IMPOSSIBLE, "both arms unusable");            }            limb1 = Mech.LOC_LARM;            limb2 = Mech.LOC_RARM;        } else {            //normal attack uses one leg and one arm            if(usedWeapons[Mech.LOC_RLEG]) {                if(usedWeapons[Mech.LOC_LLEG]) {                    return new ToHitData(ToHitData.IMPOSSIBLE, "both legs unusable");                }                limb1 = Mech.LOC_LLEG;            }            if(usedWeapons[Mech.LOC_RARM]) {                if(usedWeapons[Mech.LOC_LARM]) {                    return new ToHitData(ToHitData.IMPOSSIBLE, "both arms unusable");                }                limb2 = Mech.LOC_LARM;            }        }        //Set the base BTH        int base = 4;        // Level 3 rule: the BTH is PSR - 1        if ( game.getOptions().booleanOption("maxtech_physical_BTH") ) {            base = ae.getCrew().getPiloting() - 1;        }        // Start the To-Hit        toHit = new ToHitData(base, "base");                setCommonModifiers(toHit, game, ae, target);                // Get best leg        if(limb1 == Entity.LOC_NONE) {            ToHitData left = getLimbModifier(Mech.LOC_LLEG, ae);            ToHitData right = getLimbModifier(Mech.LOC_RLEG, ae);            if(left.getValue() < right.getValue())                toHit.append(left);            else                toHit.append(right);        } else {            toHit.append(getLimbModifier(limb1, ae));        }                // Get best arm        if(limb2 == Entity.LOC_NONE) {            ToHitData left = getLimbModifier(Mech.LOC_LARM, ae);            ToHitData right = getLimbModifier(Mech.LOC_RARM, ae);            if(left.getValue() < right.getValue())                toHit.append(left);            else                toHit.append(right);        } else {            toHit.append(getLimbModifier(limb2, ae));        }                // done!        return toHit;    }