📄 protomech.java
字号:
/* * MegaMek - Copyright (C) 2003,2004 Ben Mazur (bmazur@sev.org) * * 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 2 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. */package megamek.common;import java.io.PrintWriter;import java.io.Serializable;import java.util.Vector;import megamek.common.preference.PreferenceManager;/** * Protomechs. Level 2 Clan equipment. */public class Protomech extends Entity implements Serializable { public static final int NUM_PMECH_LOCATIONS = 6; public static final String[] LOCATION_NAMES = { "Head", "Torso", "Right Arm", "Left Arm", "Legs", "Main Gun" }; public static final String[] LOCATION_ABBRS = { "HD", "T", "RA", "LA", "L", "MG" }; // weapon bools private boolean bHasMainGun; private boolean bHasRArmGun; private boolean bHasLArmGun; private boolean bHasTorsoAGun; private boolean bHasTorsoBGun; // weapon indices private int TorsoAGunNum; private int TorsoBGunNum; // locations // Pilot damage caused so far by crits to this location. // Needed for location destruction pilot damage. private int PilotDamageTaken[] = { 0, 0, 0, 0, 0, 0 }; /** * The battle value of this unit. This value should be set when the unit's * file is read. */ private int myBV = 0; /* * * Not every Protomech has a main gun. * N.B. Regardless of the value set * here, the variable is initialized to * <code>false</code> until after * the <code>Entity</code> is initialized, * which is too late to allow * main gun armor, hence the convoluted reverse * logic. */ private boolean m_bHasNoMainGun = false; public static final int LOC_HEAD = 0; public static final int LOC_TORSO = 1; public static final int LOC_RARM = 2; public static final int LOC_LARM = 3; public static final int LOC_LEG = 4; public static final int LOC_MAINGUN = 5; // Near miss reprs. public static final int LOC_NMISS = 6; // "Systems". These represent protomech critical hits; which remain constant // regardless of proto. // doesn't matter what gets hit in a proto section, just the number of times // it's been critted // so just have the right number of these systems and it works. public static final int SYSTEM_ARMCRIT = 0; public static final int SYSTEM_LEGCRIT = 1; public static final int SYSTEM_HEADCRIT = 2; public static final int SYSTEM_TORSOCRIT = 3; public static final int SYSTEM_TORSO_WEAPON_A = 4; public static final int SYSTEM_TORSO_WEAPON_B = 5; private static final int[] NUM_OF_SLOTS = { 2, 3, 2, 2, 3, 0 }; public static final int[] POSSIBLE_PILOT_DAMAGE = { 1, 3, 1, 1, 1, 0 }; public static final String systemNames[] = { "Arm", "Leg", "Head", "Torso" }; /** * Construct a new, blank, pmech. */ public Protomech() { super(); setCritical(LOC_HEAD, 0, new CriticalSlot(CriticalSlot.TYPE_SYSTEM, SYSTEM_HEADCRIT)); setCritical(LOC_HEAD, 1, new CriticalSlot(CriticalSlot.TYPE_SYSTEM, SYSTEM_HEADCRIT)); setCritical(LOC_RARM, 0, new CriticalSlot(CriticalSlot.TYPE_SYSTEM, SYSTEM_ARMCRIT)); setCritical(LOC_RARM, 1, new CriticalSlot(CriticalSlot.TYPE_SYSTEM, SYSTEM_ARMCRIT)); setCritical(LOC_LARM, 0, new CriticalSlot(CriticalSlot.TYPE_SYSTEM, SYSTEM_ARMCRIT)); setCritical(LOC_LARM, 1, new CriticalSlot(CriticalSlot.TYPE_SYSTEM, SYSTEM_ARMCRIT)); setCritical(LOC_TORSO, 0, new CriticalSlot(CriticalSlot.TYPE_SYSTEM, SYSTEM_TORSOCRIT)); setCritical(LOC_TORSO, 1, new CriticalSlot(CriticalSlot.TYPE_SYSTEM, SYSTEM_TORSOCRIT)); setCritical(LOC_TORSO, 2, new CriticalSlot(CriticalSlot.TYPE_SYSTEM, SYSTEM_TORSOCRIT)); setCritical(LOC_LEG, 0, new CriticalSlot(CriticalSlot.TYPE_SYSTEM, SYSTEM_LEGCRIT)); setCritical(LOC_LEG, 1, new CriticalSlot(CriticalSlot.TYPE_SYSTEM, SYSTEM_LEGCRIT)); setCritical(LOC_LEG, 2, new CriticalSlot(CriticalSlot.TYPE_SYSTEM, SYSTEM_LEGCRIT)); bHasMainGun = false; bHasRArmGun = false; bHasLArmGun = false; bHasTorsoAGun = false; bHasTorsoBGun = false; m_bHasNoMainGun = true; } protected int[] getNoOfSlots() { return NUM_OF_SLOTS; } /** * Returns # of pilot damage points taken due to crits to the location so * far. */ public int getPilotDamageTaken(int loc) { return PilotDamageTaken[loc]; } /** * Get the weapon in the given torso location (if any). * * @param isTorsoA - * a <code>boolean</code> that is <code>true</code> if the * weapon in "Torso A" is needed; <code>false</code> if the * weapon in "Torso B" is needed. * @return the <code>Mounted</code> weapon at the needed location. This * value will be <code>null</code> if no weapon is in the * indicated location. */ public Mounted getTorsoWeapon(boolean isTorsoA) { Mounted weapon = null; if (isTorsoA && bHasTorsoAGun) { weapon = getEquipment(TorsoAGunNum); } else if (!isTorsoA && bHasTorsoBGun) { weapon = getEquipment(TorsoBGunNum); } return weapon; } /** * Tells the Protomech to note pilot damage taken from crit damage to the * location */ public void setPilotDamageTaken(int loc, int damage) { PilotDamageTaken[loc] = damage; } /** * Protos don't take piloting skill rolls. */ public PilotingRollData getBasePilotingRoll() { return new PilotingRollData(this.getId(), PilotingRollData.CHECK_FALSE, "Protomeks never take PSRs."); } /** * A "shaded" critical is a box shaded on the record sheet, implies pilot * damage when hit. Returns whether shaded. */ public boolean shaded(int loc, int numHit) { switch (loc) { case LOC_HEAD: case LOC_LARM: case LOC_RARM: return (2 == numHit); case LOC_TORSO: return (0 < numHit); case LOC_MAINGUN: case LOC_NMISS: return false; case LOC_LEG: return (3 == numHit); } return false; } public int getWalkMP(boolean gravity) { int wmp = getOriginalWalkMP(); int legCrits = this.getCritsHit(LOC_LEG); int i; int j; // Gravity, Protos can't get faster if (gravity) j = applyGravityEffectsOnMP(wmp); else j = wmp; if (j < wmp) wmp = j; switch (legCrits) { case 0: break; case 1: wmp--; break; case 2: wmp = wmp / 2; break; case 3: wmp = 0; break; } if (game != null) { i = game.getTemperatureDifference(); return Math.max(wmp - i, 0); } return wmp; } /** * Counts the # of crits taken by proto in the location. Needed in several * places, due to proto set criticals. */ public int getCritsHit(int loc) { int count = 0; int numberOfCriticals = this.getNumberOfCriticals(loc); for (int i = 0; i < numberOfCriticals; i++) { CriticalSlot ccs = getCritical(loc, i); if (ccs.isDamaged() || ccs.isBreached()) { count++; } } return count; } public static int getInnerLocation(int location) { return LOC_TORSO; } /** * Add in any piloting skill mods */ public PilotingRollData addEntityBonuses(PilotingRollData roll) { return roll; } /** * Returns the number of total critical slots in a location */ public int getNumberOfCriticals(int loc) { switch (loc) { case LOC_MAINGUN: return 0; case LOC_HEAD: case LOC_LARM: case LOC_RARM: return 2; case LOC_LEG: case LOC_TORSO: return 3; } return 0; } /** * Override Entity#newRound() method. */ public void newRound(int roundNumber) { setSecondaryFacing(getFacing()); super.newRound(roundNumber); } // End public void newRound() /** * This pmech's jumping MP modified for missing jump jets and gravity. */ public int getJumpMP() { int jump = this.jumpMP; int torsoCrits = this.getCritsHit(LOC_TORSO); switch (torsoCrits) { case 0: break; case 1: if (jump > 0) jump--; break; case 2: jump = jump / 2; break; } if (applyGravityEffectsOnMP(jump) > jump) return jump; return applyGravityEffectsOnMP(jump); } /** * Returns this mech's jumping MP, modified for missing & underwater jets. */ public int getJumpMPWithTerrain() { if (getPosition() == null) { return getJumpMP(); } int waterLevel = game.getBoard().getHex(getPosition()).terrainLevel( Terrains.WATER); if (waterLevel <= 0 || getElevation() >= 0) { return getJumpMP(); } return 0; } public int getHeatCapacityWithWater() { return getHeatCapacity(); } /** * Returns the amount of heat that the entity can sink each turn. Pmechs have * no heat. * //FIXME * However, the number of heat sinks they have IS importnat... * For cost and validation purposes. */ public int getHeatCapacity() { return 999; } public String[] getLocationNames() { return LOCATION_NAMES; } /** * Returns the name of the type of movement used. This is pmech-specific. */ public String getMovementString(int mtype) { switch (mtype) { case IEntityMovementType.MOVE_NONE: return "None"; case IEntityMovementType.MOVE_WALK: return "Walked"; case IEntityMovementType.MOVE_RUN: return "Ran"; case IEntityMovementType.MOVE_JUMP: return "Jumped"; default: return "Unknown!"; } } /** * Returns the name of the type of movement used. This is pmech-specific. */ public String getMovementAbbr(int mtype) { switch (mtype) { case IEntityMovementType.MOVE_NONE: return "N"; case IEntityMovementType.MOVE_WALK: return "W"; case IEntityMovementType.MOVE_RUN: return "R"; case IEntityMovementType.MOVE_JUMP: return "J"; default: return "?"; } } public boolean canChangeSecondaryFacing() { return !(this.getCritsHit(LOC_LEG) > 2); } public int getEngineCritHeat() { return 0; } /** * Can this pmech torso twist in the given direction? */ public boolean isValidSecondaryFacing(int dir) { int rotate = dir - getFacing(); if (canChangeSecondaryFacing()) { return rotate == 0 || rotate == 1 || rotate == -1 || rotate == -5; } return rotate == 0; } /** * Return the nearest valid direction to torso twist in */ public int clipSecondaryFacing(int dir) { if (isValidSecondaryFacing(dir)) { return dir; } // otherwise, twist once in the appropriate direction final int rotate = (dir + (6 - getFacing())) % 6; return rotate >= 3 ? (getFacing() + 5) % 6 : (getFacing() + 1) % 6; } public boolean hasRearArmor(int loc) { return false; } public int getRunMPwithoutMASC(boolean gravity) { return getRunMP(gravity); } /** * Returns the Compute.ARC that the weapon fires into. */ public int getWeaponArc(int wn) { final Mounted mounted = getEquipment(wn); // rear mounted? if (mounted.isRearMounted()) { return Compute.ARC_REAR; } // front mounted switch (mounted.getLocation()) { case LOC_TORSO: return Compute.ARC_FORWARD; case LOC_RARM: return Compute.ARC_RIGHTARM; case LOC_LARM: return Compute.ARC_LEFTARM; case LOC_MAINGUN: return Compute.ARC_MAINGUN; default: return Compute.ARC_360; } } /** * Returns true if this weapon fires into the secondary facing arc. If * false, assume it fires into the primary. */ public boolean isSecondaryArcWeapon(int weaponId) { return true; } /** * Rolls up a hit location */ public HitData rollHitLocation(int table, int side) { return rollHitLocation(table, side, LOC_NONE, IAimingModes.AIM_MODE_NONE); } public HitData rollHitLocation(int table, int side, int aimedLocation, int aimingMode) { int roll = -1; if ((aimedLocation != LOC_NONE) && (aimingMode == IAimingModes.AIM_MODE_IMMOBILE)) { roll = Compute.d6(2); if ((5 < roll) && (roll < 9)) { return new HitData(aimedLocation, side == ToHitData.SIDE_REAR, true); } } roll = Compute.d6(2); try { PrintWriter pw = PreferenceManager.getClientPreferences() .getMekHitLocLog(); if (pw != null) { pw.print(table); pw.print("\t"); pw.print(side); pw.print("\t"); pw.println(roll); } } catch (Throwable thrown) { thrown.printStackTrace(); } switch (roll) { case 2: return new HitData(Protomech.LOC_MAINGUN); case 3: case 11: return new HitData(Protomech.LOC_NMISS); case 4: return new HitData(Protomech.LOC_RARM); case 5: case 9: return new HitData(Protomech.LOC_LEG); case 6: case 7: case 8: return new HitData(Protomech.LOC_TORSO); case 10:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -