/** * Returns a new coordinate that represents the coordinate 1 unit in the * specified direction. * * @return the new coordinate, if the direction is valid; otherwise, a new * copy of this coordinate. * @param dir the direction. */ public final Coords translated(int dir) { return translated(dir, 1); }
/** * * STUFF FOR VECTOR MOVEMENT CALCULATIONS ** */ public static Coords getFinalPosition(Coords curpos, int[] v) { if ((v == null) || (v.length != 6)) { return curpos; } // step through each vector and move the direction indicated int thrust = 0; Coords endpos = curpos; for (int dir = 0; dir < 6; dir++) { thrust = v[dir]; while (thrust > 0) { endpos = endpos.translated(dir); thrust--; } } return endpos; }
/** * Convenience function that returns a list of all adjacent coordinates, regardless of whether they're on the board or not. * @return List of adjacent coordinates. */ public final List<Coords> allAdjacent() { List<Coords> retVal = new ArrayList<>(); for(int dir = 0; dir < 6; dir++) { retVal.add(translated(dir)); } return retVal; }
/** * Gets a ring of hexes at a specified distance from the centre * * @param centre The centre point of the ring * @param range The radius of the ring */ public static ArrayList<Coords> coordsAtRange(Coords centre, int range) { ArrayList<Coords> result = new ArrayList<Coords>(range * 6); if (range < 1) { result.add(centre); return result; } for (int dir = 0; dir < 6; dir++) { Coords corner = centre.translated(dir, range); for (int count = 0; count < range; count++) { result.add(corner); corner = corner.translated((dir + 2) % 6); } } return result; }
/** * Gets all hexes that form a larger hex around the given coordinates with the given "radius". * @param coords The coordinates around which we want to draw the donut * @param radius The donut's radius. 0 returns a single hex. * @return */ public static Set<Coords> getHexDonut(Coords coords, int radius) { Set<Coords> retval = new HashSet<>(); // algorithm outline: travel to the southwest a number of hexes equal to the radius // then, "draw" the hex sides in sequence, moving north first to draw the west side, // then rotating clockwise and moving northeast to draw the northwest side and so on, until we circle around. // the length of a hex side is equivalent to the radius Coords currentHex = coords.translated(4, radius); retval.add(currentHex); if(radius == 0) { return retval; } for(int direction = 0; direction < 6; direction++) { for(int translation = 0; translation < radius; translation++) { currentHex = currentHex.translated(direction); retval.add(currentHex); } } return retval; }
/** * scatter from a hex according, roll d6 to choose scatter direction * * @param coords The <code>Coords</code> to scatter from * @param margin the <code>int</code> margin of failure, scatter distance will * be the margin of failure * @return the <code>Coords</code> scattered to */ public static Coords scatter(Coords coords, int margin) { int scatterDirection = Compute.d6(1) - 1; return coords.translated(scatterDirection, margin); }
/** * Can the defending unit be displaced from the source to the destination? */ public static boolean isValidDisplacement(IGame game, int entityId, Coords src, int direction) { return Compute.isValidDisplacement(game, entityId, src, src.translated(direction)); }
public final Coords translated(String dir) { int intDir = 0; try { intDir = Integer.parseInt(dir); } catch (NumberFormatException nfe) { if (dir.equalsIgnoreCase("N")) { intDir = 0; } else if (dir.equalsIgnoreCase("NE")) { intDir = 1; } else if (dir.equalsIgnoreCase("SE")) { intDir = 2; } else if (dir.equalsIgnoreCase("S")) { intDir = 3; } else if (dir.equalsIgnoreCase("SW")) { intDir = 4; } else if (dir.equalsIgnoreCase("NW")) { intDir = 5; } } return translated(intDir); }
@Override public void setPosition(Coords position) { HashSet<Coords> oldPositions = getOccupiedCoords(); super.setPosition(position, false); if ((getAltitude() == 0) && (null != game) && !game.getBoard().inSpace() && (position != null)) { secondaryPositions.put(0, position); secondaryPositions.put(1, position.translated(getFacing())); secondaryPositions.put(2, position.translated((getFacing() + 1) % 6)); secondaryPositions.put(3, position.translated((getFacing() + 2) % 6)); secondaryPositions.put(4, position.translated((getFacing() + 3) % 6)); secondaryPositions.put(5, position.translated((getFacing() + 4) % 6)); secondaryPositions.put(6, position.translated((getFacing() + 5) % 6)); } if (game != null) { game.updateEntityPositionLookup(this, oldPositions); } }
/** * scatter from hex according to atmospheric drop rules d6 for direction, * 1d6 per point of MOF * * @param coords The <code>Coords</code> to scatter from * @param margin the <code>int</code> margin of failure * @return the <code>Coords</code> scattered to */ public static Coords scatterAssaultDrop(Coords coords, int margin) { int scatterDirection = Compute.d6(1) - 1; int distance = Compute.d6(margin); return coords.translated(scatterDirection, distance); }
/** * Returns the first further hex found along the line from the centers of * src to dest. Checks the three directions given and returns the closest. * This relies on the side directions being given first. If it checked the * center first, it would end up missing the side hexes sometimes. Not the * most elegant solution, but it works. */ public static Coords nextHex(Coords current, IdealHex iSrc, IdealHex iDest, int[] directions) { for (int direction : directions) { Coords testing = current.translated(direction); if (IdealHex.get(testing).isIntersectedBy(iSrc.cx, iSrc.cy, iDest.cx, iDest.cy)) { return testing; } } // if we're here then something's fishy! throw new RuntimeException("Couldn't find the next hex!"); }
/** * Moves the position one hex in the direction indicated. Does not change * facing. * * @param dir */ public void moveInDir(int dir) { position = position.translated(dir); if (!getGame().getBoard().contains(position)) { throw new RuntimeException("Coordinate off the board."); } }
@Override public void setAltitude(int altitude) { super.setAltitude(altitude); if ((getAltitude() == 0) && (game != null) && !game.getBoard().inSpace() && (getPosition() != null)) { secondaryPositions.put(0, getPosition()); secondaryPositions.put(1, getPosition().translated(getFacing())); secondaryPositions.put(2, getPosition().translated((getFacing() + 1) % 6)); secondaryPositions.put(3, getPosition().translated((getFacing() + 2) % 6)); secondaryPositions.put(4, getPosition().translated((getFacing() + 3) % 6)); secondaryPositions.put(5, getPosition().translated((getFacing() + 4) % 6)); secondaryPositions.put(6, getPosition().translated((getFacing() + 5) % 6)); } }
@Override public void performAction() { int curDir = cmd.getFinalFacing(); int dir = curDir; dir = (dir + 5) % 6; Coords curPos = cmd.getFinalCoords(); Coords target = curPos.translated(dir); // We need to set this to get the rotate behavior shiftheld = true; currentMove(target); shiftheld = false; clientgui.bv.drawMovementData(ce(), cmd); } });
@Override public void performAction() { int curDir = cmd.getFinalFacing(); int dir = curDir; dir = (dir + 7) % 6; Coords curPos = cmd.getFinalCoords(); Coords target = curPos.translated(dir); // We need to set this to get the rotate behavior shiftheld = true; currentMove(target); shiftheld = false; clientgui.bv.drawMovementData(ce(), cmd); } });
/** * Convenience function encapsulating logic for whether, if we continue forward * along the current path in the current direction, we will run off the board * @return */ public boolean nextForwardStepOffBoard() { return !game.getBoard().contains(getFinalCoords().translated(getFinalFacing())); } }
private static void findCliffNeighbours(IBoard board, Coords c, ArrayList<Coords> candidate, HashSet<Coords> ignore) { candidate.add(c); ignore.add(c); int elevation = board.getHex(c).getLevel(); for (int dir = 0; dir < 6; dir++) { Coords t = c.translated(dir); if (board.contains(t) && !ignore.contains(t)) { if (hexCouldBeCliff(board, t)) { IHex hex = board.getHex(t); int el = hex.getLevel(); if (el == elevation) { findCliffNeighbours(board, t, candidate, ignore); } } else { ignore.add(t); } } } }
@Override public String hasRoomForVerticalLanding() { // dropships can land just about anywhere they want, unless it is off // the map Vector<Coords> positions = new Vector<Coords>(); positions.add(getPosition()); for (int i = 0; i < 6; i++) { positions.add(getPosition().translated(i)); } for (Coords pos : positions) { IHex hex = game.getBoard().getHex(getPosition()); hex = game.getBoard().getHex(pos); // if the hex is null, then we are offboard. Don't let units // land offboard. if (null == hex) { return "landing area not on the map"; } if (hex.containsTerrain(Terrains.WATER)) { return "cannot land on water"; } } // TODO: what about other terrain (like jungles)? return null; }
private static boolean hexCouldBeCliff(IBoard board, Coords c) { int elevation = board.getHex(c).getLevel(); boolean higher = false; boolean lower = false; int count = 0; for (int dir = 0; dir < 6; dir++) { Coords t = c.translated(dir); if (board.contains(t)) { IHex hex = board.getHex(t); int el = hex.getLevel(); if (el > elevation) { lower = true; } else if (el < elevation) { higher = true; } else { count++; } } } return higher && lower && (count <= 3) && (count > 0); }
@Override public boolean handle(IGame.Phase phase, Vector<Report> vPhaseReport) { if (game.getOptions().booleanOption(OptionsConstants.ADVCOMBAT_TACOPS_START_FIRE) && (game.getPlanetaryConditions().getAtmosphere() >= PlanetaryConditions.ATMO_TRACE)) { int rear = (ae.getFacing() + 3 + (weapon.isMechTurretMounted() ? weapon .getFacing() : 0)) % 6; Coords src = ae.getPosition(); Coords rearCoords = src.translated(rear); IBoard board = game.getBoard(); IHex currentHex = board.getHex(src); if (!board.contains(rearCoords)) { rearCoords = src; } else if (board.getHex(rearCoords).getLevel() > currentHex .getLevel()) { rearCoords = src; } else if ((board.getBuildingAt(rearCoords) != null) && ((board.getHex(rearCoords).terrainLevel( Terrains.BLDG_ELEV) + board.getHex(rearCoords) .getLevel()) > currentHex.getLevel())) { rearCoords = src; } server.createSmoke(rearCoords, SmokeCloud.SMOKE_HEAVY, 2); } return super.handle(phase, vPhaseReport); }