public static ToHitData toHit(IGame game, int attackerId, Targetable target, Mounted club) { final Entity ae = game.getEntity(attackerId);   if (ae == null || target == null) { throw new IllegalArgumentException("Attacker or target not valid"); } if (club == null) { throw new IllegalArgumentException("Club is null"); } if (club.getType() == null) { throw new IllegalArgumentException("Club type is null"); }  String impossible = toHitIsImpossible(game, ae, target); if(impossible != null) { return new ToHitData(ToHitData.IMPOSSIBLE, impossible); }   if (!(ae instanceof Mech)) { return new ToHitData(ToHitData.IMPOSSIBLE, "Non-mechs can't club"); }   if (ae.entityIsQuad()) { return new ToHitData(ToHitData.IMPOSSIBLE, "Attacker is a quad"); }  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.height(); final int targetElevation = target.getElevation() + targHex.getElevation(); final int targetHeight = targetElevation + target.getHeight(); final boolean bothArms = (club.getType().hasFlag(MiscType.F_CLUB) && ((MiscType)club.getType()).hasSubType(MiscType.S_CLUB)); final boolean hasClaws = ( ((BipedMech)ae).hasClaw(Mech.LOC_RARM) || ((BipedMech)ae).hasClaw(Mech.LOC_LARM) ); final boolean shield = ((MiscType)club.getType()).isShield();  ToHitData toHit;   if (bothArms) {  if (ae.isLocationBad(Mech.LOC_RARM) || ae.isLocationBad(Mech.LOC_LARM)) { return new ToHitData(ToHitData.IMPOSSIBLE, "Arm missing"); }  if (ae.weaponFiredFrom(Mech.LOC_RARM) || ae.weaponFiredFrom(Mech.LOC_LARM)) { return new ToHitData(ToHitData.IMPOSSIBLE, "Weapons fired from arm this turn"); }  if (!ae.hasWorkingSystem(Mech.ACTUATOR_SHOULDER, Mech.LOC_RARM) || !ae.hasWorkingSystem(Mech.ACTUATOR_SHOULDER, Mech.LOC_LARM)) { return new ToHitData(ToHitData.IMPOSSIBLE, "Shoulder actuator destroyed"); } if ( (!ae.hasWorkingSystem(Mech.ACTUATOR_HAND, Mech.LOC_RARM) || !ae.hasWorkingSystem(Mech.ACTUATOR_HAND, Mech.LOC_LARM))  && !hasClaws) { return new ToHitData(ToHitData.IMPOSSIBLE, "Hand actuator destroyed"); } } else if (shield) { if (!ae.hasPassiveShield(club.getLocation())) { return new ToHitData(ToHitData.IMPOSSIBLE, "Shield not in passive mode"); } } else {  if (ae.isLocationBad(club.getLocation())) { return new ToHitData(ToHitData.IMPOSSIBLE, "Arm missing"); }  if (ae.weaponFiredFrom(club.getLocation())) { return new ToHitData(ToHitData.IMPOSSIBLE, "Weapons fired from arm this turn"); }  if (!ae.hasWorkingSystem(Mech.ACTUATOR_SHOULDER, club.getLocation())) { return new ToHitData(ToHitData.IMPOSSIBLE, "Shoulder actuator destroyed"); } if (!ae.hasWorkingSystem(Mech.ACTUATOR_HAND, club.getLocation()) && !hasClaws) { return new ToHitData(ToHitData.IMPOSSIBLE, "Hand actuator destroyed"); } }   if (!shield && ae.getBadCriticals(CriticalSlot.TYPE_EQUIPMENT, ae.getEquipmentNum(club), club.getLocation()) > 0) { return new ToHitData(ToHitData.IMPOSSIBLE, "Club is damaged"); }   int targetMaxElevation = attackerHeight; if(target instanceof VTOL) { targetMaxElevation ++; } if (targetHeight < attackerElevation || targetElevation > targetMaxElevation) { return new ToHitData(ToHitData.IMPOSSIBLE, "Target elevation not in range"); }   int clubArc = bothArms ? Compute.ARC_FORWARD : (club.getLocation() == Mech.LOC_LARM ? Compute.ARC_LEFTARM : Compute.ARC_RIGHTARM); if ( !Compute.isInArc( ae.getPosition(), ae.getSecondaryFacing(), target.getPosition(), clubArc ) ) { 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 instanceof GunEmplacement ) { return new ToHitData( ToHitData.AUTOMATIC_SUCCESS, "Targeting adjacent building." ); }   int base = 4;  if ( game.getOptions().booleanOption("maxtech_physical_BTH") ) { base = ae.getCrew().getPiloting() - 1; }   if (((MiscType)club.getType()).hasSubType(MiscType.S_SWORD)) { base -= 1; } else if ((((MiscType)club.getType()).hasSubType(MiscType.S_DUAL_SAW)) || (((MiscType)club.getType()).hasSubType(MiscType.S_CHAINSAW))) { base += 1; } else if ((((MiscType)club.getType()).hasSubType(MiscType.S_MACE_THB)) || (((MiscType)club.getType()).hasSubType(MiscType.S_MACE)) || (((MiscType)club.getType()).hasSubType(MiscType.S_BACKHOE))) { base += 2; } else if (((MiscType)club.getType()).hasSubType(MiscType.S_PILE_DRIVER)) { base += 3; } else if (((MiscType)club.getType()).hasSubType(MiscType.S_SHIELD_LARGE)) { base -= 3; } else if (((MiscType)club.getType()).hasSubType(MiscType.S_SHIELD_MEDIUM)) { base -= 2; } else if (((MiscType)club.getType()).hasSubType(MiscType.S_SHIELD_SMALL)) { base -= 1; }   toHit = new ToHitData(base, "base");  setCommonModifiers(toHit, game, ae, target);   if (bothArms) { if (!ae.hasWorkingSystem(Mech.ACTUATOR_UPPER_ARM, Mech.LOC_RARM)) { toHit.addModifier(2, "Upper arm actuator destroyed"); } if (!ae.hasWorkingSystem(Mech.ACTUATOR_UPPER_ARM, Mech.LOC_LARM)) { toHit.addModifier(2, "Upper arm actuator destroyed"); } if (!ae.hasWorkingSystem(Mech.ACTUATOR_LOWER_ARM, Mech.LOC_RARM)) { toHit.addModifier(2, "Lower arm actuator missing or destroyed"); } if (!ae.hasWorkingSystem(Mech.ACTUATOR_LOWER_ARM, Mech.LOC_LARM)) { toHit.addModifier(2, "Lower arm actuator missing or destroyed"); } if (hasClaws) { toHit.addModifier(2, "Mek has claws"); } } else { if (!ae.hasWorkingSystem(Mech.ACTUATOR_UPPER_ARM, club.getLocation())) { toHit.addModifier(2, "Upper arm actuator destroyed"); } if (!ae.hasWorkingSystem(Mech.ACTUATOR_LOWER_ARM, club.getLocation())) { toHit.addModifier(2, "Lower arm actuator missing or destroyed"); }  if (hasClaws) { toHit.addModifier(2, "Mek has claws"); } }   if (attackerElevation == targetElevation) { if (shield) toHit.setHitTable(ToHitData.HIT_PUNCH); else toHit.setHitTable(ToHitData.HIT_NORMAL); } else if (attackerElevation < targetElevation) { if (target.getHeight() == 0) { if (shield ) toHit.setHitTable(ToHitData.HIT_PUNCH); else toHit.setHitTable(ToHitData.HIT_NORMAL); } else { toHit.setHitTable(ToHitData.HIT_KICK); } } else { toHit.setHitTable(ToHitData.HIT_PUNCH); }   toHit.setSideTable(Compute.targetSideTable(ae,target));   return toHit;
public ToHitData toHit(IGame game) { return toHit(game, getEntityId(), game.getTarget(getTargetType(), getTargetId()), getClub());
    public static ToHitData toHit(IGame game, int attackerId, Targetable target, Mounted club) {        final Entity ae = game.getEntity(attackerId);        // arguments legal?        if (ae == null || target == null) {            throw new IllegalArgumentException("Attacker or target not valid");        }        if (club == null) {            throw new IllegalArgumentException("Club is null");        }        if (club.getType() == null) {            throw new IllegalArgumentException("Club type is null");        }        String impossible = toHitIsImpossible(game, ae, target);        if(impossible != null) {            return new ToHitData(ToHitData.IMPOSSIBLE, impossible);        }        // non-mechs can't club        if (!(ae instanceof Mech)) {            return new ToHitData(ToHitData.IMPOSSIBLE, "Non-mechs can't club");        }        //Quads can't club        if (ae.entityIsQuad()) {            return new ToHitData(ToHitData.IMPOSSIBLE, "Attacker is a quad");        }        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.height();        final int targetElevation = target.getElevation() + targHex.getElevation();        final int targetHeight = targetElevation + target.getHeight();        final boolean bothArms = (club.getType().hasFlag(MiscType.F_CLUB)                && ((MiscType)club.getType()).hasSubType(MiscType.S_CLUB));        final boolean hasClaws = ( ((BipedMech)ae).hasClaw(Mech.LOC_RARM) || ((BipedMech)ae).hasClaw(Mech.LOC_LARM) );        final boolean shield = ((MiscType)club.getType()).isShield();                ToHitData toHit;        if (bothArms) {            // check if both arms are present & operational            if (ae.isLocationBad(Mech.LOC_RARM)                    || ae.isLocationBad(Mech.LOC_LARM)) {                return new ToHitData(ToHitData.IMPOSSIBLE, "Arm missing");            }            // check if attacker has fired arm-mounted weapons            if (ae.weaponFiredFrom(Mech.LOC_RARM)                    || ae.weaponFiredFrom(Mech.LOC_LARM)) {                return new ToHitData(ToHitData.IMPOSSIBLE, "Weapons fired from arm this turn");            }            // need shoulder and hand actuators            if (!ae.hasWorkingSystem(Mech.ACTUATOR_SHOULDER, Mech.LOC_RARM)                    || !ae.hasWorkingSystem(Mech.ACTUATOR_SHOULDER, Mech.LOC_LARM)) {                return new ToHitData(ToHitData.IMPOSSIBLE, "Shoulder actuator destroyed");            }            if ( (!ae.hasWorkingSystem(Mech.ACTUATOR_HAND, Mech.LOC_RARM)                    || !ae.hasWorkingSystem(Mech.ACTUATOR_HAND, Mech.LOC_LARM))  && !hasClaws) {                return new ToHitData(ToHitData.IMPOSSIBLE, "Hand actuator destroyed");            }        } else if (shield) {            if (!ae.hasPassiveShield(club.getLocation())) {                return new ToHitData(ToHitData.IMPOSSIBLE, "Shield not in passive mode");            }        } else {            // check if arm is present            if (ae.isLocationBad(club.getLocation())) {                return new ToHitData(ToHitData.IMPOSSIBLE, "Arm missing");            }            // check if attacker has fired arm-mounted weapons            if (ae.weaponFiredFrom(club.getLocation())) {                return new ToHitData(ToHitData.IMPOSSIBLE, "Weapons fired from arm this turn");            }            // need shoulder and hand actuators            if (!ae.hasWorkingSystem(Mech.ACTUATOR_SHOULDER, club.getLocation())) {                return new ToHitData(ToHitData.IMPOSSIBLE, "Shoulder actuator destroyed");            }            if (!ae.hasWorkingSystem(Mech.ACTUATOR_HAND, club.getLocation()) && !hasClaws) {                return new ToHitData(ToHitData.IMPOSSIBLE, "Hand actuator destroyed");            }        }        // club must not be damaged        if (!shield && ae.getBadCriticals(CriticalSlot.TYPE_EQUIPMENT,                ae.getEquipmentNum(club), club.getLocation()) > 0) {            return new ToHitData(ToHitData.IMPOSSIBLE, "Club is damaged");        }        // check elevation (target must be within one level, except for VTOL)        int targetMaxElevation = attackerHeight;        if(target instanceof VTOL) {            targetMaxElevation ++;        }        if (targetHeight < attackerElevation || targetElevation > targetMaxElevation) {            return new ToHitData(ToHitData.IMPOSSIBLE, "Target elevation not in range");        }        // check facing        int clubArc = bothArms ? Compute.ARC_FORWARD : (club.getLocation() == Mech.LOC_LARM ? Compute.ARC_LEFTARM : Compute.ARC_RIGHTARM);        if ( !Compute.isInArc( ae.getPosition(), ae.getSecondaryFacing(),                       target.getPosition(), clubArc ) ) {            return new ToHitData(ToHitData.IMPOSSIBLE, "Target not in arc");        }        // can't club 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 instanceof GunEmplacement ) {            return new ToHitData( ToHitData.AUTOMATIC_SUCCESS,                                  "Targeting adjacent building." );        }        //Set the base BTH        int base = 4;        if ( game.getOptions().booleanOption("maxtech_physical_BTH") ) {            base = ae.getCrew().getPiloting() - 1;        }        // Various versions of physical weapons have different base bonuses and penalties.        if (((MiscType)club.getType()).hasSubType(MiscType.S_SWORD)) {            base -= 1;        } else if ((((MiscType)club.getType()).hasSubType(MiscType.S_DUAL_SAW))                || (((MiscType)club.getType()).hasSubType(MiscType.S_CHAINSAW))) {            base += 1;        } else if ((((MiscType)club.getType()).hasSubType(MiscType.S_MACE_THB))                 || (((MiscType)club.getType()).hasSubType(MiscType.S_MACE))                || (((MiscType)club.getType()).hasSubType(MiscType.S_BACKHOE))) {            base += 2;        } else if (((MiscType)club.getType()).hasSubType(MiscType.S_PILE_DRIVER)) {            base += 3;        } else if (((MiscType)club.getType()).hasSubType(MiscType.S_SHIELD_LARGE)) {            base -= 3;        } else if (((MiscType)club.getType()).hasSubType(MiscType.S_SHIELD_MEDIUM)) {            base -= 2;        } else if (((MiscType)club.getType()).hasSubType(MiscType.S_SHIELD_SMALL)) {            base -= 1;        }        toHit = new ToHitData(base, "base");        setCommonModifiers(toHit, game, ae, target);        // damaged or missing actuators        if (bothArms) {            if (!ae.hasWorkingSystem(Mech.ACTUATOR_UPPER_ARM, Mech.LOC_RARM)) {                toHit.addModifier(2, "Upper arm actuator destroyed");            }            if (!ae.hasWorkingSystem(Mech.ACTUATOR_UPPER_ARM, Mech.LOC_LARM)) {                toHit.addModifier(2, "Upper arm actuator destroyed");            }            if (!ae.hasWorkingSystem(Mech.ACTUATOR_LOWER_ARM, Mech.LOC_RARM)) {                toHit.addModifier(2, "Lower arm actuator missing or destroyed");            }            if (!ae.hasWorkingSystem(Mech.ACTUATOR_LOWER_ARM, Mech.LOC_LARM)) {                toHit.addModifier(2, "Lower arm actuator missing or destroyed");            }            if (hasClaws) {                toHit.addModifier(2, "Mek has claws");            }        } else {            if (!ae.hasWorkingSystem(Mech.ACTUATOR_UPPER_ARM, club.getLocation())) {                toHit.addModifier(2, "Upper arm actuator destroyed");            }            if (!ae.hasWorkingSystem(Mech.ACTUATOR_LOWER_ARM, club.getLocation())) {                toHit.addModifier(2, "Lower arm actuator missing or destroyed");            }            //Rules state +2 bth if your using a club with claws.            if (hasClaws) {                toHit.addModifier(2, "Mek has claws");            }        }        // elevation        if (attackerElevation == targetElevation) {            if (shield)                toHit.setHitTable(ToHitData.HIT_PUNCH);            else                toHit.setHitTable(ToHitData.HIT_NORMAL);        } else if (attackerElevation < targetElevation) {            if (target.getHeight() == 0) {                if (shield )                    toHit.setHitTable(ToHitData.HIT_PUNCH);                else                    toHit.setHitTable(ToHitData.HIT_NORMAL);            } else {                toHit.setHitTable(ToHitData.HIT_KICK);            }        } else {            toHit.setHitTable(ToHitData.HIT_PUNCH);        }        // factor in target side        toHit.setSideTable(Compute.targetSideTable(ae,target));        // done!        return toHit;    }