public static int GetAverageClusterHits(ifWeapon w, int manualmodifier) {
   if (!w.IsCluster()) {
     return 1;
   }
   if (w.IsStreak()) {
     return w.ClusterSize();
   }
   int size = w.ClusterSize() - 1; // subtract one for array indexing
   int roll = 5 + manualmodifier; // subtracting 2 because we're indexing an array
   if (w instanceof RangedWeapon) {
     if (((RangedWeapon) w).IsUsingFCS()) {
       roll += ((RangedWeapon) w).GetFCS().GetClusterTableBonus();
     }
   }
   if (roll > 10) {
     roll = 10;
   }
   if (roll < 0) {
     roll = 0;
   }
   if (size > 30) {
     size = 30;
   }
   if (size < 0) {
     return 0;
   }
   return ClusterTable[roll][size];
 }
 /**
  * Returns the average damage of the given weapon at the given range using the ammunition
  * specified. This routine is provided to support LB-X ACs, ATMs, and MMLs. We say "average" here
  * as some weapons use a clustered system and may only do partial damage, otherwise we return the
  * maximum damage. If the range specified is less than 0 or greater than the maximum range of the
  * weapon we return -1.
  *
  * @param w The weapon in question.
  * @param a The ammunition that the weapon will use.
  * @param range The range that the weapon will be hitting a target at.
  * @return The average damage of the weapon at that range.
  */
 public static int GetAverageDamageAtRange(ifWeapon w, Ammunition a, int range) {
   if (a.IsCluster()) {
     boolean Streak = w.IsStreak();
     boolean Ultra = w.IsUltra();
     boolean Rotary = w.IsRotary();
     boolean Ballistic = false;
     if (w.GetWeaponClass() == ifWeapon.W_BALLISTIC && a.IsCluster()) {
       Ballistic = true;
     }
     if (range > a.GetLongRange()) {
       return 0;
     } else if (range > a.GetMediumRange()) {
       if (Streak) {
         return a.GetDamageLong() * a.ClusterSize();
       } else if (Ultra) {
         // don't even bother with the cluster table, it'll always
         // return 1 in this case.
         return a.GetDamageLong();
       } else if (Ballistic & !Rotary) {
         // this covers LB-X cannons in general
         return GetAverageClusterHits(w, w.ClusterModLong());
       } else {
         return a.GetDamageLong() * GetAverageClusterHits(w, w.ClusterModLong());
       }
     } else if (range > a.GetShortRange()) {
       if (Streak) {
         return a.GetDamageMedium() * a.ClusterSize();
       } else if (Ultra) {
         return a.GetDamageMedium();
       } else if (Ballistic & !Rotary) {
         return GetAverageClusterHits(w, w.ClusterModMedium());
       } else {
         return a.GetDamageMedium() * GetAverageClusterHits(w, w.ClusterModMedium());
       }
     } else {
       if (Streak) {
         return a.GetDamageShort() * a.ClusterSize();
       } else if (Ultra) {
         return a.GetDamageShort();
       } else if (Ballistic & !Rotary) {
         return GetAverageClusterHits(w, w.ClusterModShort());
       } else {
         return a.GetDamageShort() * GetAverageClusterHits(w, w.ClusterModShort());
       }
     }
   } else {
     if (range > a.GetLongRange()) {
       return 0;
     } else if (range > a.GetMediumRange()) {
       return a.GetDamageLong();
     } else if (range > a.GetShortRange()) {
       return a.GetDamageMedium();
     } else {
       return a.GetDamageShort();
     }
   }
 }
 /**
  * Returns the to-hit modifier of the weapon at the given range. This is only weapon-specific, it
  * does not account for target or firer movement, or other modifiers. If the weapon cannot hit at
  * the given range, we return 12.
  *
  * @param w The weapon in question.
  * @param range The range that the weapon will be hitting a target at.
  * @return The to-hit modifier for the weapon at the given range.
  */
 public static int GetToHitAtRange(ifWeapon w, int range) {
   if (range > w.GetRangeLong()) {
     return 12;
   } else if (range > w.GetRangeMedium()) {
     return 4 + w.GetToHitLong();
   } else if (range > w.GetRangeShort()) {
     return 2 + w.GetToHitMedium();
   } else {
     if (range <= w.GetRangeMin() && w.GetRangeMin() > 0) {
       int min = w.GetRangeMin() - range + 1;
       return 0 + min + w.GetToHitShort();
     } else {
       return 0 + w.GetToHitShort();
     }
   }
 }
  private void GetWeaponData() {
    ArrayList v = CurMech.GetLoadout().GetNonCore();
    ArrayList<ifWeapon> wep = new ArrayList<ifWeapon>();
    ArrayList<Ammunition> ammo = new ArrayList<Ammunition>();
    ArrayList<WeaponInfo> temp = new ArrayList<WeaponInfo>();
    int cols = 0;
    for (int i = 0; i < v.size(); i++) {
      if (v.get(i) instanceof ifWeapon) {
        ifWeapon w = (ifWeapon) v.get(i);
        // do we already have a weapon of this name in the ArrayList?
        boolean add = true;
        for (int x = 0; x < wep.size(); x++) {
          if (wep.get(x).LookupName().equals(w.LookupName())) {
            add = false;
          }
        }
        if (add) {
          wep.add(w);
          if (w.GetRangeLong() > cols) {
            cols = w.GetRangeLong();
          }
        }
      } else if (v.get(i) instanceof Ammunition) {
        Ammunition a = (Ammunition) v.get(i);
        // do we already have an ammo of this name in the ArrayList?
        boolean add = true;
        for (int x = 0; x < ammo.size(); x++) {
          if (ammo.get(x).LookupName().equals(a.LookupName())) {
            add = false;
          }
        }
        if (add) {
          ammo.add(a);
          if (a.GetLongRange() > cols) {
            cols = a.GetLongRange();
          }
        }
      }
    }

    // construct the data ArrayList
    for (int i = 0; i < wep.size(); i++) {
      ifWeapon w = wep.get(i);
      if (w.HasAmmo()) {
        boolean added = false;
        // search for other ammunition for this weapon.
        for (int x = ammo.size() - 1; x >= 0; x--) {
          Ammunition a = ammo.get(x);
          if (w.GetAmmoIndex() == a.GetAmmoIndex()) {
            temp.add(new WeaponInfo(w, a));
            ammo.remove(a);
            added = true;
          }
        }
        if (!added) {
          // add the weapon in by itself
          temp.add(new WeaponInfo(w));
        }
      } else {
        temp.add(new WeaponInfo(w));
      }
    }

    // sort the weapon info by range
    SortWeapons(temp);

    // turn the temporary ArrayList into an array
    cols += 1;
    data = new String[temp.size() * 2][cols];
    for (int i = 0; i < temp.size(); i++) {
      WeaponInfo w = temp.get(i);
      for (int x = 0; x < cols; x++) {
        if (x == 0) {
          data[i * 2][x] = w.GetName();
          data[i * 2 + 1][x] = "";
        } else {
          int tohit = w.GetToHit(x);
          if (CurMech.UsingTC()) {
            if (tohit != 12 && w.CanUseTC()) {
              tohit -= 1;
            }
          }
          if (tohit >= 0) {
            data[i * 2][x] = "+" + tohit;
          } else {
            data[i * 2][x] = "" + tohit;
          }
          data[i * 2 + 1][x] = "" + w.GetDamage(x);
        }
      }
    }
  }
 public boolean CanUseTC() {
   return wep.IsTCCapable();
 }
 public int GetLongRange() {
   if (HasAmmo()) {
     return ammo.GetLongRange();
   }
   return wep.GetRangeLong();
 }
 public String GetName() {
   if (HasAmmo()) {
     return ammo.CritName().replace("@", "");
   }
   return wep.CritName();
 }