/* * Copyright 2005 (C) Tom Parker <thpr@sourceforge.net> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Created on July 22, 2005. * * Current Ver: $Revision$ */ package pcgen.core; import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.StringTokenizer; import pcgen.util.Logging; /** * @author Tom Parker <thpr@sourceforge.net> */ public class Movement { /** * Contains the movement Types for this Movement (e.g. "Walk", "Fly") */ private final String[] movementTypes; /** * Contains the associated movement rate (in feet) for the movement type of * the same index. A movement rate must be greater than or equal to zero. */ private final double[] movements; /** * The movement multiplier for the movement type of the same index. A * movement Multiplier be greater than zero. */ private final double[] movementMult; /** * The movement operation for the movement type of the same index. (e.g. "*" * or "/") */ private final String[] movementMultOp; /* * A class invariant is that the four above arrays should always have the * same length. */ /** * The Movement Rates flag indicating which type of Movement object this is * 0 indicates a basic assignment * 2 indicates this clones one movement rate into another movement rate */ private int moveRatesFlag; /** * The index within the movements array indicating the default movement type * ("Walk") */ private int movement; /** * Creates a Movement object with arrays of the given length. It is assumed * that the user of this constructor will initialize all of the arrays, as * this constructor does not perform initialization. * * @param i * The length of the movement arrays to be assigned. */ public Movement(int i) { if (i <= 0) { throw new IllegalArgumentException( "Argument of array length to ConcreteMovement" + "constructor must be positive"); } movementTypes = new String[i]; movements = new double[i]; movementMult = new double[i]; movementMultOp = new String[i]; // default the basic movement to the first movement type, if the creature has a // walk speed in some entry other than 0 this will be changed by the assign // movement operation. movement = 0; } /** * Sets the Move Rates Flag on this Movement object. * * @param i * The move rates flag. */ public void setMoveRatesFlag(int i) { if (i != 0 && i != 2) { throw new IllegalArgumentException("Rate Flag must be 0 or 2"); } moveRatesFlag = i; } /** * Gets the Movement Rates Flag for this Movement object. * @return move rates flag */ public int getMoveRatesFlag() { return moveRatesFlag; } /** * Return the creature's basic movement, this will be set to the walk * speed (if the creature has one) by the assign movement operation. * If no walk speed is assigned to the creature then the first movement * defined is returned. * @return movement as a Double */ public Double getDoubleMovement() { return movements[movement]; } /** * Get a movement multiplier * @param index of the specified movement multiplier * @return a movement multiplier */ public double getMovementMult(int index) { return movementMult[index]; } /** * a movement multiplier operator * @param index of the specified movement * @return a movement multiplier operator */ public String getMovementMultOp(int index) { return movementMultOp[index]; } /** * Get all of the movement multipliers * @return clone of the movement multipliers array */ public double[] getMovementMult() { return movementMult.clone(); } /** * Get all of the movement multiplier operators * @return clone of the movement multiplier operators array */ public String[] getMovementMultOp() { return movementMultOp.clone(); } /** * Get the number of movement types * @return the number of movement types */ public int getNumberOfMovementTypes() { return movementTypes.length; } /** * Get the movement type from the array * @param i * @return movement type */ public String getMovementType(int i) { return (i < movementTypes.length) ? movementTypes[i] : ""; } /** * Get the movement types * @return the movement types */ public String[] getMovementTypes() { return movementTypes.clone(); } /** * Get the movement at index i * @param i * @return the movement at index i or 0 */ public double getMovement(int i) { return (i < movements.length) ? movements[i] : 0.0d; } /** * Get the number of movements * @return number of movements */ public int getNumberOfMovements() { return movements.length; } /** * Get movements * @return movements */ public double[] getMovements() { return movements.clone(); } /** * Provides a String representation of this Movement object, suitable for * display to a user. * @return String */ @Override public String toString() { final StringBuilder movelabel = new StringBuilder(); if (movementTypes.length > 0) { movelabel.append(movementTypes[0]); NumberFormat numFmt = NumberFormat.getNumberInstance(); movelabel.append(' ').append( numFmt.format(Globals.getGameModeUnitSet() .convertDistanceToUnitSet(movements[0]))); movelabel.append(Globals.getGameModeUnitSet().getDistanceUnit()); if (movementMult[0] != 0) { movelabel.append('(').append(movementMultOp[0]) .append(numFmt.format(movementMult[0])).append(')'); } for (int i = 1; i < movementTypes.length; ++i) { movelabel.append(", "); movelabel.append(movementTypes[i]); movelabel.append(' ').append( numFmt.format(Globals.getGameModeUnitSet() .convertDistanceToUnitSet(movements[i]))); movelabel .append(Globals.getGameModeUnitSet().getDistanceUnit()); if (movementMult[i] != 0) { movelabel.append('(').append(movementMultOp[i]) .append(numFmt.format(movementMult[i])).append(')'); } } } return movelabel.toString(); } public void addTokenContents(StringBuilder txt) { if (moveRatesFlag == 2) { txt.append(movementTypes[0]); txt.append(','); txt.append(movementTypes[1]); txt.append(','); if (!movementMultOp[1].isEmpty()) { String multValue = NumberFormat.getNumberInstance() .format(movementMult[1]); txt.append(movementMultOp[1]).append(multValue); } else { txt.append(new DecimalFormat("###0").format(movements[1])); } return; } for (int index = 0; index < movementTypes.length; ++index) { if (index > 0) { txt.append(','); } if ((movementTypes[index] != null) && (!movementTypes[index].isEmpty())) { txt.append(movementTypes[index]).append(','); } if (!movementMultOp[index].isEmpty()) { txt.append(movementMultOp[index]).append(movementMult[index]); } else { txt.append(new DecimalFormat("###0").format(movements[index])); } } } /** * Returns a Movement object initialized from the given string. This string * can be any legal string for the MOVE or MOVECLONE tags. The object which * calls getMovementFrom MUST subsequently assign the move rates flag of the * returned Movement in order for the Movement to function properly. (The * default move rates flag is zero, so assignment in that case is not * necessary) * * @param moveparse * The String from which a new Movement should be initialized * @return A new Movement initialized from the given String. */ public static Movement getMovementFrom(final String moveparse) { if (moveparse == null) { throw new IllegalArgumentException( "Null initialization String illegal"); } final StringTokenizer moves = new StringTokenizer(moveparse, ","); Movement cm; if (moves.countTokens() == 1) { cm = new Movement(1); cm.assignMovement(0, "Walk", moves.nextToken()); } else { cm = new Movement(moves.countTokens() / 2); int x = 0; while (moves.countTokens() > 1) { cm.assignMovement(x++, moves.nextToken(), moves.nextToken()); } if (moves.countTokens() != 0) { Logging.errorPrint("Badly formed MOVE token " + "(extra value at end of list): " + moveparse); } } return cm; } public void assignMovement(int x, String type, String mod) { movementTypes[x] = type; // e.g. "Walk" movementMult[x] = 0.0d; movementMultOp[x] = ""; if ((!mod.isEmpty()) && ((mod.charAt(0) == '*') || (mod.charAt(0) == '/'))) { movements[x] = 0.0d; try { double multValue = Double.parseDouble(mod.substring(1)); if (multValue < 0) { Logging.errorPrint("Illegal movement multiplier: " + multValue + " in movement string " + mod); } movementMult[x] = multValue; movementMultOp[x] = mod.substring(0, 1); } catch (NumberFormatException e) { Logging.errorPrint("Badly formed MOVE token: " + mod); movementMult[x] = 0.0d; movementMultOp[x] = ""; } } else if (!mod.isEmpty()) { movementMult[x] = 0.0d; movementMultOp[x] = ""; try { movements[x] = Double.parseDouble(mod); } catch (NumberFormatException e) { Logging.errorPrint("Badly formed MOVE token: " + mod); movements[x] = 0.0d; } if ("Walk".equals(movementTypes[x])) { movement = x; } } } }