/*
   * (non-Javadoc)
   *
   * @see megamek.common.weapons.WeaponHandler#calcHits(Vector<Report>
   * vPhaseReport)
   */
  @Override
  protected int calcHits(Vector<Report> vPhaseReport) {
    // conventional infantry gets hit in one lump
    // BAs can't mount LBXs
    if ((target instanceof Infantry) && !(target instanceof BattleArmor)) {
      return 1;
    }

    int shotsHit;
    int nHitsModifier = getClusterModifiers(true);

    if (allShotsHit()) {
      shotsHit = wtype.getRackSize();
      if (game.getOptions().booleanOption(OptionsConstants.ADVCOMBAT_TACOPS_RANGE)
          && (nRange > wtype.getRanges(weapon)[RangeType.RANGE_LONG])) {
        shotsHit = (int) Math.ceil(shotsHit * .75);
      }
      if (game.getOptions().booleanOption(OptionsConstants.ADVCOMBAT_TACOPS_LOS_RANGE)
          && (nRange > wtype.getRanges(weapon)[RangeType.RANGE_EXTREME])) {
        shotsHit = (int) Math.ceil(shotsHit * .5);
      }
    } else {
      // flat modifier of -1, because of prototype
      nHitsModifier -= 1;

      shotsHit =
          Compute.missilesHit(
              wtype.getRackSize(), nHitsModifier, game.getPlanetaryConditions().hasEMI());
    }

    Report r = new Report(3325);
    r.subject = subjectId;
    r.add(shotsHit);
    r.add(sSalvoType);
    r.add(toHit.getTableDesc());
    r.newlines = 0;
    vPhaseReport.addElement(r);
    if (nHitsModifier != 0) {
      if (nHitsModifier > 0) {
        r = new Report(3340);
      } else {
        r = new Report(3341);
      }
      r.subject = subjectId;
      r.add(nHitsModifier);
      r.newlines = 0;
      vPhaseReport.addElement(r);
    }
    r = new Report(3345);
    r.subject = subjectId;
    vPhaseReport.addElement(r);
    bSalvo = true;
    return shotsHit;
  }
 @Override
 protected void handleIgnitionDamage(Vector<Report> vPhaseReport, Building bldg, int hits) {
   if (!bSalvo) {
     // hits!
     Report r = new Report(2270);
     r.subject = subjectId;
     r.newlines = 0;
     vPhaseReport.addElement(r);
   }
   TargetRoll tn = new TargetRoll(wtype.getFireTN(), wtype.getName());
   if (tn.getValue() != TargetRoll.IMPOSSIBLE) {
     Report.addNewline(vPhaseReport);
     server.tryIgniteHex(target.getPosition(), subjectId, true, false, tn, true, -1, vPhaseReport);
   }
 }
 /*
  * (non-Javadoc)
  *
  * @see megamek.common.weapons.WeaponHandler#doChecks(java.util.Vector)
  */
 @Override
 protected boolean doChecks(Vector<Report> vPhaseReport) {
   if ((roll == 2) && (howManyShots == 2) && !(ae instanceof Infantry)) {
     Report r = new Report();
     r.subject = subjectId;
     weapon.setJammed(true);
     isJammed = true;
     if ((wtype.getAmmoType() == AmmoType.T_AC_ULTRA)
         || (wtype.getAmmoType() == AmmoType.T_AC_ULTRA_THB)) {
       r.messageId = 3160;
     } else {
       r.messageId = 3170;
     }
     vPhaseReport.addElement(r);
   }
   return false;
 }
  /*
   * (non-Javadoc)
   *
   * @see megamek.common.weapons.WeaponHandler#calcHits(java.util.Vector)
   */
  @Override
  protected int calcHits(Vector<Report> vPhaseReport) {
    // conventional infantry gets hit in one lump
    // BAs can't mount UACS/RACs
    if ((target instanceof Infantry) && !(target instanceof BattleArmor)) {
      return 1;
    }

    bSalvo = true;

    if (howManyShots == 1 || twoRollsUltra) {
      return 1;
    }

    int shotsHit;
    int nMod = getClusterModifiers(true);

    shotsHit = allShotsHit() ? howManyShots : Compute.missilesHit(howManyShots, nMod);

    // report number of shots that hit only when weapon doesn't jam
    if (!weapon.isJammed()) {
      Report r = new Report(3325);
      r.subject = subjectId;
      r.add(shotsHit);
      r.add(sSalvoType);
      r.add(toHit.getTableDesc());
      r.newlines = 0;
      vPhaseReport.addElement(r);
      if (nMod != 0) {
        if (nMod > 0) {
          r = new Report(3340);
        } else {
          r = new Report(3341);
        }
        r.subject = subjectId;
        r.add(nMod);
        r.newlines = 0;
        vPhaseReport.addElement(r);
      }
      r = new Report(3345);
      r.subject = subjectId;
      vPhaseReport.addElement(r);
    }
    return shotsHit;
  }
  @Override
  protected void handleClearDamage(Vector<Report> vPhaseReport, Building bldg, int nDamage) {
    if (!bSalvo) {
      // hits!
      Report r = new Report(2270);
      r.subject = subjectId;
      vPhaseReport.addElement(r);
    }

    nDamage *= 2; // Plasma weapons deal double damage to woods.

    // report that damage was "applied" to terrain
    Report r = new Report(3385);
    r.indent(2);
    r.subject = subjectId;
    r.add(nDamage);
    vPhaseReport.addElement(r);

    // Any clear attempt can result in accidental ignition, even
    // weapons that can't normally start fires. that's weird.
    // Buildings can't be accidentally ignited.
    // TODO: change this for TacOps - now you roll another 2d6 first and on
    // a 5 or less
    // you do a normal ignition as though for intentional fires
    if ((bldg != null)
        && server.tryIgniteHex(
            target.getPosition(),
            subjectId,
            true,
            false,
            new TargetRoll(wtype.getFireTN(), wtype.getName()),
            5,
            vPhaseReport)) {
      return;
    }
    Vector<Report> clearReports = server.tryClearHex(target.getPosition(), nDamage, subjectId);
    if (clearReports.size() > 0) {
      vPhaseReport.lastElement().newlines = 0;
    }
    vPhaseReport.addAll(clearReports);
    return;
  }
  /**
   * handle this weapons firing
   *
   * @return a <code>boolean</code> value indicating wether this should be kept or not
   */
  @Override
  public boolean handle(IGame.Phase phase, Vector<Report> vPhaseReport) {
    if (!this.cares(phase)) {
      return true;
    }

    // Report weapon attack and its to-hit value.
    Report r = new Report(3115);
    r.indent();
    r.newlines = 0;
    r.subject = subjectId;
    r.add(wtype.getName());
    r.messageId = 3120;
    r.add(target.getDisplayName(), true);
    vPhaseReport.addElement(r);
    if (toHit.getValue() == TargetRoll.IMPOSSIBLE) {
      r = new Report(3135);
      r.subject = subjectId;
      r.add(toHit.getDesc());
      vPhaseReport.addElement(r);
      return false;
    } else if (toHit.getValue() == TargetRoll.AUTOMATIC_FAIL) {
      r = new Report(3140);
      r.newlines = 0;
      r.subject = subjectId;
      r.add(toHit.getDesc());
      vPhaseReport.addElement(r);
    } else if (toHit.getValue() == TargetRoll.AUTOMATIC_SUCCESS) {
      r = new Report(3145);
      r.newlines = 0;
      r.subject = subjectId;
      r.add(toHit.getDesc());
      vPhaseReport.addElement(r);
    }

    addHeat();

    // deliver screen
    Coords coords = target.getPosition();
    server.deliverScreen(coords, vPhaseReport);

    // damage any entities in the hex
    for (Entity entity : game.getEntitiesVector(coords)) {
      // if fighter squadron all fighters are damaged
      if (entity instanceof FighterSquadron) {
        for (Entity fighter : ((FighterSquadron) entity).getFighters()) {
          ToHitData squadronToHit = new ToHitData();
          squadronToHit.setHitTable(ToHitData.HIT_NORMAL);
          HitData hit = fighter.rollHitLocation(squadronToHit.getHitTable(), ToHitData.SIDE_FRONT);
          hit.setCapital(false);
          vPhaseReport.addAll(server.damageEntity(fighter, hit, attackValue));
          server.creditKill(fighter, ae);
        }
      } else {
        ToHitData hexToHit = new ToHitData();
        hexToHit.setHitTable(ToHitData.HIT_NORMAL);
        HitData hit = entity.rollHitLocation(hexToHit.getHitTable(), ToHitData.SIDE_FRONT);
        hit.setCapital(false);
        vPhaseReport.addAll(server.damageEntity(entity, hit, attackValue));
        server.creditKill(entity, ae);
      }
    }
    return false;
  }
 /*
  * (non-Javadoc)
  *
  * @see
  * megamek.common.weapons.WeaponHandler#specialResolution(java.util.Vector,
  * megamek.common.Entity, boolean)
  */
 @Override
 protected boolean specialResolution(Vector<Report> vPhaseReport, Entity entityTarget) {
   boolean done = false;
   if (bMissed) {
     return done;
   }
   Report r = new Report(3700);
   int taserRoll = Compute.d6(2);
   r.add(taserRoll);
   r.newlines = 0;
   vPhaseReport.add(r);
   if (entityTarget.getWeight() > 100) {
     return done;
   }
   if (entityTarget instanceof BattleArmor) {
     r = new Report(3706);
     r.addDesc(entityTarget);
     // shut down for rest of scenario, so we actually kill it
     // TODO: fix for salvage purposes
     r.add(entityTarget.getLocationAbbr(hit));
     vPhaseReport.add(r);
     entityTarget.destroyLocation(hit.getLocation());
     // Check to see if the squad has been eliminated
     if (entityTarget.getTransferLocation(hit).getLocation() == Entity.LOC_DESTROYED) {
       vPhaseReport.addAll(server.destroyEntity(entityTarget, "all troopers eliminated", false));
     }
     done = true;
   } else if (entityTarget instanceof Mech) {
     if (((Mech) entityTarget).isIndustrial()) {
       if (taserRoll >= 8) {
         r = new Report(3705);
         r.addDesc(entityTarget);
         r.add(4);
         entityTarget.taserShutdown(4, false);
       } else {
         // suffer +2 to piloting and gunnery for 4 rounds
         r = new Report(3710);
         r.addDesc(entityTarget);
         r.add(2);
         r.add(4);
         entityTarget.setTaserInterference(2, 4, true);
       }
     } else {
       if (taserRoll >= 11) {
         r = new Report(3705);
         r.addDesc(entityTarget);
         r.add(3);
         vPhaseReport.add(r);
         entityTarget.taserShutdown(3, false);
       } else {
         r = new Report(3710);
         r.addDesc(entityTarget);
         r.add(2);
         r.add(3);
         vPhaseReport.add(r);
         entityTarget.setTaserInterference(2, 3, true);
       }
     }
   } else if ((entityTarget instanceof Protomech)
       || (entityTarget instanceof Tank)
       || (entityTarget instanceof Aero)) {
     if (taserRoll >= 8) {
       r = new Report(3705);
       r.addDesc(entityTarget);
       r.add(4);
       vPhaseReport.add(r);
       entityTarget.taserShutdown(4, false);
     } else {
       r = new Report(3710);
       r.addDesc(entityTarget);
       r.add(2);
       r.add(4);
       vPhaseReport.add(r);
       entityTarget.setTaserInterference(2, 4, false);
     }
   }
   return done;
 }
 /*
  * (non-Javadoc)
  *
  * @see
  * megamek.common.weapons.WeaponHandler#handleEntityDamage(megamek.common
  * .Entity, java.util.Vector, megamek.common.Building, int, int, int, int)
  */
 @Override
 protected void handleEntityDamage(
     Entity entityTarget,
     Vector<Report> vPhaseReport,
     Building bldg,
     int hits,
     int nCluster,
     int bldgAbsorbs) {
   super.handleEntityDamage(entityTarget, vPhaseReport, bldg, hits, nCluster, bldgAbsorbs);
   if (!missed && ((entityTarget instanceof Mech) || (entityTarget instanceof Aero))) {
     Report r = new Report(3400);
     r.subject = subjectId;
     r.indent(2);
     int extraHeat = 0;
     // if this is a fighter squadron, we need to account for number of
     // weapons
     // should default to one for non squadrons
     for (int i = 0; i < nweaponsHit; i++) {
       extraHeat += Compute.d6();
     }
     if (entityTarget.getArmor(hit) > 0
         && (entityTarget.getArmorType(hit.getLocation()) == EquipmentType.T_ARMOR_REFLECTIVE)) {
       entityTarget.heatFromExternal += Math.max(1, extraHeat / 2);
       r.add(Math.max(1, extraHeat / 2));
       r.choose(true);
       r.messageId = 3406;
       r.add(extraHeat);
       r.add(EquipmentType.armorNames[entityTarget.getArmorType(hit.getLocation())]);
     } else if (entityTarget.getArmor(hit) > 0
         && (entityTarget.getArmorType(hit.getLocation())
             == EquipmentType.T_ARMOR_HEAT_DISSIPATING)) {
       entityTarget.heatFromExternal += extraHeat / 2;
       r.add(extraHeat / 2);
       r.choose(true);
       r.messageId = 3406;
       r.add(extraHeat);
       r.add(EquipmentType.armorNames[entityTarget.getArmorType(hit.getLocation())]);
     } else {
       entityTarget.heatFromExternal += extraHeat;
       r.add(extraHeat);
       r.choose(true);
     }
     vPhaseReport.addElement(r);
   }
 }