@Override public boolean shouldStay(MovePath mp) { return (mp.getMpUsed() <= maxMP); } }
/** * Worker function to determine whether we should discard the current path * (due to it being illegal or redundant) or keep generating child nodes * @param path The move path to consider * @return Whether to keep or dicsard. */ protected boolean discardPath(MovePath path, CoordsWithFacing pathDestination) { boolean maxMPExceeded = path.getMpUsed() > path.getEntity().getRunMP(); // having generated the child, we add it and (recursively) any of its children to the list of children to be returned // unless it is illegal or exceeds max MP, in which case we discard it // (max mp is maybe redundant)? if(!path.isMoveLegal() || maxMPExceeded) { return true; } // terminator conditions: // we've visited this hex already and the path we are considering is longer than the previous path that visited this hex if(visitedCoords.containsKey(pathDestination) && visitedCoords.get(pathDestination).intValue() < path.getMpUsed()) { return true; } return false; }
/** * Generates a list of possible step combinations that should be done at the beginning of a path * Has side effect of updating the visited coordinates map and adding it to the list of generated paths * @return List of all possible "starting" paths */ protected List<MovePath> generateStartingPaths(MovePath startingEdge) { List<MovePath> startingPaths = new ArrayList<>(); MovePath defaultPath = startingEdge.clone(); aerospacePaths.add(defaultPath); visitedCoords.put(new CoordsWithFacing(defaultPath), defaultPath.getMpUsed()); startingPaths.add(defaultPath); MovePath reverseEdge = startingEdge.clone(); reverseEdge.addStep(MoveStepType.YAW); aerospacePaths.add(reverseEdge); visitedCoords.put(new CoordsWithFacing(reverseEdge), reverseEdge.getMpUsed()); startingPaths.add(defaultPath); return startingPaths; }
/** * Determines whether or not the given move path is "redundant". * In this situation, "redundant" means "there is already a shorter path that goes to the ending coordinates/facing/height" combo. */ @Override protected boolean pathIsRedundant(MovePath mp) { if(!mp.fliesOffBoard()) { CoordsWithFacing destinationCoords = new CoordsWithFacing(mp); if(!visitedCoords.containsKey(destinationCoords)) { visitedCoords.put(destinationCoords, new HashMap<>()); } // we may or may not have been to these coordinates before, but we haven't been to this height. Not redundant. if(!visitedCoords.get(destinationCoords).containsKey(mp.getFinalAltitude())) { visitedCoords.get(destinationCoords).put(mp.getFinalAltitude(), mp.getMpUsed()); return false; // we *have* been to these coordinates and height before. This is redundant if the previous visit used less MP. } else { return visitedCoords.get(destinationCoords).get(mp.getFinalAltitude()) < mp.getMpUsed(); } } else { return false; } } }
/** * Compares MovePaths based on distance from final position to * destination. If those distances are equal then spent movement points * are compared. * */ @Override public int compare(MovePath mp1, MovePath mp2) { int d1 = mp1.getFinalCoords().distance(destination); int d2 = mp2.getFinalCoords().distance(destination); if (d1 != d2) return d1 - d2; else return mp1.getMpUsed() - mp2.getMpUsed(); } }
public int compare(final MovePath first, final MovePath second) { final int firstDist = first.getMpUsed() + first.getFinalCoords().distance(destination) + getFacingDiff(first); final int secondDist = second.getMpUsed() + second.getFinalCoords().distance(destination) + getFacingDiff(second); return firstDist - secondDist; }
/** * Worker function to determine whether we should discard the current path * (due to it being illegal or redundant) or keep generating child nodes * @param path The move path to consider * @return Whether to keep or dicsard. */ @Override protected boolean discardPath(MovePath path, CoordsWithFacing pathDestination) { boolean maxMPExceeded = path.getMpUsed() > path.getEntity().getRunMP(); // having generated the child, we add it and (recursively) any of its children to the list of children to be returned // unless it moves too far or exceeds max thrust if(path.getFinalVelocityLeft() < 0 || maxMPExceeded) { return true; } // terminator conditions: // we've visited this hex already and the path we are considering is longer than the previous path that visited this hex if(visitedCoords.containsKey(pathDestination) && visitedCoords.get(pathDestination).intValue() < path.getMpUsed()) { return true; } // there's no reason to consider off-board paths in the standard flight model. if(!path.getGame().getBoard().contains(pathDestination.getCoords())) { return true; } return false; } }
/** * compares MovePaths based on lexicographical order of triples ( hexes * traveled; thrust used; 0-( hexes flown in a straight line ) ) * */ @Override public int compare(MovePath mp1, MovePath mp2) { if (!mp1.getEntity().isAero()) { throw new IllegalArgumentException("wanted aero got:" + mp1.getClass().toString()); } //we want to process shorter paths first int dHT = mp1.getHexesMoved() - mp2.getHexesMoved(); if (dHT != 0) { return dHT; } //then those which used less thrust int dMP = mp1.getMpUsed() - mp2.getMpUsed(); if (dMP != 0) { return dMP; } //lastly those with more hexes flown straight. MoveStep lms1 = mp1.getLastStep(), lms2 = mp2.getLastStep(); int hs1 = lms1 == null ? 0 : lms1.getNStraight(); int hs2 = lms2 == null ? 0 : lms2.getNStraight(); int dHS = hs1 - hs2; return -dHS; } }
private void updateRACButton() { final Entity ce = ce(); if (null == ce) { return; } GameOptions opts = clientgui.getClient().getGame().getOptions(); setUnjamEnabled(ce.canUnjamRAC() && ((gear == MovementDisplay.GEAR_LAND) || (gear == MovementDisplay.GEAR_TURN) || (gear == MovementDisplay.GEAR_BACKUP)) && ((cmd.getMpUsed() <= ce.getWalkMP()) || (cmd.getLastStep().isOnlyPavement() && (cmd.getMpUsed() <= (ce.getWalkMP() + 1)))) && !(opts.booleanOption("tacops_tank_crews") && (cmd.getMpUsed() > 0) && (ce instanceof Tank) && (ce.getCrew().getSize() < 2))); }
/** * Helper function that appends an unjam RAC command to the end of a qualifying path. * @param path The path to process. */ private void unjamRAC(MovePath path) { if(path.getEntity().canUnjamRAC() && (path.getMpUsed() <= path.getEntity().getWalkMP()) && !path.isJumping()) { path.addStep(MoveStepType.UNJAM_RAC); } }
/** * A quick determination that checks the given path for the most common causes of a PSR and whether it leads us off board. * The idea being that a safe path off board should not include any PSRs. * @param movePath The path to check * @return True or false */ public static boolean isSafePathOffBoard(MovePath movePath) { // common causes of PSR include, but are not limited to: // stalling your aircraft // crashing your aircraft into the ground // executing maneuvers // thrusting too hard // see your doctor if you experience any of these symptoms as it may lead to your aircraft transforming into a lawn dart return !willStall(movePath) && !willCrash(movePath) && movePath.fliesOffBoard() && !movePath.contains(MoveStepType.MANEUVER) && (movePath.getMpUsed() <= movePath.getEntity().getWalkMP()) && (movePath.getEntity().isAero() && (movePath.getMpUsed() <= ((IAero) movePath.getEntity()).getSI())); }
/** * Helper function that insinuates an "evade" step for aircraft that will not be shooting. * @param path The path to process */ private void evadeIfNotFiring(MovePath path, boolean possibleToInflictDamage) { Entity pathEntity = path.getEntity(); // we cannot evade if we are out of control if(pathEntity.isAero() && pathEntity.isAirborne() && ((IAero) pathEntity).isOutControlTotal()) { return; } // if we're an airborne aircraft // and we're not going to do any damage anyway // and we can do so without causing a PSR // then evade if(pathEntity.isAirborne() && !possibleToInflictDamage && (path.getMpUsed() <= AeroPathUtil.calculateMaxSafeThrust((IAero) path.getEntity()) - 2)) { path.addStep(MoveStepType.EVADE); } }
&& (movePath.getMpUsed() == 0) && !movePath.contains(MoveStepType.VLAND)) { return true;
altitudePath.getMpUsed() < maxThrust - 1) { altitudePath.addStep(MoveStepType.UP);
public boolean canShift() { return ((getEntity() instanceof QuadMech // QuadVee cannot shift in vee mode && !(getEntity() instanceof QuadVee && (entity.getConversionMode() == QuadVee.CONV_MODE_VEHICLE || getEntity().isConvertingNow()))) // Maneuvering Ace allows Bipeds and VTOLs moving at cruise // speed to perform a lateral shift || (getEntity().isUsingManAce() && ((getEntity() instanceof BipedMech) || ((getEntity() instanceof VTOL) && (getMpUsed() <= getEntity().getWalkMP())))) || (game.getOptions().booleanOption(OptionsConstants.ADVGRNDMOV_VEHICLE_ADVANCED_MANEUVERS) && getEntity() instanceof Tank && (getEntity().getMovementMode() == EntityMovementMode.VTOL || getEntity().getMovementMode() == EntityMovementMode.HOVER)) || ((getEntity() instanceof TripodMech) && (((Mech) getEntity()).countBadLegs() == 0))) && !isJumping(); }
private synchronized void updateElevationButtons() { final Entity ce = ce(); if (null == ce) { return; } if (ce.isAirborne()) { // then use altitude not elevation setRaiseEnabled(ce.canGoUp(cmd.getFinalAltitude(), cmd.getFinalCoords())); setLowerEnabled(ce.canGoDown(cmd.getFinalAltitude(), cmd.getFinalCoords())); return; } // WiGEs (and LAMs and glider protomechs) cannot go up if they've used ground movement. if ((ce.getMovementMode() == EntityMovementMode.WIGE) && !ce.isAirborneVTOLorWIGE() && (cmd.getMpUsed() > 0) && !cmd.contains(MoveStepType.UP)) { setRaiseEnabled(false); } else { setRaiseEnabled(ce.canGoUp(cmd.getFinalElevation(), cmd.getFinalCoords())); } setLowerEnabled(ce.canGoDown(cmd.getFinalElevation(), cmd.getFinalCoords())); }