/* * 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.spell; import com.trollworks.gcs.app.GCSImages; import com.trollworks.gcs.character.GURPSCharacter; import com.trollworks.gcs.common.DataFile; import com.trollworks.gcs.common.HasSourceReference; import com.trollworks.gcs.common.ListFile; import com.trollworks.gcs.common.LoadState; import com.trollworks.gcs.library.LibraryFile; import com.trollworks.gcs.skill.SkillAttribute; import com.trollworks.gcs.skill.SkillDefault; import com.trollworks.gcs.skill.SkillLevel; import com.trollworks.gcs.weapon.MeleeWeaponStats; import com.trollworks.gcs.weapon.RangedWeaponStats; import com.trollworks.gcs.weapon.WeaponStats; import com.trollworks.gcs.widgets.outline.ListRow; import com.trollworks.gcs.widgets.outline.RowEditor; import com.trollworks.toolkit.annotation.Localize; import com.trollworks.toolkit.io.xml.XMLReader; import com.trollworks.toolkit.io.xml.XMLWriter; import com.trollworks.toolkit.ui.image.StdImage; import com.trollworks.toolkit.ui.widget.outline.Column; import com.trollworks.toolkit.ui.widget.outline.Row; import com.trollworks.toolkit.utility.Localization; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; /** A GURPS Spell. */ public class Spell extends ListRow implements HasSourceReference { @Localize("Spell") @Localize(locale = "de", value = "Zauber") @Localize(locale = "ru", value = "Заклинание") @Localize(locale = "es", value = "Sortilegio") private static String DEFAULT_NAME; @Localize("Arcane") @Localize(locale = "de", value = "Arkan") @Localize(locale = "ru", value = "Тайный") @Localize(locale = "es", value = "Arcano") private static String DEFAULT_POWER_SOURCE; @Localize("Regular") @Localize(locale = "de", value = "Regulär") @Localize(locale = "ru", value = "Обычный") @Localize(locale = "es", value = "Normal") private static String DEFAULT_SPELL_CLASS; @Localize("1") @Localize(locale = "de", value = "1") private static String DEFAULT_CASTING_COST; @Localize("1 sec") @Localize(locale = "de", value = "1 Sek.") @Localize(locale = "ru", value = "1 сек") @Localize(locale = "es", value = "1 seg.") private static String DEFAULT_CASTING_TIME; @Localize("Instant") @Localize(locale = "de", value = "Sofort") @Localize(locale = "ru", value = "Мгновенное") @Localize(locale = "es", value = "Instantáneo") private static String DEFAULT_DURATION; static { Localization.initialize(); } private static final int CURRENT_VERSION = 2; /** The extension for Spell lists. */ public static final String OLD_SPELL_EXTENSION = "spl"; //$NON-NLS-1$ /** The XML tag used for items. */ public static final String TAG_SPELL = "spell"; //$NON-NLS-1$ /** The XML tag used for containers. */ public static final String TAG_SPELL_CONTAINER = "spell_container"; //$NON-NLS-1$ private static final String TAG_NAME = "name"; //$NON-NLS-1$ private static final String TAG_TECH_LEVEL = "tech_level"; //$NON-NLS-1$ private static final String TAG_COLLEGE = "college"; //$NON-NLS-1$ private static final String TAG_POWER_SOURCE = "power_source"; //$NON-NLS-1$ private static final String TAG_SPELL_CLASS = "spell_class"; //$NON-NLS-1$ private static final String TAG_CASTING_COST = "casting_cost"; //$NON-NLS-1$ private static final String TAG_MAINTENANCE_COST = "maintenance_cost"; //$NON-NLS-1$ private static final String TAG_CASTING_TIME = "casting_time"; //$NON-NLS-1$ private static final String TAG_DURATION = "duration"; //$NON-NLS-1$ private static final String TAG_POINTS = "points"; //$NON-NLS-1$ private static final String TAG_REFERENCE = "reference"; //$NON-NLS-1$ private static final String ATTRIBUTE_VERY_HARD = "very_hard"; //$NON-NLS-1$ /** The prefix used in front of all IDs for the spells. */ public static final String PREFIX = GURPSCharacter.CHARACTER_PREFIX + "spell."; //$NON-NLS-1$ /** The field ID for name changes. */ public static final String ID_NAME = PREFIX + "Name"; //$NON-NLS-1$ /** The field ID for tech level changes. */ public static final String ID_TECH_LEVEL = PREFIX + "TechLevel"; //$NON-NLS-1$ /** The field ID for college changes. */ public static final String ID_COLLEGE = PREFIX + "College"; //$NON-NLS-1$ /** The field ID for power source changes. */ public static final String ID_POWER_SOURCE = PREFIX + "PowerSource"; //$NON-NLS-1$ /** The field ID for spell class changes. */ public static final String ID_SPELL_CLASS = PREFIX + "Class"; //$NON-NLS-1$ /** The field ID for casting cost changes */ public static final String ID_CASTING_COST = PREFIX + "CastingCost"; //$NON-NLS-1$ /** The field ID for maintainance cost changes */ public static final String ID_MAINTENANCE_COST = PREFIX + "MaintenanceCost"; //$NON-NLS-1$ /** The field ID for casting time changes */ public static final String ID_CASTING_TIME = PREFIX + "CastingTime"; //$NON-NLS-1$ /** The field ID for duration changes */ public static final String ID_DURATION = PREFIX + "Duration"; //$NON-NLS-1$ /** The field ID for point changes. */ public static final String ID_POINTS = PREFIX + "Points"; //$NON-NLS-1$ /** The field ID for level changes. */ public static final String ID_LEVEL = PREFIX + "Level"; //$NON-NLS-1$ /** The field ID for page reference changes. */ public static final String ID_REFERENCE = PREFIX + "Reference"; //$NON-NLS-1$ /** The field ID for difficulty changes. */ public static final String ID_DIFFICULTY = PREFIX + "Difficulty"; //$NON-NLS-1$ /** The field ID for when the categories change. */ public static final String ID_CATEGORY = PREFIX + "Category"; //$NON-NLS-1$ /** The field ID for when the row hierarchy changes. */ public static final String ID_LIST_CHANGED = PREFIX + "ListChanged"; //$NON-NLS-1$ /** The field ID for when the spell becomes or stops being a weapon. */ public static final String ID_WEAPON_STATUS_CHANGED = PREFIX + "WeaponStatus"; //$NON-NLS-1$ private static final String EMPTY = ""; //$NON-NLS-1$ private static final String NEWLINE = "\n"; //$NON-NLS-1$ private static final String SPACE = " "; //$NON-NLS-1$ private String mName; private String mTechLevel; private String mCollege; private String mPowerSource; private String mSpellClass; private String mCastingCost; private String mMaintenance; private String mCastingTime; private String mDuration; private int mPoints; private int mLevel; private int mRelativeLevel; private SkillAttribute mAttribute; private String mReference; private boolean mIsVeryHard; private ArrayList<WeaponStats> mWeapons; /** * Creates a new spell. * * @param dataFile The data file to associate it with. * @param isContainer Whether or not this row allows children. */ public Spell(DataFile dataFile, boolean isContainer) { super(dataFile, isContainer); mName = DEFAULT_NAME; mAttribute = SkillAttribute.IQ; mTechLevel = null; mCollege = EMPTY; mPowerSource = isContainer ? EMPTY : DEFAULT_POWER_SOURCE; mSpellClass = isContainer ? EMPTY : DEFAULT_SPELL_CLASS; mCastingCost = isContainer ? EMPTY : DEFAULT_CASTING_COST; mMaintenance = EMPTY; mCastingTime = isContainer ? EMPTY : DEFAULT_CASTING_TIME; mDuration = isContainer ? EMPTY : DEFAULT_DURATION; mPoints = 1; mReference = EMPTY; mIsVeryHard = false; mWeapons = new ArrayList<>(); updateLevel(false); } /** * Creates a clone of an existing spell and associates it with the specified data file. * * @param dataFile The data file to associate it with. * @param spell The spell to clone. * @param deep Whether or not to clone the children, grandchildren, etc. * @param forSheet Whether this is for a character sheet or a list. */ public Spell(DataFile dataFile, Spell spell, boolean deep, boolean forSheet) { super(dataFile, spell); mName = spell.mName; mAttribute = spell.mAttribute; mTechLevel = spell.mTechLevel; mCollege = spell.mCollege; mPowerSource = spell.mPowerSource; mSpellClass = spell.mSpellClass; mCastingCost = spell.mCastingCost; mMaintenance = spell.mMaintenance; mCastingTime = spell.mCastingTime; mDuration = spell.mDuration; mPoints = forSheet ? spell.mPoints : 1; mReference = spell.mReference; mIsVeryHard = spell.mIsVeryHard; if (forSheet && dataFile instanceof GURPSCharacter) { if (mTechLevel != null) { mTechLevel = ((GURPSCharacter) dataFile).getDescription().getTechLevel(); } } else { if (mTechLevel != null && mTechLevel.trim().length() > 0) { mTechLevel = EMPTY; } } mWeapons = new ArrayList<>(spell.mWeapons.size()); for (WeaponStats weapon : spell.mWeapons) { if (weapon instanceof MeleeWeaponStats) { mWeapons.add(new MeleeWeaponStats(this, (MeleeWeaponStats) weapon)); } else if (weapon instanceof RangedWeaponStats) { mWeapons.add(new RangedWeaponStats(this, (RangedWeaponStats) weapon)); } } updateLevel(false); if (deep) { int count = spell.getChildCount(); for (int i = 0; i < count; i++) { addChild(new Spell(dataFile, (Spell) spell.getChild(i), true, forSheet)); } } } /** * Loads a spell and associates it with the specified data file. * * @param dataFile The data file to associate it with. * @param reader The XML reader to load from. * @param state The {@link LoadState} to use. */ public Spell(DataFile dataFile, XMLReader reader, LoadState state) throws IOException { this(dataFile, TAG_SPELL_CONTAINER.equals(reader.getName())); load(reader, state); } @Override public boolean isEquivalentTo(Object obj) { if (obj == this) { return true; } if (obj instanceof Spell && super.isEquivalentTo(obj)) { Spell row = (Spell) obj; if (mIsVeryHard == row.mIsVeryHard && mPoints == row.mPoints && mLevel == row.mLevel && mAttribute == row.mAttribute && mRelativeLevel == row.mRelativeLevel) { if (mTechLevel == null ? row.mTechLevel == null : mTechLevel.equals(row.mTechLevel)) { if (mName.equals(row.mName) && mCollege.equals(row.mCollege) && mPowerSource.equals(row.mPowerSource) && mSpellClass.equals(row.mSpellClass) && mReference.equals(row.mReference)) { if (mCastingCost.equals(row.mCastingCost) && mMaintenance.equals(row.mMaintenance) && mCastingTime.equals(row.mCastingTime) && mDuration.equals(row.mDuration)) { return mWeapons.equals(row.mWeapons); } } } } } return false; } @Override public String getLocalizedName() { return DEFAULT_NAME; } @Override public String getListChangedID() { return ID_LIST_CHANGED; } @Override public String getXMLTagName() { return canHaveChildren() ? TAG_SPELL_CONTAINER : TAG_SPELL; } @Override public int getXMLTagVersion() { return CURRENT_VERSION; } @Override public String getRowType() { return DEFAULT_NAME; } @Override protected void prepareForLoad(LoadState state) { boolean isContainer = canHaveChildren(); super.prepareForLoad(state); mName = DEFAULT_NAME; mAttribute = SkillAttribute.IQ; mTechLevel = null; mCollege = EMPTY; mPowerSource = isContainer ? EMPTY : DEFAULT_POWER_SOURCE; mSpellClass = isContainer ? EMPTY : DEFAULT_SPELL_CLASS; mCastingCost = isContainer ? EMPTY : DEFAULT_CASTING_COST; mMaintenance = EMPTY; mCastingTime = isContainer ? EMPTY : DEFAULT_CASTING_TIME; mDuration = isContainer ? EMPTY : DEFAULT_DURATION; mPoints = 1; mReference = EMPTY; mIsVeryHard = false; mWeapons = new ArrayList<>(); } @Override protected void loadAttributes(XMLReader reader, LoadState state) { super.loadAttributes(reader, state); mIsVeryHard = reader.isAttributeSet(ATTRIBUTE_VERY_HARD); } @Override protected void loadSubElement(XMLReader reader, LoadState state) throws IOException { String name = reader.getName(); if (TAG_NAME.equals(name)) { mName = reader.readText().replace(NEWLINE, SPACE); // Fix for legacy format... if (mName.toLowerCase().endsWith("(vh)")) { //$NON-NLS-1$ mName = mName.substring(0, mName.length() - 4).trim(); mIsVeryHard = true; } } else if (TAG_TECH_LEVEL.equals(name)) { mTechLevel = reader.readText(); if (mTechLevel != null) { DataFile dataFile = getDataFile(); if (dataFile instanceof ListFile || dataFile instanceof LibraryFile) { mTechLevel = EMPTY; } } } else if (TAG_REFERENCE.equals(name)) { mReference = reader.readText().replace(NEWLINE, SPACE); } else if (!state.mForUndo && (TAG_SPELL.equals(name) || TAG_SPELL_CONTAINER.equals(name))) { addChild(new Spell(mDataFile, reader, state)); } else if (!canHaveChildren()) { if (TAG_COLLEGE.equals(name)) { mCollege = reader.readText().replace(NEWLINE, SPACE).replace("/ ", "/"); //$NON-NLS-1$ //$NON-NLS-2$ } else if (TAG_POWER_SOURCE.equals(name)) { mPowerSource = reader.readText().replace(NEWLINE, SPACE); } else if (TAG_SPELL_CLASS.equals(name)) { mSpellClass = reader.readText().replace(NEWLINE, SPACE); } else if (TAG_CASTING_COST.equals(name)) { mCastingCost = reader.readText().replace(NEWLINE, SPACE); } else if (TAG_MAINTENANCE_COST.equals(name)) { mMaintenance = reader.readText().replace(NEWLINE, SPACE); } else if (TAG_CASTING_TIME.equals(name)) { mCastingTime = reader.readText().replace(NEWLINE, SPACE); } else if (TAG_DURATION.equals(name)) { mDuration = reader.readText().replace(NEWLINE, SPACE); } else if (TAG_POINTS.equals(name)) { mPoints = reader.readInteger(1); } else if (MeleeWeaponStats.TAG_ROOT.equals(name)) { mWeapons.add(new MeleeWeaponStats(this, reader)); } else if (RangedWeaponStats.TAG_ROOT.equals(name)) { mWeapons.add(new RangedWeaponStats(this, reader)); } else { super.loadSubElement(reader, state); } } else { super.loadSubElement(reader, state); } } @Override protected void finishedLoading(LoadState state) { updateLevel(false); super.finishedLoading(state); } @Override protected void saveAttributes(XMLWriter out, boolean forUndo) { if (mIsVeryHard) { out.writeAttribute(ATTRIBUTE_VERY_HARD, mIsVeryHard); } } @Override public void saveSelf(XMLWriter out, boolean forUndo) { out.simpleTag(TAG_NAME, mName); if (!canHaveChildren()) { if (mTechLevel != null) { if (getCharacter() != null) { out.simpleTagNotEmpty(TAG_TECH_LEVEL, mTechLevel); } else { out.startTag(TAG_TECH_LEVEL); out.finishEmptyTagEOL(); } } out.simpleTagNotEmpty(TAG_COLLEGE, mCollege); out.simpleTagNotEmpty(TAG_POWER_SOURCE, mPowerSource); out.simpleTagNotEmpty(TAG_SPELL_CLASS, mSpellClass); out.simpleTagNotEmpty(TAG_CASTING_COST, mCastingCost); out.simpleTagNotEmpty(TAG_MAINTENANCE_COST, mMaintenance); out.simpleTagNotEmpty(TAG_CASTING_TIME, mCastingTime); out.simpleTagNotEmpty(TAG_DURATION, mDuration); if (mPoints != 1) { out.simpleTag(TAG_POINTS, mPoints); } for (WeaponStats weapon : mWeapons) { weapon.save(out); } } out.simpleTagNotEmpty(TAG_REFERENCE, mReference); } /** @return The weapon list. */ public List<WeaponStats> getWeapons() { return Collections.unmodifiableList(mWeapons); } /** * @param weapons The weapons to set. * @return Whether it was modified. */ public boolean setWeapons(List<WeaponStats> weapons) { if (!mWeapons.equals(weapons)) { mWeapons = new ArrayList<>(weapons); for (WeaponStats weapon : mWeapons) { weapon.setOwner(this); } notifySingle(ID_WEAPON_STATUS_CHANGED); return true; } return false; } /** @return The tech level. */ public String getTechLevel() { return mTechLevel; } /** * @param techLevel The tech level to set. * @return Whether it was changed. */ public boolean setTechLevel(String techLevel) { if (mTechLevel == null ? techLevel != null : !mTechLevel.equals(techLevel)) { mTechLevel = techLevel; notifySingle(ID_TECH_LEVEL); return true; } return false; } /** @return The level. */ public int getLevel() { return mLevel; } /** @return The relative level. */ public int getRelativeLevel() { return mRelativeLevel; } /** * Call to force an update of the level and relative level for this spell. * * @param notify Whether or not a notification should be issued on a change. */ public void updateLevel(boolean notify) { int savedLevel = mLevel; int savedRelativeLevel = mRelativeLevel; SkillLevel level = calculateLevel(getCharacter(), mPoints, mAttribute, mIsVeryHard, mCollege, mPowerSource, mName); mLevel = level.mLevel; mRelativeLevel = level.mRelativeLevel; if (notify && (savedLevel != mLevel || savedRelativeLevel != mRelativeLevel)) { notify(ID_LEVEL, this); } } /** * Calculates the spell level. * * @param character The character the spell will be attached to. * @param points The number of points spent in the spell. * @param isVeryHard Whether the spell is "Very Hard" or not. * @param college The college the spell belongs to. * @param powerSource The source of power for the spell. * @param name The name of the spell. * @return The calculated spell level. */ public static SkillLevel calculateLevel(GURPSCharacter character, int points, SkillAttribute attribute, boolean isVeryHard, String college, String powerSource, String name) { int relativeLevel = isVeryHard ? -3 : -2; int level; if (character != null) { level = attribute.getBaseSkillLevel(character); if (points < 1) { level = -1; relativeLevel = 0; } else if (points == 1) { // mRelativeLevel is preset to this point value } else if (points < 4) { relativeLevel++; } else { relativeLevel += 1 + points / 4; } if (level != -1) { relativeLevel += getSpellBonusesFor(character, ID_COLLEGE, college); relativeLevel += getSpellBonusesFor(character, ID_POWER_SOURCE, powerSource); relativeLevel += getSpellBonusesFor(character, ID_NAME, name); level += relativeLevel; } } else { level = -1; } return new SkillLevel(level, relativeLevel); } private static int getSpellBonusesFor(GURPSCharacter character, String id, String qualifier) { int level = character.getIntegerBonusFor(id); level += character.getIntegerBonusFor(id + '/' + qualifier.toLowerCase()); level += character.getSpellComparedIntegerBonusFor(id + '*', qualifier); return level; } /** @return The name. */ public String getName() { return mName; } /** * @param name The name to set. * @return Whether it was changed. */ public boolean setName(String name) { if (!mName.equals(name)) { mName = name; notifySingle(ID_NAME); return true; } return false; } /** @return The college. */ public String getCollege() { return mCollege; } /** * @param college The college to set. * @return Whether it was changed. */ public boolean setCollege(String college) { if (!mCollege.equals(college)) { mCollege = college; notifySingle(ID_COLLEGE); return true; } return false; } /** @return The power source. */ public String getPowerSource() { return mPowerSource; } /** * @param powerSource The college to set. * @return Whether it was changed. */ public boolean setPowerSource(String powerSource) { if (!mPowerSource.equals(powerSource)) { mPowerSource = powerSource; notifySingle(ID_POWER_SOURCE); return true; } return false; } /** @return The class. */ public String getSpellClass() { return mSpellClass; } /** * @param spellClass The class to set. * @return Whether it was modified. */ public boolean setSpellClass(String spellClass) { if (!mSpellClass.equals(spellClass)) { mSpellClass = spellClass; return true; } return false; } /** @return The casting cost. */ public String getCastingCost() { return mCastingCost; } /** * @param cost The casting cost to set. * @return Whether it was modified. */ public boolean setCastingCost(String cost) { if (!mCastingCost.equals(cost)) { mCastingCost = cost; return true; } return false; } /** @return The maintainance cost. */ public String getMaintenance() { return mMaintenance; } /** * @param cost The maintainance cost to set. * @return Whether it was modified. */ public boolean setMaintenance(String cost) { if (!mMaintenance.equals(cost)) { mMaintenance = cost; return true; } return false; } /** @return The casting time. */ public String getCastingTime() { return mCastingTime; } /** * @param castingTime The casting time to set. * @return Whether it was modified. */ public boolean setCastingTime(String castingTime) { if (!mCastingTime.equals(castingTime)) { mCastingTime = castingTime; return true; } return false; } /** @return The duration. */ public String getDuration() { return mDuration; } /** * @param duration The duration to set. * @return Whether it was modified. */ public boolean setDuration(String duration) { if (!mDuration.equals(duration)) { mDuration = duration; return true; } return false; } /** @return The points. */ public int getPoints() { if (canHaveChildren()) { int sum = 0; for (Row row : getChildren()) { if (row instanceof Spell) { sum += ((Spell) row).getPoints(); } } return sum; } return mPoints; } /** * @param points The points to set. * @return Whether it was modified. */ public boolean setPoints(int points) { if (mPoints != points) { mPoints = points; startNotify(); notify(ID_POINTS, this); updateLevel(true); endNotify(); return true; } return false; } @Override public String getReference() { return mReference; } @Override public boolean setReference(String reference) { if (!mReference.equals(reference)) { mReference = reference; return true; } return false; } @Override public String getReferenceHighlight() { return getName(); } @Override public Object getData(Column column) { return SpellColumn.values()[column.getID()].getData(this); } @Override public String getDataAsText(Column column) { return SpellColumn.values()[column.getID()].getDataAsText(this); } @Override public boolean contains(String text, boolean lowerCaseOnly) { if (getName().toLowerCase().indexOf(text) != -1) { return true; } if (getCollege().toLowerCase().indexOf(text) != -1) { return true; } if (getSpellClass().toLowerCase().indexOf(text) != -1) { return true; } return super.contains(text, lowerCaseOnly); } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append(getName()); if (!canHaveChildren()) { String techLevel = getTechLevel(); if (techLevel != null) { builder.append("/TL"); //$NON-NLS-1$ if (techLevel.length() > 0) { builder.append(techLevel); } } } return builder.toString(); } @Override public StdImage getIcon(boolean large) { return GCSImages.getSpellsIcons().getImage(large ? 64 : 16); } /** @return The attribute. */ public SkillAttribute getAttribute() { return mAttribute; } /** @return Whether this is a "Very Hard" spell or not. */ public boolean isVeryHard() { return mIsVeryHard; } /** * @param attribute The attribute to use. * @param veryHard Whether this is a "Very Hard" spell or not. * @return Whether it was modified. */ public boolean setDifficulty(SkillAttribute attribute, boolean veryHard) { if (mAttribute != attribute || mIsVeryHard != veryHard) { mAttribute = attribute; mIsVeryHard = veryHard; startNotify(); notify(ID_DIFFICULTY, this); updateLevel(true); endNotify(); return true; } return false; } @Override public RowEditor<? extends ListRow> createEditor() { return new SpellEditor(this); } @Override public void fillWithNameableKeys(HashSet<String> set) { super.fillWithNameableKeys(set); extractNameables(set, mName); extractNameables(set, mCollege); extractNameables(set, mPowerSource); extractNameables(set, mCastingCost); extractNameables(set, mMaintenance); extractNameables(set, mCastingTime); extractNameables(set, mDuration); for (WeaponStats weapon : mWeapons) { for (SkillDefault one : weapon.getDefaults()) { one.fillWithNameableKeys(set); } } } @Override public void applyNameableKeys(HashMap<String, String> map) { super.applyNameableKeys(map); mName = nameNameables(map, mName); mCollege = nameNameables(map, mCollege); mPowerSource = nameNameables(map, mPowerSource); mSpellClass = nameNameables(map, mSpellClass); mCastingCost = nameNameables(map, mCastingCost); mMaintenance = nameNameables(map, mMaintenance); mCastingTime = nameNameables(map, mCastingTime); mDuration = nameNameables(map, mDuration); for (WeaponStats weapon : mWeapons) { for (SkillDefault one : weapon.getDefaults()) { one.applyNameableKeys(map); } } } /** @return The default casting cost. */ public static final String getDefaultCastingCost() { return DEFAULT_CASTING_COST; } /** @return The default casting time. */ public static final String getDefaultCastingTime() { return DEFAULT_CASTING_TIME; } /** @return The default duration. */ public static final String getDefaultDuration() { return DEFAULT_DURATION; } /** @return The default spell class. */ public static final String getDefaultSpellClass() { return DEFAULT_SPELL_CLASS; } @Override protected String getCategoryID() { return ID_CATEGORY; } }