public static ToHitData toHit(Game game, int attackerId, Targetable target) { final Entity ae = game.getEntity(attackerId); int targetId = Entity.NONE; Entity te = null; if ( target.getTargetType() == Targetable.TYPE_ENTITY ) { te = (Entity) target; targetId = target.getTargetId(); } final int attackerElevation = ae.getElevation(); final int targetHeight = target.absHeight(); final int targetElevation = target.getElevation(); final boolean targetInBuilding = Compute.isInBuilding( game, te ); Building bldg = null; if ( targetInBuilding ) { bldg = game.board.getBuildingAt( te.getPosition() ); } final int nightModifier = (game.getOptions().booleanOption("night_battle")) ? +2 : 0; ToHitData toHit;   if (ae == null || target == null) { throw new IllegalArgumentException("Attacker or target not valid"); }   if (ae.equals(te)) { return new ToHitData(ToHitData.IMPOSSIBLE, "You can't target yourself"); }   if (!(ae instanceof Protomech)) { return new ToHitData(ToHitData.IMPOSSIBLE, "Non-protos can't make proto-physicalattacks"); }   if (ae.isSpotting()) { return new ToHitData(ToHitData.IMPOSSIBLE, "Attacker is spotting this turn"); }   if ( te != null && Entity.NONE != te.getTransportId() ) { return new ToHitData(ToHitData.IMPOSSIBLE, "Target is a passenger."); }   if ( te != null && Entity.NONE != te.getSwarmTargetId() ) { return new ToHitData(ToHitData.IMPOSSIBLE, "Target is swarming a Mek."); }   final int range = ae.getPosition().distance(target.getPosition()); if ( range > 1 ) { return new ToHitData(ToHitData.IMPOSSIBLE, "Target not in range"); }   if (attackerElevation < targetElevation || attackerElevation > targetHeight) { return new ToHitData(ToHitData.IMPOSSIBLE, "Target elevation not in range"); }   if ( te != null && te.isMakingDfa() ) { return new ToHitData(ToHitData.IMPOSSIBLE, "Target is making a DFA attack"); }   if (range == 0) { return new ToHitData(ToHitData.IMPOSSIBLE, "Target not in adjacent hex"); }    if (0 != range && !Compute.isInArc(ae.getPosition(), ae.getFacing(), target.getPosition(), Compute.ARC_FORWARD)) { return new ToHitData(ToHitData.IMPOSSIBLE, "Target not in arc"); }   if ( 0 != range && targetInBuilding ) { if ( !Compute.isInBuilding(game, ae) ) { return new ToHitData(ToHitData.IMPOSSIBLE, "Target is inside building" ); } else if ( !game.board.getBuildingAt( ae.getPosition() ) .equals( bldg ) ) { return new ToHitData(ToHitData.IMPOSSIBLE, "Target is inside differnt building" ); } }   if ( target.getTargetType() == Targetable.TYPE_BUILDING ) { return new ToHitData( ToHitData.AUTOMATIC_SUCCESS, "Targeting adjacent building." ); }   if ( target.getTargetType() == Targetable.TYPE_BLDG_IGNITE || target.getTargetType() == Targetable.TYPE_HEX_CLEAR || target.getTargetType() == Targetable.TYPE_HEX_IGNITE ) { return new ToHitData( ToHitData.IMPOSSIBLE, "Invalid attack"); }   int base = 4;   toHit = new ToHitData(base, "base");   toHit.append(Compute.getAttackerMovementModifier(game, attackerId));   toHit.append(Compute.getTargetMovementModifier(game, targetId));   toHit.append(Compute.getAttackerTerrainModifier(game, attackerId));   toHit.append(Compute.getTargetTerrainModifier(game, te));   if (te.isProne()) { toHit.addModifier(-2, "target prone and adjacent"); }   Hex targHex = game.board.getHex(te.getPosition()); if (te.height() > 0 && targHex.levelOf(Terrain.WATER) == te.height()) { toHit.addModifier(3, "target has partial cover"); }   toHit.append(Compute.getImmobileMod(te));  if (nightModifier>0) { toHit.addModifier(nightModifier, "Night Battle, no Spotlight"); }  Compute.modifyPhysicalBTHForAdvantages(ae, te, toHit, game);   if (attackerElevation < targetHeight) { toHit.setHitTable(ToHitData.HIT_KICK); } else if (te.height() > 0) { toHit.setHitTable(ToHitData.HIT_PUNCH); } else { toHit.setHitTable(ToHitData.HIT_NORMAL); }   toHit.setSideTable(Compute.targetSideTable(ae,te));   return toHit;
public ToHitData toHit(Game game) { return toHit(game, getEntityId(), game.getTarget(getTargetType(), getTargetId()));
    public static ToHitData toHit(Game game, int attackerId, Targetable target) {    	final Entity ae = game.getEntity(attackerId);        int targetId = Entity.NONE;        Entity te = null;        if ( target.getTargetType() == Targetable.TYPE_ENTITY ) {            te = (Entity) target;            targetId = target.getTargetId();        }        final int attackerElevation = ae.getElevation();        final int targetHeight = target.absHeight();        final int targetElevation = target.getElevation();        final boolean targetInBuilding = Compute.isInBuilding( game, te );        Building bldg = null;        if ( targetInBuilding ) {            bldg = game.board.getBuildingAt( te.getPosition() );        }        final int nightModifier = (game.getOptions().booleanOption("night_battle")) ? +2 : 0;        ToHitData toHit;        // arguments legal?        if (ae == null || target == null) {            throw new IllegalArgumentException("Attacker or target not valid");        }        // can't target yourself        if (ae.equals(te)) {            return new ToHitData(ToHitData.IMPOSSIBLE, "You can't target yourself");        }        // non-protos can't make protomech-physicalattacks        if (!(ae instanceof Protomech)) {            return new ToHitData(ToHitData.IMPOSSIBLE, "Non-protos can't make proto-physicalattacks");        }        // can't make physical attacks while spotting        if (ae.isSpotting()) {            return new ToHitData(ToHitData.IMPOSSIBLE, "Attacker is spotting this turn");        }        // Can't target a transported entity.        if ( te != null && Entity.NONE != te.getTransportId() ) {            return new ToHitData(ToHitData.IMPOSSIBLE, "Target is a passenger.");        }        // Can't target a entity conducting a swarm attack.        if ( te != null && Entity.NONE != te.getSwarmTargetId() ) {            return new ToHitData(ToHitData.IMPOSSIBLE, "Target is swarming a Mek.");        }        // check range        final int range = ae.getPosition().distance(target.getPosition());        if ( range > 1 ) {            return new ToHitData(ToHitData.IMPOSSIBLE, "Target not in range");        }        // check elevation        if (attackerElevation < targetElevation || attackerElevation > targetHeight) {            return new ToHitData(ToHitData.IMPOSSIBLE, "Target elevation not in range");        }        // can't physically attack mechs making dfa attacks        if ( te != null && te.isMakingDfa() ) {            return new ToHitData(ToHitData.IMPOSSIBLE, "Target is making a DFA attack");        }                //can only target targets in adjacent hexes, not in same hex        if (range == 0) {        	return new ToHitData(ToHitData.IMPOSSIBLE, "Target not in adjacent hex");        }                // check facing        // Don't check arc for stomping infantry or tanks.        if (0 != range &&            !Compute.isInArc(ae.getPosition(), ae.getFacing(),                     target.getPosition(), Compute.ARC_FORWARD)) {            return new ToHitData(ToHitData.IMPOSSIBLE, "Target not in arc");        }        // Can't target units in buildings (from the outside).        if ( 0 != range && targetInBuilding ) {            if ( !Compute.isInBuilding(game, ae) ) {                return new ToHitData(ToHitData.IMPOSSIBLE, "Target is inside building" );            }            else if ( !game.board.getBuildingAt( ae.getPosition() )                      .equals( bldg ) ) {                return new ToHitData(ToHitData.IMPOSSIBLE, "Target is inside differnt building" );            }        }        // Attacks against adjacent buildings automatically hit.        if ( target.getTargetType() == Targetable.TYPE_BUILDING ) {            return new ToHitData( ToHitData.AUTOMATIC_SUCCESS,                                  "Targeting adjacent building." );        }        // Can't target woods or ignite a building with a physical.        if ( target.getTargetType() == Targetable.TYPE_BLDG_IGNITE ||             target.getTargetType() == Targetable.TYPE_HEX_CLEAR ||             target.getTargetType() == Targetable.TYPE_HEX_IGNITE ) {            return new ToHitData( ToHitData.IMPOSSIBLE, "Invalid attack");        }        //Set the base BTH        int base = 4;        // Start the To-Hit        toHit = new ToHitData(base, "base");        // attacker movement        toHit.append(Compute.getAttackerMovementModifier(game, attackerId));        // target movement        toHit.append(Compute.getTargetMovementModifier(game, targetId));        // attacker terrain        toHit.append(Compute.getAttackerTerrainModifier(game, attackerId));        // target terrain        toHit.append(Compute.getTargetTerrainModifier(game, te));        // target prone        if (te.isProne()) {            toHit.addModifier(-2, "target prone and adjacent");        }        // water partial cover?        Hex targHex = game.board.getHex(te.getPosition());        if (te.height() > 0 && targHex.levelOf(Terrain.WATER) == te.height()) {            toHit.addModifier(3, "target has partial cover");        }        // target immobile        toHit.append(Compute.getImmobileMod(te));        if (nightModifier>0) {            toHit.addModifier(nightModifier, "Night Battle, no Spotlight");        }                Compute.modifyPhysicalBTHForAdvantages(ae, te, toHit, game);        // elevation        if (attackerElevation < targetHeight) {            toHit.setHitTable(ToHitData.HIT_KICK);        } else if (te.height() > 0) {            toHit.setHitTable(ToHitData.HIT_PUNCH);        } else {            toHit.setHitTable(ToHitData.HIT_NORMAL);        }        // factor in target side        toHit.setSideTable(Compute.targetSideTable(ae,te));        // done!        return toHit;    }