los.targetCover |= COVER_HORIZONTAL;
los.targetCover |= COVER_HORIZONTAL; }
    private static LosEffects losForCoords(IGame game, AttackInfo ai,                                           Coords coords, Building thruBldg) {        LosEffects los = new LosEffects();                // ignore hexes not on board        if (!game.getBoard().contains(coords)) {            return los;        }            // Is there a building in this hex?        Building bldg = game.getBoard().getBuildingAt(coords);            // We're only tracing thru a single building if there        // is a building in this hex, and if it isn't the same        // building that we'be been tracing LOS thru.        if ( bldg != null && bldg.equals(thruBldg) ) {            los.setThruBldg( thruBldg );        }            // ignore hexes the attacker or target are in        if ( coords.equals(ai.attackPos) ||             coords.equals(ai.targetPos) ) {            return los;        }            IHex hex = game.getBoard().getHex(coords);        int hexEl = ai.underWaterCombat ? hex.floor() : hex.surface();        // Handle minimum water depth.        // Applies to Torpedos.        if (!(hex.containsTerrain(Terrains.WATER)))            ai.minimumWaterDepth = 0;        else if ((hex.terrainLevel(Terrains.WATER) >= 0)                && ((ai.minimumWaterDepth == -1)                || (hex.terrainLevel(Terrains.WATER) < ai.minimumWaterDepth)))            ai.minimumWaterDepth = hex.terrainLevel(Terrains.WATER);            // Handle building elevation.        // Attacks thru a building are not blocked by that building.        // ASSUMPTION: bridges don't block LOS.        int bldgEl = 0;        if ( null == los.getThruBldg() &&             hex.containsTerrain( Terrains.BLDG_ELEV ) ) {            bldgEl = hex.terrainLevel( Terrains.BLDG_ELEV );        }            // TODO: Identify when LOS travels *above* a building's hex.        //       Alternatively, force all building hexes to be same height.            // check for block by terrain                //check for LOS according to diagramming rule from MaxTech, page 22        if (game.getOptions().booleanOption("maxtech_LOS1")) {            if (hexEl + bldgEl > (ai.targetAbsHeight * ai.attackPos.distance(coords) +                                  ai.attackAbsHeight * ai.targetPos.distance(coords)) /                                  (ai.targetPos.distance(coords) +                                   ai.attackPos.distance(coords))) {                los.blocked = true;                    }        }        if ((hexEl + bldgEl > ai.attackAbsHeight && hexEl + bldgEl > ai.targetAbsHeight)        || (hexEl + bldgEl > ai.attackAbsHeight && ai.attackPos.distance(coords) == 1)        || (hexEl + bldgEl > ai.targetAbsHeight && ai.targetPos.distance(coords) == 1)) {            los.blocked = true;        }                // check if there's a clear hex between the targets that's higher than        // one of them, if we're in underwater combat        if (ai.underWaterCombat && hex.terrainLevel(Terrains.WATER) == ITerrain.LEVEL_NONE &&            (hexEl + bldgEl > ai.attackAbsHeight || hexEl + bldgEl > ai.targetAbsHeight)) {            los.blocked = true;        }            // check for woods or smoke only if not under water        if (!ai.underWaterCombat) {            if ((hexEl + 2 > ai.attackAbsHeight && hexEl + 2 > ai.targetAbsHeight)            || (hexEl + 2 > ai.attackAbsHeight && ai.attackPos.distance(coords) == 1)            || (hexEl + 2 > ai.targetAbsHeight && ai.targetPos.distance(coords) == 1)) {                // smoke overrides any woods in the hex if L3 smoke rule is off                if (!game.getOptions().booleanOption("maxtech_fire")) {                  if (hex.containsTerrain(Terrains.SMOKE)) {                    los.heavySmoke++;                  }                  else if (hex.terrainLevel(Terrains.WOODS) == 1) {                    los.lightWoods++;                  }                  else if (hex.terrainLevel(Terrains.WOODS) > 1) {                    los.heavyWoods++;                  }                }                // if the L3 fire/smoke rule is on, smoke and woods stack for LOS                // so check them both                else {                  if (hex.containsTerrain(Terrains.SMOKE)) {                    if (hex.terrainLevel(Terrains.SMOKE) == 1) {                      los.lightSmoke++;                    }                    else if (hex.terrainLevel(Terrains.SMOKE) > 1) {                      los.heavySmoke++;                    }                  }                  if (hex.terrainLevel(Terrains.WOODS) == 1) {                    los.lightWoods++;                  }                  else if (hex.terrainLevel(Terrains.WOODS) > 1) {                    los.heavyWoods++;                  }                }            }        }                // check for target partial cover        if ( ai.targetPos.distance(coords) == 1 &&             hexEl + bldgEl == ai.targetAbsHeight &&             ai.attackAbsHeight <= ai.targetAbsHeight && ai.targetHeight > 0) {            los.targetCover |= COVER_HORIZONTAL;        }            // check for attacker partial cover        if (ai.attackPos.distance(coords) == 1 &&            hexEl + bldgEl == ai.attackAbsHeight &&            ai.attackAbsHeight >= ai.targetAbsHeight && ai.attackHeight > 0) {            los.attackerCover |= COVER_HORIZONTAL;        }                return los;    }