/* * Copyright (c) 1998-2017 by Richard A. Wilkes. All rights reserved. * * This Source Code Form is subject to the terms of the Mozilla Public * License, version 2.0. If a copy of the MPL was not distributed with * this file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This Source Code Form is "Incompatible With Secondary Licenses", as * defined by the Mozilla Public License, version 2.0. */ package com.trollworks.gcs.weapon; import com.trollworks.gcs.character.GURPSCharacter; import com.trollworks.gcs.common.DataFile; import com.trollworks.gcs.widgets.outline.ListRow; import com.trollworks.toolkit.io.xml.XMLReader; import com.trollworks.toolkit.io.xml.XMLWriter; import com.trollworks.toolkit.utility.text.Numbers; import java.io.IOException; /** The stats for a ranged weapon. */ public class RangedWeaponStats extends WeaponStats { /** The root XML tag. */ public static final String TAG_ROOT = "ranged_weapon"; //$NON-NLS-1$ private static final String TAG_ACCURACY = "accuracy"; //$NON-NLS-1$ private static final String TAG_RANGE = "range"; //$NON-NLS-1$ private static final String TAG_RATE_OF_FIRE = "rate_of_fire"; //$NON-NLS-1$ private static final String TAG_SHOTS = "shots"; //$NON-NLS-1$ private static final String TAG_BULK = "bulk"; //$NON-NLS-1$ private static final String TAG_RECOIL = "recoil"; //$NON-NLS-1$ /** The field ID for accuracy changes. */ public static final String ID_ACCURACY = PREFIX + TAG_ACCURACY; /** The field ID for range changes. */ public static final String ID_RANGE = PREFIX + TAG_RANGE; /** The field ID for rate of fire changes. */ public static final String ID_RATE_OF_FIRE = PREFIX + TAG_RATE_OF_FIRE; /** The field ID for shots changes. */ public static final String ID_SHOTS = PREFIX + TAG_SHOTS; /** The field ID for bulk changes. */ public static final String ID_BULK = PREFIX + TAG_BULK; /** The field ID for recoil changes. */ public static final String ID_RECOIL = PREFIX + TAG_RECOIL; private String mAccuracy; private String mRange; private String mRateOfFire; private String mShots; private String mBulk; private String mRecoil; /** * Creates a new {@link RangedWeaponStats}. * * @param owner The owning piece of equipment or advantage. */ public RangedWeaponStats(ListRow owner) { super(owner); } /** * Creates a clone of the specified {@link RangedWeaponStats}. * * @param owner The owning piece of equipment or advantage. * @param other The {@link RangedWeaponStats} to clone. */ public RangedWeaponStats(ListRow owner, RangedWeaponStats other) { super(owner, other); mAccuracy = other.mAccuracy; mRange = other.mRange; mRateOfFire = other.mRateOfFire; mShots = other.mShots; mBulk = other.mBulk; mRecoil = other.mRecoil; } /** * Creates a {@link RangedWeaponStats}. * * @param owner The owning piece of equipment or advantage. * @param reader The reader to load from. */ public RangedWeaponStats(ListRow owner, XMLReader reader) throws IOException { super(owner, reader); } @Override public WeaponStats clone(ListRow owner) { return new RangedWeaponStats(owner, this); } @Override protected void initialize() { mAccuracy = EMPTY; mRange = EMPTY; mRateOfFire = EMPTY; mShots = EMPTY; mBulk = EMPTY; mRecoil = EMPTY; } @Override protected void loadSelf(XMLReader reader) throws IOException { String name = reader.getName(); if (TAG_ACCURACY.equals(name)) { mAccuracy = reader.readText(); } else if (TAG_RANGE.equals(name)) { mRange = reader.readText(); } else if (TAG_RATE_OF_FIRE.equals(name)) { mRateOfFire = reader.readText(); } else if (TAG_SHOTS.equals(name)) { mShots = reader.readText(); } else if (TAG_BULK.equals(name)) { mBulk = reader.readText(); } else if (TAG_RECOIL.equals(name)) { mRecoil = reader.readText(); } else { super.loadSelf(reader); } } @Override protected String getRootTag() { return TAG_ROOT; } @Override protected void saveSelf(XMLWriter out) { out.simpleTagNotEmpty(TAG_ACCURACY, mAccuracy); out.simpleTagNotEmpty(TAG_RANGE, mRange); out.simpleTagNotEmpty(TAG_RATE_OF_FIRE, mRateOfFire); out.simpleTagNotEmpty(TAG_SHOTS, mShots); out.simpleTagNotEmpty(TAG_BULK, mBulk); out.simpleTagNotEmpty(TAG_RECOIL, mRecoil); } /** @return The accuracy. */ public String getAccuracy() { return mAccuracy; } /** * Sets the value of accuracy. * * @param accuracy The value to set. */ public void setAccuracy(String accuracy) { accuracy = sanitize(accuracy); if (!mAccuracy.equals(accuracy)) { mAccuracy = accuracy; notifySingle(ID_ACCURACY); } } /** @return The bulk. */ public String getBulk() { return mBulk; } /** * Sets the value of bulk. * * @param bulk The value to set. */ public void setBulk(String bulk) { bulk = sanitize(bulk); if (!mBulk.equals(bulk)) { mBulk = bulk; notifySingle(ID_BULK); } } /** @return The range. */ public String getRange() { return mRange; } /** @return The range, fully resolved for the user's ST, if possible. */ public String getResolvedRange() { DataFile df = getOwner().getDataFile(); String range = mRange; if (df instanceof GURPSCharacter) { int strength = ((GURPSCharacter) df).getStrength(); String savedRange; do { savedRange = range; range = resolveRange(range, strength); } while (!savedRange.equals(range)); } return range; } private String resolveRange(String range, int strength) { int where = range.indexOf("x"); //$NON-NLS-1$ if (where != -1) { int last = where + 1; int max = range.length(); last = skipSpaces(range, last); if (last < max) { double value = 0.0; char ch = range.charAt(last); boolean found = false; double multiplier = 1.0; while (multiplier == 1.0 && ch == '.' || ch >= '0' && ch <= '9') { found = true; if (ch == '.') { multiplier = 0.1; } else if (multiplier == 1.0) { value *= 10.0; value += ch - '0'; } else { value += (ch - '0') * multiplier; multiplier *= 0.1; } if (++last >= max) { break; } ch = range.charAt(last); } if (found) { StringBuffer buffer = new StringBuffer(); if (where > 0) { buffer.append(range.substring(0, where)); } strength *= value; buffer.append(Numbers.format(strength)); if (last < max) { buffer.append(range.substring(last)); } return buffer.toString(); } } } return range; } /** * Sets the value of range. * * @param range The value to set. */ public void setRange(String range) { range = sanitize(range); if (!mRange.equals(range)) { mRange = range; notifySingle(ID_RANGE); } } /** @return The rate of fire. */ public String getRateOfFire() { return mRateOfFire; } /** * Sets the value of rate of fire. * * @param rateOfFire The value to set. */ public void setRateOfFire(String rateOfFire) { rateOfFire = sanitize(rateOfFire); if (!mRateOfFire.equals(rateOfFire)) { mRateOfFire = rateOfFire; notifySingle(ID_RATE_OF_FIRE); } } /** @return The recoil. */ public String getRecoil() { return mRecoil; } /** * Sets the value of recoil. * * @param recoil The value to set. */ public void setRecoil(String recoil) { recoil = sanitize(recoil); if (!mRecoil.equals(recoil)) { mRecoil = recoil; notifySingle(ID_RECOIL); } } /** @return The shots. */ public String getShots() { return mShots; } /** * Sets the value of shots. * * @param shots The value to set. */ public void setShots(String shots) { shots = sanitize(shots); if (!mShots.equals(shots)) { mShots = shots; notifySingle(ID_SHOTS); } } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof RangedWeaponStats && super.equals(obj)) { RangedWeaponStats rws = (RangedWeaponStats) obj; return mAccuracy.equals(rws.mAccuracy) && mRange.equals(rws.mRange) && mRateOfFire.equals(rws.mRateOfFire) && mShots.equals(rws.mShots) && mBulk.equals(rws.mBulk) && mRecoil.equals(rws.mRecoil); } return false; } }