📄 tank.java
字号:
/* * MegaMek - Copyright (C) 2000-2003 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.Serializable;import java.util.Vector;/** * You know what tanks are, silly. */public class Tank extends Entity implements Serializable{ private boolean m_bHasNoTurret = false; private boolean m_bTurretLocked = false; private int m_nTurretOffset = 0; private int m_nStunnedTurns = 0; private int m_nJammedTurns = 0; private Mounted m_jammedGun = null; private boolean m_bImmobile = false; private boolean m_bImmobileHit = false; private int burningLocations = 0; private int movementDamage = 0; private boolean infernoFire = false; // locations public static final int LOC_BODY = 0; public static final int LOC_FRONT = 1; public static final int LOC_RIGHT = 2; public static final int LOC_LEFT = 3; public static final int LOC_REAR = 4; public static final int LOC_TURRET = 5; // tanks have no critical slot limitations private static final int[] NUM_OF_SLOTS = {25, 25, 25, 25, 25, 25}; protected static String[] LOCATION_ABBRS = { "BD", "FR", "RS", "LS", "RR", "TU" }; protected static String[] LOCATION_NAMES = { "Body", "Front", "Right", "Left", "Rear", "Turret" }; public String[] getLocationAbbrs() { return LOCATION_ABBRS; } public String[] getLocationNames() { return LOCATION_NAMES; } private int armorType = 0; private int structureType = 0; public boolean hasNoTurret() { return m_bHasNoTurret; } public void setHasNoTurret(boolean b) { m_bHasNoTurret = b; } /** * Returns this entity's walking/cruising mp, factored * for heat, extreme temperatures, and gravity. */ public int getWalkMP(boolean gravity) { int i; int j; if (gravity) j = applyGravityEffectsOnMP(getOriginalWalkMP()); else j = getOriginalWalkMP(); if (game != null) { i = game.getTemperatureDifference(); return Math.max(j - i, 0); } return j; } public boolean isTurretLocked() { return m_bTurretLocked; } /** * Returns the number of locations in the entity */ public int locations() { return m_bHasNoTurret ? 5 : 6; //return 6; } public boolean canChangeSecondaryFacing() { return !m_bHasNoTurret && !m_bTurretLocked; } public boolean isValidSecondaryFacing(int n) { return !m_bTurretLocked; } public int clipSecondaryFacing(int n) { return n; } public void setSecondaryFacing(int sec_facing) { if (!m_bTurretLocked) { super.setSecondaryFacing(sec_facing); if (!m_bHasNoTurret) { m_nTurretOffset = sec_facing - getFacing(); } } } public void setFacing(int facing) { super.setFacing(facing); if (m_bTurretLocked) { int nTurretFacing = (facing + m_nTurretOffset + 6) % 6; super.setSecondaryFacing(nTurretFacing); } } public boolean isMovementHit() { return m_bImmobile; } public boolean isMovementHitPending() { return m_bImmobileHit; } public void immobilize() { m_bImmobileHit = true; setOriginalWalkMP(0); } public boolean isImmobile() { if (game.getOptions().booleanOption("no_immobile_vehicles")) { return super.isImmobile(); } return super.isImmobile() || m_bImmobile; } /** * Tanks have all sorts of prohibited terrain. */ public boolean isHexProhibited(IHex hex) { if(hex.containsTerrain(Terrains.IMPASSABLE)) return true; switch(movementMode) { case IEntityMovementMode.TRACKED : return hex.terrainLevel(Terrains.WOODS) > 1 || (hex.terrainLevel(Terrains.WATER) > 0 && !hex.containsTerrain(Terrains.ICE)) || hex.containsTerrain(Terrains.JUNGLE) || hex.terrainLevel(Terrains.MAGMA) > 1; case IEntityMovementMode.WHEELED : return hex.containsTerrain(Terrains.WOODS) || hex.containsTerrain(Terrains.ROUGH) || (hex.terrainLevel(Terrains.WATER) > 0 && !hex.containsTerrain(Terrains.ICE)) || hex.containsTerrain(Terrains.RUBBLE) || hex.containsTerrain(Terrains.MAGMA) || hex.containsTerrain(Terrains.JUNGLE) || hex.containsTerrain(Terrains.SNOW) || hex.terrainLevel(Terrains.GEYSER) == 2; case IEntityMovementMode.HOVER : return hex.containsTerrain(Terrains.WOODS) || hex.containsTerrain(Terrains.JUNGLE) || hex.terrainLevel(Terrains.MAGMA) > 1; case IEntityMovementMode.NAVAL: case IEntityMovementMode.HYDROFOIL: return (hex.terrainLevel(Terrains.WATER) <= 0) || hex.containsTerrain(Terrains.ICE); case IEntityMovementMode.SUBMARINE: return (hex.terrainLevel(Terrains.WATER) <= 0); default : return false; } } public void lockTurret() { m_bTurretLocked = true; } public int getStunnedTurns() { return m_nStunnedTurns; } public void setStunnedTurns( int turns ) { m_nStunnedTurns = turns; this.crew.setUnconscious(true); } public void stunCrew() { setStunnedTurns( 3 ); } public int getJammedTurns() { return m_nJammedTurns; } public void setJammedTurns( int turns ) { // Set the jammed gun, if none are currently jammed. if ( null == m_jammedGun ) { m_jammedGun = this.getMainWeapon(); // We *may* be in the middle of de-serializing this tank. if ( null != m_jammedGun ) { m_jammedGun.setJammed(true); } } m_nJammedTurns = turns; } public void applyDamage() { m_bImmobile |= m_bImmobileHit; } public void newRound(int roundNumber) { super.newRound(roundNumber); // check for crew stun if (m_nStunnedTurns > 0) { m_nStunnedTurns--; if (m_nStunnedTurns == 0) { this.crew.setUnconscious(false); } } // check for weapon jam if (m_jammedGun != null) { if (m_nJammedTurns > 0) { m_nJammedTurns--; } else { m_jammedGun.setJammed(false); m_jammedGun = null; } } // reset turret facing, if not jammed if (!m_bTurretLocked) { setSecondaryFacing(getFacing()); } } /** * This is only used for the 'main weapon' vehicle critical result. * No standard for 'mainness' is given (although it's also described * as the 'largest', so maybe it's tonnage). I'm going with the highest * BV non-disabled weapon (even if it's out of ammo) */ public Mounted getMainWeapon() { double fBestBV = -1; Mounted mBest = null; for (Mounted m : getWeaponList()) { if (m.isDestroyed()) continue; double fValue = m.getType().getBV(this); if (fValue > fBestBV) { fBestBV = fValue; mBest = m; } } return mBest; } /** * Returns the name of the type of movement used. * This is tank-specific. */ public String getMovementString(int mtype) { switch(mtype) { case IEntityMovementType.MOVE_SKID : return "Skidded"; case IEntityMovementType.MOVE_NONE : return "None"; case IEntityMovementType.MOVE_WALK : return "Cruised"; case IEntityMovementType.MOVE_RUN : return "Flanked"; case IEntityMovementType.MOVE_JUMP : return "Jumped"; default : return "Unknown!"; } } /** * Returns the name of the type of movement used. * This is tank-specific. */ public String getMovementAbbr(int mtype) { switch(mtype) { case IEntityMovementType.MOVE_SKID : return "S"; case IEntityMovementType.MOVE_NONE : return "N"; case IEntityMovementType.MOVE_WALK : return "C"; case IEntityMovementType.MOVE_RUN : return "F"; case IEntityMovementType.MOVE_JUMP : return "J"; default : return "?"; } } public boolean hasRearArmor(int loc) { return false; } /** * Returns the Compute.ARC that the weapon fires into. */ public int getWeaponArc(int wn) { final Mounted mounted = getEquipment(wn); switch (mounted.getLocation()) { case LOC_FRONT: case LOC_TURRET: case LOC_BODY: // Body mounted C3Ms fire into the front arc, // per http://forums.classicbattletech.com/index.php/topic,9400.0.html return Compute.ARC_FORWARD; case LOC_RIGHT: return Compute.ARC_RIGHTSIDE; case LOC_LEFT: return Compute.ARC_LEFTSIDE; case LOC_REAR: return Compute.ARC_REAR; 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) { if (getEquipment(weaponId).getLocation() == LOC_TURRET) { return true; } return false; } /** * Rolls up a hit location */ public HitData rollHitLocation(int table, int side, int aimedLocation, int aimingMode) { return rollHitLocation(table, side); } public HitData rollHitLocation(int table, int side) { int nArmorLoc = LOC_FRONT; boolean bSide = false; if (side == ToHitData.SIDE_FRONT && isHullDown() && !m_bHasNoTurret) { //on a hull down vee, all front hits go to turret if one exists. nArmorLoc = LOC_TURRET; } if (side == ToHitData.SIDE_LEFT) { nArmorLoc = LOC_LEFT; bSide = true; } else if (side == ToHitData.SIDE_RIGHT) { nArmorLoc = LOC_RIGHT; bSide = true; } else if (side == ToHitData.SIDE_REAR) { nArmorLoc = LOC_REAR; } switch (Compute.d6(2)) { case 2: return new HitData(nArmorLoc, false, HitData.EFFECT_CRITICAL); case 3: return new HitData(nArmorLoc, false, HitData.EFFECT_VEHICLE_MOVE_DESTROYED); case 4: return new HitData(nArmorLoc, false, HitData.EFFECT_VEHICLE_MOVE_DAMAGED); case 5: if (bSide || getMovementMode() == IEntityMovementMode.HOVER || getMovementMode() == IEntityMovementMode.HYDROFOIL) { return new HitData(nArmorLoc, false, HitData.EFFECT_VEHICLE_MOVE_DAMAGED); } return new HitData(nArmorLoc); case 6: case 7: case 8: return new HitData(nArmorLoc); case 9: if (bSide && ((getMovementMode() == IEntityMovementMode.HOVER) || (getMovementMode() == IEntityMovementMode.HYDROFOIL))) { return new HitData(nArmorLoc, false, HitData.EFFECT_VEHICLE_MOVE_DAMAGED); } return new HitData(nArmorLoc); case 10: if (m_bHasNoTurret) { return new HitData(nArmorLoc); } return new HitData(LOC_TURRET); case 11: if (m_bHasNoTurret) { return new HitData(nArmorLoc); } return new HitData(LOC_TURRET, false, HitData.EFFECT_VEHICLE_TURRETLOCK); case 12: if (m_bHasNoTurret || bSide) { return new HitData(nArmorLoc, false, HitData.EFFECT_CRITICAL); } return new HitData(LOC_TURRET, false, HitData.EFFECT_CRITICAL); } return null; } /** * Gets the location that excess damage transfers to */ public HitData getTransferLocation(HitData hit) { return new HitData(LOC_DESTROYED); } /** * Gets the location that is destroyed recursively */ public int getDependentLocation(int loc) { return LOC_NONE; } /** * Calculates the battle value of this mech */ public int calculateBattleValue() { return calculateBattleValue(false); } /** * Calculates the battle value of this tank */ public int calculateBattleValue(boolean assumeLinkedC3) { double dbv = 0; // defensive battle value double obv = 0; // offensive bv // total armor points dbv += getTotalArmor(); // total internal structure dbv += getTotalInternal() / 2.0; // add defensive equipment double dEquipmentBV = 0; for (Mounted mounted : getEquipment()) { EquipmentType etype = mounted.getType(); // don't count destroyed equipment if (mounted.isDestroyed()) continue; if ((etype instanceof WeaponType && etype.hasFlag(WeaponType.F_AMS)) || (etype instanceof AmmoType && ((AmmoType)etype).getAmmoType() == AmmoType.T_AMS) || etype.hasFlag(MiscType.F_ECM)) { dEquipmentBV += etype.getBV(this); } } dbv += dEquipmentBV; double typeModifier; switch (getMovementMode()) { case IEntityMovementMode.TRACKED: typeModifier = 0.8; break; case IEntityMovementMode.WHEELED:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -