/*
* Copyright (C) 2012 Sebastian Straub <sebastian-straub@gmx.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.nx42.wotcrawler.ext;
import java.net.MalformedURLException;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.List;
import java.util.Locale;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import de.nx42.wotcrawler.db.BaseProperties.Development;
import de.nx42.wotcrawler.db.TanksDB;
import de.nx42.wotcrawler.db.module.Engine;
import de.nx42.wotcrawler.db.module.Gun;
import de.nx42.wotcrawler.db.module.Module;
import de.nx42.wotcrawler.db.module.Radio;
import de.nx42.wotcrawler.db.module.Suspension;
import de.nx42.wotcrawler.db.module.Turret;
import de.nx42.wotcrawler.db.tank.Equipment;
import de.nx42.wotcrawler.db.tank.Tank;
import de.nx42.wotcrawler.db.tank.Tank.TankType;
import de.nx42.wotcrawler.db.tank.TankRef;
import de.nx42.wotcrawler.xml.Crawler;
/**
* This enum is real sugar: It contains all attributes that can be extracted
* from the TanksDB. Furthermore, for every Field methods are provided to
* access the value of this field for a specified tank object.
*
* This means that you can create a list of Fields and access the values
* of these fields for every tank, just by looping over it. For examples,
* see the FieldDef and Transformer class.
*
* @author Sebastian Straub <sebastian-straub@gmx.net>
*/
public enum Field {
//<editor-fold desc="all fields (enum)">
// -- tank --
//<editor-fold defaultstate="collapsed" desc="tank base details">
/** The minimum battle tier the tank (usually) participates in */
T_BattleTier_Min {
@Override
public String get(Tank t, Development dev) {
return Byte.toString(t.battleTierMin);
}
},
/** The maximum battle tier the tank (usually) participates in */
T_BattleTier_Max {
@Override
public String get(Tank t, Development dev) {
return Byte.toString(t.battleTierMax);
}
},
/** A list of tanks this tank leads to in the tech tree */
T_Children {
@Override
public String get(Tank t, Development dev) {
return (t.children == null) ? na : buildTankRefList(t.children, t.name, LinkType.INTERNAL);
}
},
/** The cost of this object (currency in separate field) */
T_Cost {
@Override
public String get(Tank t, Development dev) {
return Integer.toString(t.cost);
}
},
/** The number of crew members */
T_CrewMembers {
@Override
public String get(Tank t, Development dev) {
return Integer.toString(t.crewMembers);
}
},
/** The currency this tank is paid for with */
T_Currency {
@Override
public String get(Tank t, Development dev) {
return t.currency.toString();
}
},
/** Indicates, if this tank is only accessible as special gift */
T_Gift {
@Override
public String get(Tank t, Development dev) {
return t.gift ? "Yes" : "No";
}
},
/** Max. rotation of gun / turret to the left (deg) */
T_GunArc_Left {
@Override
public String get(Tank t, Development dev) {
return df.format(t.gunArcLeft);
}
},
/** Max. rotation of the gun to the right (deg).
Note that 360° means the tower can rotate infinitely */
T_GunArc_Right {
@Override
public String get(Tank t, Development dev) {
return df.format(t.gunArcRight);
}
},
/** Hull armor (mm) - Front */
T_Hull_Front {
@Override
public String get(Tank t, Development dev) {
return df.format(t.hullFront);
}
},
/** Hull armor (mm) - Side */
T_Hull_Side {
@Override
public String get(Tank t, Development dev) {
return df.format(t.hullSide);
}
},
/** Hull armor (mm) - Rear */
T_Hull_Rear {
@Override
public String get(Tank t, Development dev) {
return df.format(t.hullRear);
}
},
/** The ID of this tank (unique identifier, used to maintain references in the xml database) */
T_ID {
@Override
public String get(Tank t, Development dev) {
return t.id;
}
},
/** The name of this tank */
T_Name {
@Override
public String get(Tank t, Development dev) {
try {
return String.format("<a href=\"%s\">%s</a>", Crawler.buildWikiLink(t.wikiURL).toString(), t.name);
} catch (MalformedURLException ex) {
log.warn("The Wikilink to this tank is invalid, returning just the name...", ex);
return t.name;
}
}
},
/** The Nation this tank belongs to */
T_Nation {
@Override
public String get(Tank t, Development dev) {
return t.nation.toString();
}
},
/** A list of tanks that lead to this tank in the tech tree (only empty for tier 1 tanks) */
T_Parents {
@Override
public String get(Tank t, Development dev) {
return (t.parents == null) ? na : buildTankRefList(t.parents, t.name, LinkType.INTERNAL);
}
},
/** The tier / level of this tank */
T_Tier {
@Override
public String get(Tank t, Development dev) {
return Byte.toString(t.tier);
}
},
/** Maximum speed (km/h) on even ground */
T_TopSpeed {
@Override
public String get(Tank t, Development dev) {
return df.format(t.speed);
}
},
/** The type of the tank: Light/Medium/Heavy Tank, Tank Destroyer or Artillery (SPG) */
T_Type {
@Override
public String get(Tank t, Development dev) {
return t.type.toString();
}
},
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="tank equipment (stock/top)">
/** Indicates, if this tank's attributes are top or stock values */
TE_Development {
@Override
public String get(Tank t, Development dev) {
return dev.toShortString();
}
},
/** Minimum gun elevation (deg) = Lowest angle the gun can be positioned */
TE_Elevation_Low {
@Override
public String get(Tank t, Development dev) {
return df.format(getEquipment(t, dev).gunElevationLow);
}
},
/** Maximum gun elevation (deg) = Highest angle the gun can be positioned */
TE_Elevation_High {
@Override
public String get(Tank t, Development dev) {
return df.format(getEquipment(t, dev).gunElevationHigh);
}
},
/** Hitpoints */
TE_Hitpoints {
@Override
public String get(Tank t, Development dev) {
return Integer.toString(getEquipment(t, dev).hitpoints);
}
},
/** The view range of the tank (m) */
TE_ViewRange {
@Override
public String get(Tank t, Development dev) {
return df.format(getEquipment(t, dev).viewRange);
}
},
/** Current weight (tons) */
TE_Weight {
@Override
public String get(Tank t, Development dev) {
return df.format(getEquipment(t, dev).weight);
}
},
/** Maximum load that can be carried (tons) */
TE_WeightLimit {
@Override
public String get(Tank t, Development dev) {
return df.format(getEquipment(t, dev).weightLimit);
}
},
//</editor-fold>
// -- modules --
//<editor-fold defaultstate="collapsed" desc="engine">
/** all tanks that are compatible with this engine */
ME_Compatibility {
@Override
public String get(Tank t, Development dev) {
Engine e = ModuleMap.getModuleByDev(Engine.class, t, dev);
return (e == null || e.compatibility == null) ? na : buildTankRefList(e.compatibility, t.name, LinkType.INTERNAL);
}
@Override
public String get(Module m) {
Engine e = (Engine) m;
return (e == null || e.compatibility == null) ? na : buildTankRefList(e.compatibility, "engine", LinkType.INTERNAL);
}
},
/** The cost of this engine (currency in separate field) */
ME_Cost {
@Override
public String get(Tank t, Development dev) {
Engine e = ModuleMap.getModuleByDev(Engine.class, t, dev);
return (e == null) ? na : Integer.toString(e.cost);
}
@Override
public String get(Module m) {
Engine e = (Engine) m;
return (e == null) ? na : Integer.toString(e.cost);
}
},
/** The currency this engine is paid for with */
ME_Currency {
@Override
public String get(Tank t, Development dev) {
Engine e = ModuleMap.getModuleByDev(Engine.class, t, dev);
return (e == null || e.currency == null) ? na : e.currency.toString();
}
@Override
public String get(Module m) {
Engine e = (Engine) m;
return (e == null || e.currency == null) ? na : e.currency.toString();
}
},
/** The name of this engine */
ME_Name {
@Override
public String get(Tank t, Development dev) {
Engine e = ModuleMap.getModuleByDev(Engine.class, t, dev);
return (e == null) ? na : e.name;
}
@Override
public String get(Module m) {
Engine e = (Engine) m;
return (e == null) ? na : e.name;
}
},
/** The Nation this engine belongs to */
ME_Nation {
@Override
public String get(Tank t, Development dev) {
Engine e = ModuleMap.getModuleByDev(Engine.class, t, dev);
return (e == null || e.nation == null) ? na : e.nation.toString();
}
@Override
public String get(Module m) {
Engine e = (Engine) m;
return (e == null || e.nation == null) ? na : e.nation.toString();
}
},
/** The tier / level of this engine */
ME_Tier {
@Override
public String get(Tank t, Development dev) {
Engine e = ModuleMap.getModuleByDev(Engine.class, t, dev);
return (e == null) ? na : Byte.toString(e.tier);
}
@Override
public String get(Module m) {
Engine e = (Engine) m;
return (e == null) ? na : Byte.toString(e.tier);
}
},
/** the weight of the module */
ME_Weight {
@Override
public String get(Tank t, Development dev) {
Engine e = ModuleMap.getModuleByDev(Engine.class, t, dev);
return (e == null) ? na : df.format(e.weight);
}
@Override
public String get(Module m) {
Engine e = (Engine) m;
return (e == null) ? na : df.format(e.weight);
}
},
/** Chance that the engine will catch fire when hit (%) */
ME_Firechance {
@Override
public String get(Tank t, Development dev) {
Engine e = ModuleMap.getModuleByDev(Engine.class, t, dev);
return (e == null) ? na : df.format(e.firechance);
}
@Override
public String get(Module m) {
Engine e = (Engine) m;
return (e == null) ? na : df.format(e.firechance);
}
},
/** Type of gas needed by the engine */
ME_Gas {
@Override
public String get(Tank t, Development dev) {
Engine e = ModuleMap.getModuleByDev(Engine.class, t, dev);
return (e == null || e.gas == null) ? na : e.gas.toString();
}
@Override
public String get(Module m) {
Engine e = (Engine) m;
return (e == null || e.gas == null) ? na : e.gas.toString();
}
},
/** Engine power (HP) */
ME_Power {
@Override
public String get(Tank t, Development dev) {
Engine e = ModuleMap.getModuleByDev(Engine.class, t, dev);
return (e == null) ? na : Integer.toString(e.power);
}
@Override
public String get(Module m) {
Engine e = (Engine) m;
return (e == null) ? na : Integer.toString(e.power);
}
},
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="gun">
/** all tanks that are compatible with this gun */
MG_Compatibility {
@Override
public String get(Tank t, Development dev) {
Gun g = ModuleMap.getModuleByDev(Gun.class, t, dev);
return (g == null || g.compatibility == null) ? na : buildTankRefList(g.compatibility, t.name, LinkType.INTERNAL);
}
@Override
public String get(Module m) {
Gun g = (Gun) m;
return (g == null || g.compatibility == null) ? na : buildTankRefList(g.compatibility, "gun", LinkType.INTERNAL);
}
},
/** The cost of this gun (currency in separate field) */
MG_Cost {
@Override
public String get(Tank t, Development dev) {
Gun g = ModuleMap.getModuleByDev(Gun.class, t, dev);
return (g == null) ? na : Integer.toString(g.cost);
}
@Override
public String get(Module m) {
Gun g = (Gun) m;
return (g == null) ? na : Integer.toString(g.cost);
}
},
/** The currency this gun is paid for with */
MG_Currency {
@Override
public String get(Tank t, Development dev) {
Gun g = ModuleMap.getModuleByDev(Gun.class, t, dev);
return (g == null || g.currency == null) ? na : g.currency.toString();
}
@Override
public String get(Module m) {
Gun g = (Gun) m;
return (g == null || g.currency == null) ? na : g.currency.toString();
}
},
/** The name of this gun */
MG_Name {
@Override
public String get(Tank t, Development dev) {
Gun g = ModuleMap.getModuleByDev(Gun.class, t, dev);
return (g == null) ? na : g.name;
}
@Override
public String get(Module m) {
Gun g = (Gun) m;
return (g == null) ? na : g.name;
}
},
/** The Nation this gun belongs to */
MG_Nation {
@Override
public String get(Tank t, Development dev) {
Gun g = ModuleMap.getModuleByDev(Gun.class, t, dev);
return (g == null || g.nation == null) ? na : g.nation.toString();
}
@Override
public String get(Module m) {
Gun g = (Gun) m;
return (g == null || g.nation == null) ? na : g.nation.toString();
}
},
/** The tier / level of this gun */
MG_Tier {
@Override
public String get(Tank t, Development dev) {
Gun g = ModuleMap.getModuleByDev(Gun.class, t, dev);
return (g == null) ? na : Byte.toString(g.tier);
}
@Override
public String get(Module m) {
Gun g = (Gun) m;
return (g == null) ? na : Byte.toString(g.tier);
}
},
/** the weight of the module */
MG_Weight {
@Override
public String get(Tank t, Development dev) {
Gun g = ModuleMap.getModuleByDev(Gun.class, t, dev);
return (g == null) ? na : df.format(g.weight);
}
@Override
public String get(Module m) {
Gun g = (Gun) m;
return (g == null) ? na : df.format(g.weight);
}
},
/** Accuracy (diameter in meters at 100m distance - minimum) */
MG_Accuracy_Min {
@Override
public String get(Tank t, Development dev) {
Gun g = ModuleMap.getModuleByDev(Gun.class, t, dev);
return (g == null) ? na : dfp.format(g.accuracyMin);
}
@Override
public String get(Module m) {
Gun g = (Gun) m;
return (g == null) ? na : dfp.format(g.accuracyMin);
}
},
/** Accuracy (diameter in meters at 100m distance - maximum) */
MG_Accuracy_Max {
@Override
public String get(Tank t, Development dev) {
Gun g = ModuleMap.getModuleByDev(Gun.class, t, dev);
return (g == null) ? na : dfp.format(g.accuracyMax);
}
@Override
public String get(Module m) {
Gun g = (Gun) m;
return (g == null) ? na : dfp.format(g.accuracyMax);
}
},
/** Aim Time (seconds - maximum) */
MG_AimTime_Min {
@Override
public String get(Tank t, Development dev) {
Gun g = ModuleMap.getModuleByDev(Gun.class, t, dev);
return (g == null) ? na : dfp.format(g.aimTimeMin);
}
@Override
public String get(Module m) {
Gun g = (Gun) m;
return (g == null) ? na : dfp.format(g.aimTimeMin);
}
},
/** Aim Time (seconds - maximum) */
MG_AimTime_Max {
@Override
public String get(Tank t, Development dev) {
Gun g = ModuleMap.getModuleByDev(Gun.class, t, dev);
return (g == null) ? na : dfp.format(g.aimTimeMax);
}
@Override
public String get(Module m) {
Gun g = (Gun) m;
return (g == null) ? na : dfp.format(g.aimTimeMax);
}
},
/** Ammo capacity (shells - minimum) */
MG_AmmoCapacity_Min {
@Override
public String get(Tank t, Development dev) {
Gun g = ModuleMap.getModuleByDev(Gun.class, t, dev);
return (g == null) ? na : Integer.toString(g.ammoCapacityMin);
}
@Override
public String get(Module m) {
Gun g = (Gun) m;
return (g == null) ? na : Integer.toString(g.ammoCapacityMin);
}
},
/** Ammo capacity (shells - maximum) */
MG_AmmoCapacity_Max {
@Override
public String get(Tank t, Development dev) {
Gun g = ModuleMap.getModuleByDev(Gun.class, t, dev);
return (g == null) ? na : Integer.toString(g.ammoCapacityMax);
}
@Override
public String get(Module m) {
Gun g = (Gun) m;
return (g == null) ? na : Integer.toString(g.ammoCapacityMax);
}
},
/** Gun Damage (AP = Armor Piercing) */
MG_Dmg_AP {
@Override
public String get(Tank t, Development dev) {
Gun g = ModuleMap.getModuleByDev(Gun.class, t, dev);
return (g == null) ? na : df.format(g.dmgAP);
}
@Override
public String get(Module m) {
Gun g = (Gun) m;
return (g == null) ? na : df.format(g.dmgAP);
}
},
/** Gun Damage (APCR = Armor Piercing Composite Rigid) */
MG_Dmg_APCR {
@Override
public String get(Tank t, Development dev) {
Gun g = ModuleMap.getModuleByDev(Gun.class, t, dev);
return (g == null) ? na : df.format(g.dmgAPCR);
}
@Override
public String get(Module m) {
Gun g = (Gun) m;
return (g == null) ? na : df.format(g.dmgAPCR);
}
},
/** Gun Damage (HE = High Explosive) */
MG_Dmg_HE {
@Override
public String get(Tank t, Development dev) {
Gun g = ModuleMap.getModuleByDev(Gun.class, t, dev);
return (g == null) ? na : df.format(g.dmgHE);
}
@Override
public String get(Module m) {
Gun g = (Gun) m;
return (g == null) ? na : df.format(g.dmgHE);
}
},
/** Gun Damage (HEAT = High Explosive Anti-Tank) */
MG_Dmg_HEAT {
@Override
public String get(Tank t, Development dev) {
Gun g = ModuleMap.getModuleByDev(Gun.class, t, dev);
return (g == null) ? na : df.format(g.dmgHEAT);
}
@Override
public String get(Module m) {
Gun g = (Gun) m;
return (g == null) ? na : df.format(g.dmgHEAT);
}
},
/** Fire Rate (Shots per Minute - minimum) */
MG_FireRate_Min {
@Override
public String get(Tank t, Development dev) {
Gun g = ModuleMap.getModuleByDev(Gun.class, t, dev);
return (g == null) ? na : dfp.format(g.fireRateMin);
}
@Override
public String get(Module m) {
Gun g = (Gun) m;
return (g == null) ? na : dfp.format(g.fireRateMin);
}
},
/** Fire Rate (Shots per Minute - maximum) */
MG_FireRate_Max {
@Override
public String get(Tank t, Development dev) {
Gun g = ModuleMap.getModuleByDev(Gun.class, t, dev);
return (g == null) ? na : dfp.format(g.fireRateMax);
}
@Override
public String get(Module m) {
Gun g = (Gun) m;
return (g == null) ? na : dfp.format(g.fireRateMax);
}
},
/** Shell Penetration in mm (AP = Armor Piercing) */
MG_Penetration_AP {
@Override
public String get(Tank t, Development dev) {
Gun g = ModuleMap.getModuleByDev(Gun.class, t, dev);
return (g == null) ? na : Integer.toString(g.penAP);
}
@Override
public String get(Module m) {
Gun g = (Gun) m;
return (g == null) ? na : Integer.toString(g.penAP);
}
},
/** Shell Penetration in mm (APCR = Armor Piercing Composite Rigid) */
MG_Penetration_APCR {
@Override
public String get(Tank t, Development dev) {
Gun g = ModuleMap.getModuleByDev(Gun.class, t, dev);
return (g == null) ? na : Integer.toString(g.penAPCR);
}
@Override
public String get(Module m) {
Gun g = (Gun) m;
return (g == null) ? na : Integer.toString(g.penAPCR);
}
},
/** Shell Penetration in mm (HE = High Explosive) */
MG_Penetration_HE {
@Override
public String get(Tank t, Development dev) {
Gun g = ModuleMap.getModuleByDev(Gun.class, t, dev);
return (g == null) ? na : Integer.toString(g.penHE);
}
@Override
public String get(Module m) {
Gun g = (Gun) m;
return (g == null) ? na : Integer.toString(g.penHE);
}
},
/** Shell Penetration in mm (HEAT = High Explosive Anti-Tank) */
MG_Penetration_HEAT {
@Override
public String get(Tank t, Development dev) {
Gun g = ModuleMap.getModuleByDev(Gun.class, t, dev);
return (g == null) ? na : Integer.toString(g.penHEAT);
}
@Override
public String get(Module m) {
Gun g = (Gun) m;
return (g == null) ? na : Integer.toString(g.penHEAT);
}
},
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="radio">
/** all tanks that are compatible with this radio */
MR_Compatibility {
@Override
public String get(Tank t, Development dev) {
Radio r = ModuleMap.getModuleByDev(Radio.class, t, dev);
return (r == null || r.compatibility == null) ? na : buildTankRefList(r.compatibility, t.name, LinkType.INTERNAL);
}
@Override
public String get(Module m) {
Radio r = (Radio) m;
return (r == null || r.compatibility == null) ? na : buildTankRefList(r.compatibility, "radio", LinkType.INTERNAL);
}
},
/** The cost of this radio (currency in separate field) */
MR_Cost {
@Override
public String get(Tank t, Development dev) {
Radio r = ModuleMap.getModuleByDev(Radio.class, t, dev);
return (r == null) ? na : Integer.toString(r.cost);
}
@Override
public String get(Module m) {
Radio r = (Radio) m;
return (r == null) ? na : Integer.toString(r.cost);
}
},
/** The currency this radio is paid for with */
MR_Currency {
@Override
public String get(Tank t, Development dev) {
Radio r = ModuleMap.getModuleByDev(Radio.class, t, dev);
return (r == null || r.currency == null) ? na : r.currency.toString();
}
@Override
public String get(Module m) {
Radio r = (Radio) m;
return (r == null || r.currency == null) ? na : r.currency.toString();
}
},
/** The name of this radio */
MR_Name {
@Override
public String get(Tank t, Development dev) {
Radio r = ModuleMap.getModuleByDev(Radio.class, t, dev);
return (r == null) ? na : r.name;
}
@Override
public String get(Module m) {
Radio r = (Radio) m;
return (r == null) ? na : r.name;
}
},
/** The Nation this radio belongs to */
MR_Nation {
@Override
public String get(Tank t, Development dev) {
Radio r = ModuleMap.getModuleByDev(Radio.class, t, dev);
return (r == null || r.nation == null) ? na : r.nation.toString();
}
@Override
public String get(Module m) {
Radio r = (Radio) m;
return (r == null || r.nation == null) ? na : r.nation.toString();
}
},
/** The tier / level of this radio */
MR_Tier {
@Override
public String get(Tank t, Development dev) {
Radio r = ModuleMap.getModuleByDev(Radio.class, t, dev);
return (r == null) ? na : Byte.toString(r.tier);
}
@Override
public String get(Module m) {
Radio r = (Radio) m;
return (r == null) ? na : Byte.toString(r.tier);
}
},
/** the weight of the module */
MR_Weight {
@Override
public String get(Tank t, Development dev) {
Radio r = ModuleMap.getModuleByDev(Radio.class, t, dev);
return (r == null) ? na : df.format(r.weight);
}
@Override
public String get(Module m) {
Radio r = (Radio) m;
return (r == null) ? na : df.format(r.weight);
}
},
/** The radio transmission range (m) */
MR_Range {
@Override
public String get(Tank t, Development dev) {
Radio r = ModuleMap.getModuleByDev(Radio.class, t, dev);
return (r == null) ? na : Integer.toString(r.range);
}
@Override
public String get(Module m) {
Radio r = (Radio) m;
return (r == null) ? na : Integer.toString(r.range);
}
},
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="suspension">
/** all tanks that are compatible with this suspension */
MS_Compatibility {
@Override
public String get(Tank t, Development dev) {
Suspension s = ModuleMap.getModuleByDev(Suspension.class, t, dev);
return (s == null || s.compatibility == null) ? na : buildTankRefList(s.compatibility, t.name, LinkType.INTERNAL);
}
@Override
public String get(Module m) {
Suspension s = (Suspension) m;
return (s == null || s.compatibility == null) ? na : buildTankRefList(s.compatibility, "suspension", LinkType.INTERNAL);
}
},
/** The cost of this suspension (currency in separate field) */
MS_Cost {
@Override
public String get(Tank t, Development dev) {
Suspension s = ModuleMap.getModuleByDev(Suspension.class, t, dev);
return (s == null) ? na : Integer.toString(s.cost);
}
@Override
public String get(Module m) {
Suspension s = (Suspension) m;
return (s == null) ? na : Integer.toString(s.cost);
}
},
/** The currency this suspension is paid for with */
MS_Currency {
@Override
public String get(Tank t, Development dev) {
Suspension s = ModuleMap.getModuleByDev(Suspension.class, t, dev);
return (s == null || s.currency == null) ? na : s.currency.toString();
}
@Override
public String get(Module m) {
Suspension s = (Suspension) m;
return (s == null || s.currency == null) ? na : s.currency.toString();
}
},
/** The name of this suspension */
MS_Name {
@Override
public String get(Tank t, Development dev) {
Suspension s = ModuleMap.getModuleByDev(Suspension.class, t, dev);
return (s == null) ? na : s.name;
}
@Override
public String get(Module m) {
Suspension s = (Suspension) m;
return (s == null) ? na : s.name;
}
},
/** The Nation this suspension belongs to */
MS_Nation {
@Override
public String get(Tank t, Development dev) {
Suspension s = ModuleMap.getModuleByDev(Suspension.class, t, dev);
return (s == null || s.nation == null) ? na : s.nation.toString();
}
@Override
public String get(Module m) {
Suspension s = (Suspension) m;
return (s == null || s.nation == null) ? na : s.nation.toString();
}
},
/** The tier / level of this suspension */
MS_Tier {
@Override
public String get(Tank t, Development dev) {
Suspension s = ModuleMap.getModuleByDev(Suspension.class, t, dev);
return (s == null) ? na : Byte.toString(s.tier);
}
@Override
public String get(Module m) {
Suspension s = (Suspension) m;
return (s == null) ? na : Byte.toString(s.tier);
}
},
/** the weight of the module */
MS_Weight {
@Override
public String get(Tank t, Development dev) {
Suspension s = ModuleMap.getModuleByDev(Suspension.class, t, dev);
return (s == null) ? na : df.format(s.weight);
}
@Override
public String get(Module m) {
Suspension s = (Suspension) m;
return (s == null) ? na : df.format(s.weight);
}
},
/** Maximum load that can be carried (tons) */
MS_Load {
@Override
public String get(Tank t, Development dev) {
Suspension s = ModuleMap.getModuleByDev(Suspension.class, t, dev);
return (s == null) ? na : df.format(s.load);
}
@Override
public String get(Module m) {
Suspension s = (Suspension) m;
return (s == null) ? na : df.format(s.load);
}
},
/** Rotation speed of the standing tank (deg/s) */
MS_Traverse {
@Override
public String get(Tank t, Development dev) {
Suspension s = ModuleMap.getModuleByDev(Suspension.class, t, dev);
return (s == null) ? na : Integer.toString(s.traverse);
}
@Override
public String get(Module m) {
Suspension s = (Suspension) m;
return (s == null) ? na : Integer.toString(s.traverse);
}
},
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="turret">
/** all tanks that are compatible with this turret */
MT_Compatibility {
@Override
public String get(Tank t, Development dev) {
Turret tu = ModuleMap.getModuleByDev(Turret.class, t, dev);
return (tu == null || tu.compatibility == null) ? na : buildTankRefList(tu.compatibility, t.name, LinkType.INTERNAL);
}
@Override
public String get(Module m) {
Turret tu = (Turret) m;
return (tu == null || tu.compatibility == null) ? na : buildTankRefList(tu.compatibility, "turret", LinkType.INTERNAL);
}
},
/** The cost of this turret (currency in separate field) */
MT_Cost {
@Override
public String get(Tank t, Development dev) {
Turret tu = ModuleMap.getModuleByDev(Turret.class, t, dev);
return (tu == null) ? na : Integer.toString(tu.cost);
}
@Override
public String get(Module m) {
Turret tu = (Turret) m;
return (tu == null) ? na : Integer.toString(tu.cost);
}
},
/** The currency this turret is paid for with */
MT_Currency {
@Override
public String get(Tank t, Development dev) {
Turret tu = ModuleMap.getModuleByDev(Turret.class, t, dev);
return (tu == null || tu.currency == null) ? na : tu.currency.toString();
}
@Override
public String get(Module m) {
Turret tu = (Turret) m;
return (tu == null || tu.currency == null) ? na : tu.currency.toString();
}
},
/** the name of this turret */
MT_Name {
@Override
public String get(Tank t, Development dev) {
Turret tu = ModuleMap.getModuleByDev(Turret.class, t, dev);
return (tu == null) ? na : tu.name;
}
@Override
public String get(Module m) {
Turret tu = (Turret) m;
return (tu == null) ? na : tu.name;
}
},
/** The Nation this turret belongs to */
MT_Nation {
@Override
public String get(Tank t, Development dev) {
Turret tu = ModuleMap.getModuleByDev(Turret.class, t, dev);
return (tu == null || tu.nation == null) ? na : tu.nation.toString();
}
@Override
public String get(Module m) {
Turret tu = (Turret) m;
return (tu == null || tu.nation == null) ? na : tu.nation.toString();
}
},
/** The tier / level of this turret */
MT_Tier {
@Override
public String get(Tank t, Development dev) {
Turret tu = ModuleMap.getModuleByDev(Turret.class, t, dev);
return (tu == null) ? na : Byte.toString(tu.tier);
}
@Override
public String get(Module m) {
Turret tu = (Turret) m;
return (tu == null) ? na : Byte.toString(tu.tier);
}
},
/** the weight of the turret */
MT_Weight {
@Override
public String get(Tank t, Development dev) {
Turret tu = ModuleMap.getModuleByDev(Turret.class, t, dev);
return (tu == null) ? na : df.format(tu.weight);
}
@Override
public String get(Module m) {
Turret tu = (Turret) m;
return (tu == null) ? na : df.format(tu.weight);
}
},
/** Turret armor (mm) - Front */
MT_Armor_Front {
@Override
public String get(Tank t, Development dev) {
Turret tu = ModuleMap.getModuleByDev(Turret.class, t, dev);
return (tu == null) ? na : df.format(tu.armorFront);
}
@Override
public String get(Module m) {
Turret tu = (Turret) m;
return (tu == null) ? na : df.format(tu.armorFront);
}
},
/** Turret armor (mm) - Side */
MT_Armor_Side {
@Override
public String get(Tank t, Development dev) {
Turret tu = ModuleMap.getModuleByDev(Turret.class, t, dev);
return (tu == null) ? na : df.format(tu.armorSide);
}
@Override
public String get(Module m) {
Turret tu = (Turret) m;
return (tu == null) ? na : df.format(tu.armorSide);
}
},
/** Turret armor (mm) - Rear */
MT_Armor_Rear {
@Override
public String get(Tank t, Development dev) {
Turret tu = ModuleMap.getModuleByDev(Turret.class, t, dev);
return (tu == null) ? na : df.format(tu.armorRear);
}
@Override
public String get(Module m) {
Turret tu = (Turret) m;
return (tu == null) ? na : df.format(tu.armorRear);
}
},
/** Rotation speed of gun or turret (deg/s) */
MT_Traverse {
@Override
public String get(Tank t, Development dev) {
Turret tu = ModuleMap.getModuleByDev(Turret.class, t, dev);
return (tu == null) ? na : df.format(tu.traverse);
}
@Override
public String get(Module m) {
Turret tu = (Turret) m;
return (tu == null) ? na : df.format(tu.traverse);
}
},
/** The view range of the tank (m) */
MT_ViewRange {
@Override
public String get(Tank t, Development dev) {
Turret tu = ModuleMap.getModuleByDev(Turret.class, t, dev);
return (tu == null) ? na : df.format(tu.viewRange);
}
@Override
public String get(Module m) {
Turret tu = (Turret) m;
return (tu == null) ? na : df.format(tu.viewRange);
}
},
//</editor-fold>
// -- module relations --
//<editor-fold defaultstate="collapsed" desc="relations">
/** List of engines compatible with this tank */
REL_Engines {
@Override
public String get(Tank t, Development dev) {
return buildModuleRefList(ModuleMap.getModules(t, Module.ModuleType.Engine), LinkType.INTERNAL);
}
},
/** List of radios compatible with this tank */
REL_Radios {
@Override
public String get(Tank t, Development dev) {
return buildModuleRefList(ModuleMap.getModules(t, Module.ModuleType.Radio), LinkType.INTERNAL);
}
},
/** List of guns compatible with this tank */
REL_Guns {
@Override
public String get(Tank t, Development dev) {
return buildModuleRefList(ModuleMap.getModules(t, Module.ModuleType.Gun), LinkType.INTERNAL);
}
},
/** List of suspension compatible with this tank */
REL_Suspensions {
@Override
public String get(Tank t, Development dev) {
return buildModuleRefList(ModuleMap.getModules(t, Module.ModuleType.Suspension), LinkType.INTERNAL);
}
},
/** List of turrets compatible with this tank */
REL_Turrets {
@Override
public String get(Tank t, Development dev) {
return buildModuleRefList(ModuleMap.getModules(t, Module.ModuleType.Turret), LinkType.INTERNAL);
}
},
//</editor-fold>
// -- specials --
//<editor-fold defaultstate="collapsed" desc="depending fields">
/** total gun arc (left and right) */
DP_GunArc {
@Override
public String get(Tank t, Development dev) {
return Integer.toString((int) calc(t, dev));
}
@Override
public double calc(Tank t, Development dev) {
return Math.abs(t.gunArcLeft) + t.gunArcRight;
}
},
/** Total gun elevation (up and down) */
DP_Elevation {
@Override
public String get(Tank t, Development dev) {
return df.format(calc(t, dev));
}
@Override
public double calc(Tank t, Development dev) {
Equipment eq = getEquipment(t, dev);
return Math.abs(eq.gunElevationLow) + eq.gunElevationHigh;
}
},
/**
* normalized ammo capacity, defined as the time you can shoot nonstop
* (in seconds), before you run out of ammo
*/
DP_Ammo_Normalized {
@Override
public String get(Tank t, Development dev) {
return df.format(calc(t, dev));
}
@Override
public double calc(Tank t, Development dev) {
Gun g = ModuleMap.getModuleByDev(Gun.class, t, dev);
double rpm = (dev == Development.Stock) ? g.fireRateMin : g.fireRateMax;
double ammo = (dev == Development.Stock) ? g.ammoCapacityMin : g.ammoCapacityMax;
return ammo / (rpm / 60.0);
}
},
/** Damage per Second, using AP ammo */
DP_DmgPS_AP {
@Override
public String get(Tank t, Development dev) {
double dps = calc(t, dev);
return (dps == -1) ? na : df.format(dps);
}
@Override
public double calc(Tank t, Development dev) {
Gun g = ModuleMap.getModuleByDev(Gun.class, t, dev);
return calculateDPS(g, dev, g.dmgAP);
}
},
/** Damage per Second, using APCR ammo */
DP_DmgPS_APCR {
@Override
public String get(Tank t, Development dev) {
double dps = calc(t, dev);
return (dps == -1) ? na : df.format(dps);
}
@Override
public double calc(Tank t, Development dev) {
Gun g = ModuleMap.getModuleByDev(Gun.class, t, dev);
return calculateDPS(g, dev, g.dmgAPCR);
}
},
/** Damage per Second, using HE ammo */
DP_DmgPS_HE {
@Override
public String get(Tank t, Development dev) {
double dps = calc(t, dev);
return (dps == -1) ? na : df.format(dps);
}
@Override
public double calc(Tank t, Development dev) {
Gun g = ModuleMap.getModuleByDev(Gun.class, t, dev);
return calculateDPS(g, dev, g.dmgHE);
}
},
/** Damage per Second, using HEAT ammo */
DP_DmgPS_HEAT {
@Override
public String get(Tank t, Development dev) {
double dps = calc(t, dev);
return (dps == -1) ? na : df.format(dps);
}
@Override
public double calc(Tank t, Development dev) {
Gun g = ModuleMap.getModuleByDev(Gun.class, t, dev);
return calculateDPS(g, dev, g.dmgHEAT);
}
},
/** Horse Power per Ton, Tank accelerates faster for high values */
DP_HPperTon {
@Override
public String get(Tank t, Development dev) {
return df.format(calc(t, dev));
}
@Override
public double calc(Tank t, Development dev) {
Equipment eq = getEquipment(t, dev);
Engine e = ModuleMap.getModuleByDev(Engine.class, t, dev);
return (e.power) / eq.weight;
}
},
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="ratings">
/** the hitpoints rating */
RT_Hitpoints {
@Override
public String get(TankRating tr) {
return ratingHTMLsp(tr.hitpoints, tr.eq.hitpoints, TE_Hitpoints.best);
}
},
/** the weight rating */
RT_Weight {
@Override
public String get(TankRating tr) {
return ratingHTMLsp(tr.weight, tr.eq.weight, TE_Weight.best);
}
},
/** the engine firechance rating */
RT_Firechance {
@Override
public String get(TankRating tr) {
return ratingHTMLsp(tr.firechance, tr.e.firechance, ME_Firechance.best);
}
},
/** the turret rotation rating */
RT_TraverseTurret {
@Override
public String get(TankRating tr) {
return ratingHTMLsp(tr.traverseTurret, tr.tu.traverse, MT_Traverse.best);
}
},
/** the tank rotation rating */
RT_TraverseSuspension {
@Override
public String get(TankRating tr) {
return ratingHTMLsp(tr.traverseSuspension, tr.s.traverse, MS_Traverse.best);
}
},
/** the accuracy rating */
RT_Accuracy {
@Override
public String get(TankRating tr) {
return ratingHTMLdp(tr.gunAccuracy, (tr.eq.development == Development.Stock) ? tr.g.accuracyMax : tr.g.accuracyMin, MG_Accuracy_Min.best);
}
},
/** the aim time rating */
RT_AimTime {
@Override
public String get(TankRating tr) {
return ratingHTMLdp(tr.gunAimTime, (tr.eq.development == Development.Stock) ? tr.g.aimTimeMax : tr.g.aimTimeMin, MG_AimTime_Min.best);
}
},
/** the ammo capacity rating rating, using normalized ammo (continuous fire time) */
RT_AmmoCapacity {
@Override
public String get(TankRating tr) {
int ammo = (tr.eq.development == Development.Stock) ? tr.g.ammoCapacityMin : tr.g.ammoCapacityMax;
double rate = (tr.eq.development == Development.Stock) ? tr.g.fireRateMin : tr.g.fireRateMax;
long s = Math.round(ammo / (rate / 60.0));
String duration = String.format("%02d:%02d", (s/60), (s%60));
String tooltip = String.format("Ammo: %s rounds<br/>Rate: %s rpm<br/>=> Constant Fire: %s<br/>Best: %s s",
ammo, rate, duration, Math.round(DP_Ammo_Normalized.best));
return ratingHTML(percent(tr.gunAmmo), tooltip);
}
},
/** the top speed rating */
RT_TopSpeed {
@Override
public String get(TankRating tr) {
return ratingHTMLsp(tr.speed, tr.t.speed, T_TopSpeed.best);
}
},
/** the engine power rating */
RT_EnginePower {
@Override
public String get(TankRating tr) {
return ratingHTMLsp(tr.enginePower, tr.e.power, ME_Power.best);
}
},
/** the power-weight ratio rating */
RT_PowerWeightRatio {
@Override
public String get(TankRating tr) {
return ratingHTMLsp(tr.powerWeightRatio, Field.DP_HPperTon.calc(tr.t, tr.eq.development), DP_HPperTon.best);
}
},
/** the radio transmission rate rating */
RT_RadioRange {
@Override
public String get(TankRating tr) {
return ratingHTMLsp(tr.radioRange, tr.r.range, MR_Range.best);
}
},
/** the view range rating */
RT_ViewRange {
@Override
public String get(TankRating tr) {
return ratingHTMLsp(tr.viewRange, tr.eq.viewRange, TE_ViewRange.best);
}
},
/** The hull armor rating (cumulation of front, side and rear) */
RT_HullArmor {
@Override
public String get(TankRating tr) {
String tooltip = String.format("F: %s mm (best: %s)<br/>S: %s mm (best: %s)<br/>R: %s mm (best: %s)",
tr.t.hullFront, T_Hull_Front.best, tr.t.hullSide, T_Hull_Side.best,
tr.t.hullRear, T_Hull_Rear.best);
return ratingHTML(percent(tr.hullArmor), tooltip);
}
},
/** The turret armor rating (cumulation of front, side and rear) */
RT_TurretArmor {
@Override
public String get(TankRating tr) {
String tooltip = String.format("F: %s mm (best: %s)<br/>S: %s mm (best: %s)<br/>R: %s mm (best: %s)",
tr.tu.armorFront, MT_Armor_Front.best, tr.tu.armorSide, MT_Armor_Side.best,
tr.tu.armorRear, MT_Armor_Rear.best);
return ratingHTML(percent(tr.turretArmor), tooltip);
}
},
/** The gun arc (left/right) rating */
RT_GunArc {
@Override
public String get(TankRating tr) {
return ratingHTMLsp(tr.gunArc, Field.DP_GunArc.calc(tr.t, tr.eq.development), DP_GunArc.best);
}
},
/** The gun elevation (low/high) rating */
RT_GunElevation {
@Override
public String get(TankRating tr) {
return ratingHTMLsp(tr.gunElevation, Field.DP_Elevation.calc(tr.t, tr.eq.development), DP_Elevation.best);
}
},
/** The damage rating (cumulation of all damage types) */
RT_Damage {
@Override
public String get(TankRating tr) {
String rate = (tr.eq.development == Development.Stock) ? df.format(tr.g.fireRateMin) : df.format(tr.g.fireRateMax);
String row = "<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>";
StringBuilder sb = new StringBuilder(200);
sb.append("<table><tr><th>AmmoType</th><th>dmg/shot</th><th>shots/min</th><th>dmg/s</th><th>dmg/s (best)</th></tr>");
sb.append(String.format(row, "AP", tr.g.dmgAP, rate, df.format(Field.DP_DmgPS_AP.calc(tr.t, tr.eq.development)),
df.format(Field.DP_DmgPS_AP.best)));
sb.append(String.format(row, "APCR", tr.g.dmgAPCR, rate, df.format(Field.DP_DmgPS_APCR.calc(tr.t, tr.eq.development)),
df.format(Field.DP_DmgPS_APCR.best)));
sb.append(String.format(row, "HE", tr.g.dmgHE, rate, df.format(Field.DP_DmgPS_HE.calc(tr.t, tr.eq.development)),
df.format(Field.DP_DmgPS_HE.best)));
sb.append(String.format(row, "HEAT", tr.g.dmgHEAT, rate, df.format(Field.DP_DmgPS_HEAT.calc(tr.t, tr.eq.development)),
df.format(Field.DP_DmgPS_HEAT.best)));
sb.append("</table>");
return ratingHTML(percent(tr.damage), sb.toString());
}
},
/** The penetration rating (cumulation of all ammo types) */
RT_Penetration {
@Override
public String get(TankRating tr) {
String tooltip = String.format("AP: %s mm (best: %s)<br/>APCR: %s mm (best: %s)<br/>"
+ "HE: %s mm (best: %s)<br/>HEAT: %s mm (best: %s)",
tr.g.penAP, MG_Penetration_AP.best, tr.g.penAPCR, MG_Penetration_APCR.best,
tr.g.penHE, MG_Penetration_HE.best, tr.g.penHEAT, MG_Penetration_HEAT.best);
return ratingHTML(percent(tr.penetration), tooltip);
}
},
/** The defensive rating for this tank */
RT2_Defense {
@Override
public String get(TankRating tr) {
return percent(tr.ratingDefense);
}
},
/** The offensive rating for this tank */
RT2_Attack {
@Override
public String get(TankRating tr) {
return percent(tr.ratingAttack);
}
},
/** The mobility rating for this tank */
RT2_Mobility {
@Override
public String get(TankRating tr) {
return percent(tr.ratingMobility);
}
},
/** The recon rating for this tank */
RT2_Recon {
@Override
public String get(TankRating tr) {
return percent(tr.ratingRecon);
}
},
/** The cost/benefit-rating for this tank */
RT2_CostBenefit {
@Override
public String get(TankRating tr) {
return percent(tr.ratingCostBenefit);
}
},
/** The overall rating for this tank */
RT2_OverallRating {
@Override
public String get(TankRating tr) {
return percent(tr.ratingOverall);
}
},
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="special fields">
/** Just an empty field, no value associated */
EMPTY;
//</editor-fold>
//</editor-fold>
private static final Logger log = LoggerFactory.getLogger(Field.class);
//<editor-fold desc="shared enum members">
/** best value for each field (compared to the other instances) */
public double best = -1;
/**
* Calculates the value of an advanced field (prefix DP_)
* Returns -1 on all other fields
* @param t the Tank to calculate the value for
* @param dev the development (needed if field depends on it)
* @return the value of this field (or -1, if not applicable)
*/
public double calc(Tank t, Development dev) {
return -1;
}
/**
* Gets the value of this field as String
* @param t the Tank to calculate the value for
* @param dev the development (needed if field depends on it)
* @return String representation of this field
*/
public String get(Tank t, Development dev) {
return "";
}
/**
* Gets the value of this field as String.
* Does only work for Modules, returns empty String for anything else!
* @param m the module that is associated with this value
* @return the value for the given module, or an empty string if wrong
* module is given or the requested value is not part of a module
*/
public String get(Module m) {
return "";
}
/**
* Gets the value of this rating (includes HTML)
* @param tr the tank rating
* @return String representation of this rating
*/
public String get(TankRating tr) {
return get(tr.t, tr.eq.development);
}
//</editor-fold>
//<editor-fold desc="methods">
/** Decimal formatter, one decimal digit */
protected static final DecimalFormat df = new DecimalFormat("0.0", new DecimalFormatSymbols(Locale.US));
/** More precise decimal formatter, two decimal digits */
protected static final DecimalFormat dfp = new DecimalFormat("0.00", new DecimalFormatSymbols(Locale.US));
/** this string is entered for invalid field values */
public static final String na = "n/a";
/**
* Returns the equipment for this tank that represents stock or top.
* @param t the tank
* @param dev stock or top
* @return equipment of this tank for stock or top
*/
protected static Equipment getEquipment(Tank t, Development dev) {
switch (dev) {
case Stock:
return t.equipmentStock;
case Top:
return t.equipmentTop;
default:
return null;
}
}
// ---------- reference lists ----------
/**
* Creates a String of the tank reference list, using html <a> to link
* stuff...
* @param refs the references to link to
* @param source the name of the source tank, only needed for error logging
* @param link the type of link to create
* @return HTML String representation of the given list
*/
protected static String buildTankRefList(List<TankRef> refs, String source, LinkType link) {
StringBuilder sb = new StringBuilder();
for (TankRef tr : refs) {
if (tr.ref != null) {
switch (link) {
case INTERNAL:
sb.append(String.format("<a href=\"#%s\">%s</a>", tr.ref.id, tr.ref.name));
break;
case EXTERNAL:
try {
sb.append(String.format("<a href=\"%s\">%s</a>", Crawler.buildWikiLink(tr.ref.name).toString(), tr.ref.name));
} catch (MalformedURLException ex) {
log.error("The generated Wikilink is not a valid URL", ex);
sb.append(tr.ref.name);
}
break;
case NONE:
sb.append(tr.ref.name);
break;
default:
sb.append(tr.ref.id);
break;
}
sb.append(", ");
} else {
log.error("Invalid child reference for Tank {}", source);
}
}
// delete last comma and return
if (sb.length() > 3) {
sb.delete(sb.length() - 2, sb.length());
}
return sb.toString();
}
/**
* Creates a String of the module list, using html <a> to link
* stuff...
* @param modules the modules to link to
* @param link the type of link to create
* @return HTML String representation of the given list
*/
protected static String buildModuleRefList(List<? extends Module> modules, LinkType link) {
StringBuilder sb = new StringBuilder();
for (Object o : modules) {
Module ref = (Module) o;
switch (link) {
case INTERNAL:
sb.append(String.format("<a href=\"#%s\">%s</a>", ref.name, ref.name));
break;
case EXTERNAL:
// not supported, go on (no break)
case NONE:
sb.append(ref.name);
break;
}
sb.append(", ");
}
// delete last comma and return
if (sb.length() > 3) {
sb.delete(sb.length() - 2, sb.length());
}
return sb.toString();
}
// ---------- min max fields ----------
/**
* Calculates the minimum and maximum values for all relevant fields, using
* the data from the specified TankDB
* @param db the database to retrieve values from
*/
public static void calculateMinMaxFields(TanksDB db) {
for (Tank t : db.tanks) {
for (Development dev : Development.values()) {
calculateMinMaxFields(t, dev);
}
}
}
/**
* Calculates the minimum and maximum values for all relevant fields, using
* the data from the specified TankDB, but only for tanks of the specified
* TankType
* @param db the database to retrieve values from
* @param type the TankType to calculate values for
*/
public static void calculateMinMaxFields(TanksDB db, TankType type) {
// reset old values
resetBestValues();
// calculate new ones for this type only
for (Tank t : db.tanks) {
// use only tanks of specified type for minmax rating!
if(t.type == type) {
for (Development dev : Development.values()) {
calculateMinMaxFields(t, dev);
}
}
}
}
/**
* Resets the min and max values, before new ones are generated.
*/
protected static void resetBestValues() {
// higher is better (default)
for (Field f : Field.values()) {
f.best = -1;
}
// lower is better
Field.MG_AimTime_Min.best = Double.POSITIVE_INFINITY;
Field.MG_AimTime_Max.best = Double.POSITIVE_INFINITY;
Field.MG_Accuracy_Min.best = Double.POSITIVE_INFINITY;
Field.MG_Accuracy_Max.best = Double.POSITIVE_INFINITY;
Field.ME_Firechance.best = Double.POSITIVE_INFINITY;
}
/**
* Calculates the minimum and maximum values for all relevant fields for
* the specified tank.
* @param t the tank to calculate values for
* @param dev the development of this tank (to retrieve correct modules)
*/
protected static void calculateMinMaxFields(Tank t, Development dev) {
Equipment eq = dev.getEquip(t, dev);
Engine e = ModuleMap.getModuleByDev(Engine.class, t, dev);
Gun g = ModuleMap.getModuleByDev(Gun.class, t, dev);
Radio r = ModuleMap.getModuleByDev(Radio.class, t, dev);
Suspension s = ModuleMap.getModuleByDev(Suspension.class, t, dev);
Turret tu = ModuleMap.getModuleByDev(Turret.class, t, dev);
// base properties
updateMax(Field.TE_Hitpoints, eq.hitpoints);
updateMax(Field.TE_Weight , eq.weight);
updateMin(Field.ME_Firechance , e.firechance);
updateMax(Field.MT_Traverse , tu.traverse);
updateMax(Field.MS_Traverse , s.traverse);
updateMax(Field.T_TopSpeed , t.speed);
updateMax(Field.ME_Power , e.power);
updateMax(Field.MR_Range , r.range);
updateMax(Field.TE_ViewRange , eq.viewRange);
updateMax(Field.T_Hull_Front , t.hullFront);
updateMax(Field.T_Hull_Side , t.hullRear);
updateMax(Field.T_Hull_Rear , t.hullSide);
updateMax(Field.MT_Armor_Front , tu.armorFront);
updateMax(Field.MT_Armor_Side , tu.armorSide);
updateMax(Field.MT_Armor_Rear , tu.armorRear);
updateMax(Field.MG_Penetration_AP , g.penAP);
updateMax(Field.MG_Penetration_APCR , g.penAPCR);
updateMax(Field.MG_Penetration_HE , g.penHE);
updateMax(Field.MG_Penetration_HEAT , g.penHEAT);
// special calculations
updateMax(Field.DP_GunArc , t, dev);
updateMax(Field.DP_Elevation, t, dev);
updateMax(Field.DP_Ammo_Normalized, t, dev);
updateMax(Field.DP_DmgPS_AP , t, dev);
updateMax(Field.DP_DmgPS_APCR , t, dev);
updateMax(Field.DP_DmgPS_HE , t, dev);
updateMax(Field.DP_DmgPS_HEAT , t, dev);
updateMax(Field.DP_HPperTon, t, dev);
// depending on dev --> always use best values, will be applied anyways
switch (eq.development) {
case Stock:
updateMin(Field.MG_Accuracy_Max, g.accuracyMin);
updateMin(Field.MG_AimTime_Max, g.aimTimeMin);
updateMax(Field.MG_AmmoCapacity_Min, g.ammoCapacityMax);
break;
case Top:
updateMin(Field.MG_Accuracy_Min, g.accuracyMin);
updateMin(Field.MG_AimTime_Min, g.aimTimeMin);
updateMax(Field.MG_AmmoCapacity_Max, g.ammoCapacityMax);
break;
}
}
/**
* Updates the maximum value of a given field with the specified value,
* if it really is larger than the current max value
* @param f the field to update
* @param value the value to set as max, if larger
*/
protected static void updateMax(Field f, double value) {
if (value > 0.0) {
if (value > f.best) {
f.best = value;
}
} else if (value < 0.0) {
log.warn("Field {} is associated with illegal value {}", f.toString(), value);
}
}
/**
* Updates the maximum value of a given field with the value from the
* specified tank, if it really is larger than the current max value
* @param f the field to update
* @param t the tank
* @param dev stock or top equipment?
*/
protected static void updateMax(Field f, Tank t, Development dev) {
double value = f.calc(t, dev);
updateMax(f, value);
}
/**
* Updates the minimum value of a given field with the specified value,
* if it really is smaller than the current min value
* @param f the field to update
* @param value the value to set as min, if smaller
*/
protected static void updateMin(Field f, double value) {
if (value > 0.0) {
if (value < f.best) {
f.best = value;
}
} else if (value < 0.0) {
log.warn("Field {} is associated with illegal value {}", f.toString(), value);
}
}
/**
* Updates the minimum value of a given field with the value from the
* specified tank, if it really is smaller than the current max value
* @param f the field to update
* @param t the tank
* @param dev stock or top equipment?
*/
protected static void updateMin(Field f, Tank t, Development dev) {
double value = f.calc(t, dev);
updateMin(f, value);
}
// ---------- other helpers ----------
/**
* Converts a double into a String representing it's percent value
* @param d the double to convert
* @return percent (e.g. 0.52 -> 52.0 %)
*/
public static String percent(double d) {
return (d == -1) ? na : df.format(d * 100) + " %";
}
/**
* Creates a html string containing the specified rating and a custom
* comment inside an abbr-tag (so it is visible on mouseover)
* @param rating the rating of a field
* @param comment the comment for this field
* @return rating and hidden comment as html string
*/
protected static String ratingHTML(String rating, String comment) {
return String.format("<abbr title=\"%s\">%s</abbr>", comment, rating);
}
/**
* Special version of ratingHTML:
* Writes the given rating (double) as percent string and surrounds it with
* an abbr-tag that contains the absolute value as well as the given best
* value.
* sp: the hidden values will be printed in "single precision" (one decimal
* place)
* @param rating the rating of this field
* @param value the actual value of this field
* @param best the best value of this field
* @return rating and hidden comment as html string
*/
protected static String ratingHTMLsp(double rating, double value, double best) {
String tooltip = String.format("Value: %s<br/>Best: %s", df.format(value), df.format(best));
return ratingHTML(percent(rating), tooltip);
}
/**
* Special version of ratingHTML:
* Writes the given rating (double) as percent string and surrounds it with
* an abbr-tag that contains the absolute value as well as the given best
* value.
* dp: the hidden values will be printed in "double precision" (two decimal
* places)
* @param rating the rating of this field
* @param value the actual value of this field
* @param best the best value of this field
* @return rating and hidden comment as html string
*/
protected static String ratingHTMLdp(double rating, double value, double best) {
String tooltip = String.format("Value: %s<br/>Best: %s", dfp.format(value), dfp.format(best));
return ratingHTML(percent(rating), tooltip);
}
/**
* Calculates the Damage per Second for a specified gun. The development is
* used to determine, if min or max fire rate is used and the damage value
* is needed because there are different ammo types...
* @param g the gun this value is calculated for
* @param dev the development of the tank where the gun is mounted
* @param damage the actual damage of the gun (depends on ammo type1)
* @return dmg/s
*/
protected static double calculateDPS(Gun g, Development dev, double damage) {
if (g == null) {
return -1;
} else {
double rate = (dev == Development.Stock) ? g.fireRateMin : g.fireRateMax;
return damage * rate / 60.0;
}
}
/**
* Different types of (web)links
*/
enum LinkType {
/** internal html link (anchor) */
INTERNAL,
/** external html link (hyperref) */
EXTERNAL,
/** no link at all... */
NONE;
}
//</editor-fold>
}