📄 compute.java
字号:
/* * MegaMek - * Copyright (C) 2000,2001,2002,2003,2004,2005 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.util.ArrayList;import java.util.Enumeration;import java.util.Iterator;import java.util.Vector;import megamek.common.Coords;import megamek.common.actions.BreakGrappleAttackAction;import megamek.common.actions.BrushOffAttackAction;import megamek.common.actions.ClubAttackAction;import megamek.common.actions.GrappleAttackAction;import megamek.common.actions.JumpJetAttackAction;import megamek.common.actions.KickAttackAction;import megamek.common.actions.LayExplosivesAttackAction;import megamek.common.actions.ProtomechPhysicalAttackAction;import megamek.common.actions.PunchAttackAction;import megamek.common.actions.PushAttackAction;import megamek.common.actions.ThrashAttackAction;import megamek.common.actions.TripAttackAction;import megamek.common.actions.WeaponAttackAction;/** * The compute class is designed to provide static methods for mechs and other * entities moving, firing, etc. */public class Compute { public static final int ARC_360 = 0; public static final int ARC_FORWARD = 1; public static final int ARC_LEFTARM = 2; public static final int ARC_RIGHTARM = 3; public static final int ARC_REAR = 4; public static final int ARC_LEFTSIDE = 5; public static final int ARC_RIGHTSIDE = 6; public static final int ARC_MAINGUN = 7; public static final int ARC_NORTH = 8; public static final int ARC_EAST = 9; public static final int ARC_WEST = 10; private static MMRandom random = MMRandom.generate(MMRandom.R_DEFAULT); private static final int[][] clusterHitsTable = new int[][] { { 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2 }, { 3, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3 }, { 4, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4 }, { 5, 1, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5 }, { 6, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6 }, //{ 7, 2, 2, 3, 4, 4, 4, 4, 6, 6, 7, 7 }, { 8, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 8 }, { 9, 3, 3, 4, 5, 5, 5, 5, 7, 7, 9, 9 }, { 10, 3, 3, 4, 6, 6, 6, 6, 8, 8, 10, 10 }, //{ 11, 4, 4, 5, 7, 7, 7, 7, 9, 9, 11, 11 }, { 12, 4, 4, 5, 8, 8, 8, 8, 10, 10, 12, 12 }, //{ 13, 4, 4, 5, 8, 8, 8, 8, 11, 11, 13, 13 }, //{ 14, 5, 5, 6, 9, 9, 9, 9, 11, 11, 14, 14 }, { 15, 5, 5, 6, 9, 9, 9, 9, 12, 12, 15, 15 }, //{ 16, 5, 5, 7, 10, 10, 10, 10, 13, 13, 16, 16 }, //{ 17, 5, 5, 7, 10, 10, 10, 10, 14, 14, 17, 17 }, //{ 18, 6, 6, 8, 11, 11, 11, 11, 14, 14, 18, 18 }, //{ 19, 6, 6, 8, 11, 11, 11, 11, 15, 15, 19, 19 }, { 20, 6, 6, 9, 12, 12, 12, 12, 16, 16, 20, 20 } }; //{ 21, 7, 7, 9, 13, 13, 13, 13, 17, 17, 21, 21 }, //{ 22, 7, 7, 9, 14, 14, 14, 14, 18, 18, 22, 22 }, //{ 23, 7, 7, 10, 15, 15, 15, 15, 19, 19, 23, 23 }, //{ 24, 8, 8, 10, 16, 16, 16, 16, 20, 20, 24, 24 }, //{ 25, 8, 8, 10, 16, 16, 16, 16, 21, 21, 25, 25 }, //{ 26, 9, 9, 11, 17, 17, 17, 17, 21, 21, 26, 26 }, //{ 27, 9, 9, 11, 17, 17, 17, 17, 22, 22, 27, 27 }, //{ 28, 9, 9, 11, 17, 17, 17, 17, 23, 23, 28, 28 }, //{ 29, 10, 10, 12, 18, 18, 18, 18, 23, 23, 29, 29}, //{ 30, 10, 10, 12, 18, 18, 18, 18, 24, 24, 30, 30}, //{ 40, 12, 12, 18, 24, 24, 24, 24, 32, 32, 40, 40} }; /** Wrapper to random#d6(n) */ public static int d6(int dice) { Roll roll = random.d6(dice); return roll.getIntValue(); } /** Wrapper to random#d6() */ public static int d6() { Roll roll = random.d6(); return roll.getIntValue(); } /** Wrapper to random#randomInt(n) */ public static int randomInt(int maxValue) { Roll roll = new MMRoll(random, maxValue); return roll.getIntValue(); } /** * Sets the RNG to the desired type */ public static void setRNG(int type) { random = MMRandom.generate(type); } /** * Returns the odds that a certain number or above will be rolled on 2d6. */ public static double oddsAbove(int n) { if (n <= 2) { return 100.0; } else if (n > 12) { return 0; } final double[] odds = { 100.0, 100.0, 100.0, 97.2, 91.6, 83.3, 72.2, 58.3, 41.6, 27.7, 16.6, 8.3, 2.78, 0 }; return odds[n]; } /** * Returns an entity if the specified entity would cause a stacking * violation entering a hex, or returns null if it would not. * * The returned entity is the entity causing the violation. */ public static Entity stackingViolation(IGame game, int enteringId, Coords coords) { Entity entering = game.getEntity(enteringId); return stackingViolation(game, entering, coords, null); } /** * When compiling an unloading step, both the transporter and the unloaded * unit probably occupy some other position on the board. */ public static Entity stackingViolation(IGame game, Entity entering, Coords coords, Entity transport) { boolean isMech = entering instanceof Mech; Entity firstEntity = transport; int totalUnits = 1; int thisLowStackingLevel = entering.getElevation(); if ((coords != null) && (entering.getPosition() != null)) thisLowStackingLevel = entering.calcElevation(game.getBoard() .getHex(entering.getPosition()), game.getBoard().getHex( coords)); int thisHighStackingLevel = thisLowStackingLevel + entering.height(); // Walk through the entities in the given hex. for (Enumeration i = game.getEntities(coords); i.hasMoreElements();) { final Entity inHex = (Entity) i.nextElement(); int lowStackinglevel = inHex.getElevation(); int highStackingLevel = lowStackinglevel + inHex.height(); // Only do all this jazz if they're close enough together on level // to interfere. if ((thisLowStackingLevel <= highStackingLevel) && (thisHighStackingLevel >= lowStackinglevel)) { // Don't compare the entering entity to itself. if (inHex.equals(entering)) { continue; } // Ignore the transport of the entering entity. if (inHex.equals(transport)) { continue; } // DFAing units don't count towards stacking if (inHex.isMakingDfa()) { continue; } // If the entering entity is a mech, // then any other mech in the hex is a violation. // Unless grappled if (isMech && (inHex instanceof Mech) && ((Mech)inHex).getGrappled() != entering.getId()) { return inHex; } totalUnits++; // If the new one is the most if (totalUnits > 4) { // Arbitrarily return this one, because we can, and it's // simpler. return inHex; } // Otherwise, if there are two present entities controlled // by this player, returns a random one of the two. // Somewhat arbitrary, but how else should we resolve it? if (!inHex.getOwner().isEnemyOf(entering.getOwner())) { if (firstEntity == null) { firstEntity = inHex; } else { return d6() > 3 ? firstEntity : inHex; } } } } // okay, all clear return null; } public static boolean isEnemyIn(IGame game, int entityId, Coords coords, boolean isMech) { return isEnemyIn(game, entityId, coords, isMech, game.getEntity( entityId).getElevation()); } /** * Returns true if there is any unit that is an enemy of the specified unit * in the specified hex. This is only called for stacking purposes, and so * does not return true if the enemy unit is currenly making a DFA. */ public static boolean isEnemyIn(IGame game, int entityId, Coords coords, boolean isMech, int enLowEl) { Entity entity = game.getEntity(entityId); int enHighEl = enLowEl + entity.getHeight(); for (Enumeration i = game.getEntities(coords); i.hasMoreElements();) { final Entity inHex = (Entity) i.nextElement(); int inHexEnLowEl = inHex.getElevation(); int inHexEnHighEl = inHexEnLowEl + inHex.getHeight(); if ((!isMech || inHex instanceof Mech) && inHex.isEnemyOf(entity) && !inHex.isMakingDfa() && (enLowEl <= inHexEnHighEl) && (enHighEl >= inHexEnLowEl)) { return true; } } return false; } /** * @return true if a piloting skill roll is needed to traverse the terrain */ public static boolean isPilotingSkillNeeded(IGame game, int entityId, Coords src, Coords dest, int movementType, boolean isTurning, boolean prevStepIsOnPavement, int srcElevation, int destElevation) { final Entity entity = game.getEntity(entityId); final IHex srcHex = game.getBoard().getHex(src); final IHex destHex = game.getBoard().getHex(dest); final boolean isInfantry = (entity instanceof Infantry); final boolean isPavementStep = canMoveOnPavement(game, src, dest); // arguments valid? if (entity == null) { throw new IllegalArgumentException("Entity invalid."); } if (src.distance(dest) > 1) { throw new IllegalArgumentException("Coordinates must be adjacent."); } // let's only worry about actual movement, please if (src.equals(dest)) { return false; } // check for rubble if (movementType != IEntityMovementType.MOVE_JUMP && destHex.terrainLevel(Terrains.RUBBLE) > 0 && entity.getMovementMode() != IEntityMovementMode.VTOL && !isInfantry) { return true; } // check for swamp if (destHex.containsTerrain(Terrains.SWAMP) && !(entity.getElevation() > destHex.getElevation()) && entity.getMovementMode() != IEntityMovementMode.HOVER && entity.getMovementMode() != IEntityMovementMode.VTOL && movementType != IEntityMovementType.MOVE_JUMP) { return true; } // check for thin ice if (destHex.containsTerrain(Terrains.ICE) && destHex.containsTerrain(Terrains.WATER) && !(entity.getElevation() > destHex.getElevation()) && !isPavementStep && movementType != IEntityMovementType.MOVE_JUMP) { return true; } // Check for water unless we're a hovercraft or naval or using a bridge // or flying. if (movementType != IEntityMovementType.MOVE_JUMP && !(entity.getElevation() > destHex.surface()) && !(entity.getMovementMode() == IEntityMovementMode.HOVER || entity.getMovementMode() == IEntityMovementMode.NAVAL || entity.getMovementMode() == IEntityMovementMode.HYDROFOIL || entity.getMovementMode() == IEntityMovementMode.SUBMARINE || entity.getMovementMode() == IEntityMovementMode.BIPED_SWIM || entity.getMovementMode() == IEntityMovementMode.QUAD_SWIM) && destHex.terrainLevel(Terrains.WATER) > 0 && !isPavementStep) { return true; } // Check for skid. Please note, the skid will be rolled on the // current step, but starts from the previous step's location. // TODO: add check for elevation of pavement, road, // or bridge matches entity elevation. /* * Bug 754610: Revert fix for bug 702735. if ( ( * srcHex.contains(Terrain.PAVEMENT) || srcHex.contains(Terrain.ROAD) || * srcHex.contains(Terrain.BRIDGE) )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -