use of pcgen.core.character.SpellInfo in project pcgen by PCGen.
the class PCGVer2Parser method parseSpellLine.
/*
* ###############################################################
* Character Spells Information methods
* ###############################################################
*/
private void parseSpellLine(final String line) {
final PCGTokenizer tokens;
try {
tokens = new PCGTokenizer(line);
} catch (PCGParseException pcgpex) {
final String message = "Illegal Spell line ignored: " + line + Constants.LINE_SEPARATOR + "Error: " + pcgpex.getMessage();
warnings.add(message);
return;
}
Spell aSpell = null;
PCClass aPCClass = null;
PObject source = null;
String spellBook = null;
int times = 1;
int spellLevel = 0;
int numPages = 0;
final List<Ability> metaFeats = new ArrayList<>();
int ppCost = -1;
for (final PCGElement element : tokens.getElements()) {
final String tag = element.getName();
if (IOConstants.TAG_SPELLNAME.equals(tag)) {
String spellName = EntityEncoder.decode(element.getText());
spellName = SpellMigration.getNewSpellKey(spellName, pcgenVersion, SettingsHandler.getGame().getName());
// either NULL (no spell) a Spell instance,
aSpell = Globals.getContext().getReferenceContext().silentlyGetConstructedCDOMObject(Spell.class, spellName);
if (aSpell == null) {
final String message = "Could not find spell named: " + spellName;
warnings.add(message);
return;
}
} else if (IOConstants.TAG_TIMES.equals(tag)) {
try {
times = Integer.parseInt(element.getText());
} catch (NumberFormatException nfe) {
// nothing we can do about it
}
} else if (IOConstants.TAG_CLASS.equals(tag)) {
final String classKey = EntityEncoder.decode(element.getText());
aPCClass = thePC.getClassKeyed(classKey);
if (aPCClass == null) {
final String message = "Invalid class specification: " + classKey;
warnings.add(message);
return;
}
} else if (IOConstants.TAG_SPELL_BOOK.equals(tag)) {
spellBook = EntityEncoder.decode(element.getText());
} else if (IOConstants.TAG_SPELLLEVEL.equals(tag)) {
try {
spellLevel = Integer.parseInt(element.getText());
} catch (NumberFormatException nfe) {
// nothing we can do about it
}
} else if (IOConstants.TAG_SPELLPPCOST.equals(tag)) {
try {
ppCost = Integer.parseInt(element.getText());
} catch (NumberFormatException nfe) {
// nothing we can do about it
}
} else if (IOConstants.TAG_SPELLNUMPAGES.equals(tag)) {
try {
numPages = Integer.parseInt(element.getText());
} catch (NumberFormatException nfe) {
// nothing we can do about it
}
} else if (IOConstants.TAG_SOURCE.equals(tag)) {
String typeName = Constants.EMPTY_STRING;
String objectKey = Constants.EMPTY_STRING;
for (final PCGElement child : element.getChildren()) {
final String childTag = child.getName();
if (IOConstants.TAG_TYPE.equals(childTag)) {
typeName = child.getText().toUpperCase();
} else if (IOConstants.TAG_NAME.equals(childTag)) {
objectKey = child.getText();
}
}
if (IOConstants.TAG_DOMAIN.equals(typeName)) {
Domain domain = Globals.getContext().getReferenceContext().silentlyGetConstructedCDOMObject(DOMAIN_CLASS, objectKey);
ClassSource cs = thePC.getDomainSource(domain);
if (cs == null) {
final String message = "Could not find domain: " + objectKey;
warnings.add(message);
return;
}
source = domain;
} else {
// it's either the class, sub-class or a cast-as class
// first see if it's the class
ClassSpellList csl = Globals.getContext().getReferenceContext().silentlyGetConstructedCDOMObject(ClassSpellList.class, objectKey);
if (((aPCClass != null) && objectKey.equals(aPCClass.getKeyName())) || (aPCClass != null && thePC.getSpellLists(aPCClass).contains(csl))) {
source = aPCClass;
} else {
// see if PC has the class
source = thePC.getClassKeyed(objectKey);
}
}
} else if (IOConstants.TAG_FEATLIST.equals(tag)) {
for (PCGElement child : element.getChildren()) {
final String featKey = EntityEncoder.decode(child.getText());
final Ability anAbility = Globals.getContext().getReferenceContext().silentlyGetConstructedCDOMObject(Ability.class, AbilityCategory.FEAT, featKey);
if (anAbility != null) {
metaFeats.add(anAbility);
}
}
}
}
if ((aPCClass == null) || (spellBook == null)) {
final String message = "Illegal Spell line ignored: " + line;
warnings.add(message);
return;
}
/*
* this can only happen if the source type was NOT DOMAIN!
*/
if (source == null) {
source = aPCClass;
}
// if (obj instanceof List)
// {
// // find the instance of Spell in this class
// // best suited to this spell
// for (final Spell spell : (ArrayList<Spell>) obj)
// {
// // valid spell has a non-negative spell level
// if ((spell != null)
// && (SpellLevel.getFirstLevelForKey(spell,
// thePC.getSpellLists(source), thePC) >= 0))
// {
// aSpell = spell;
// break;
// }
// }
// if (aSpell == null)
// {
// Logging.errorPrint("Could not resolve spell " + obj.toString());
// }
// }
// if (aSpell == null)
// {
// final String message =
// "Could not find spell named: " + String.valueOf(obj);
// warnings.add(message);
//
// return;
// }
// just to make sure the spellbook is present
thePC.addSpellBook(spellBook);
final SpellBook book = thePC.getSpellBookByName(spellBook);
thePC.calculateKnownSpellsForClassLevel(aPCClass);
final Integer[] spellLevels = SpellLevel.levelForKey(aSpell, thePC.getSpellLists(source), thePC);
boolean found = false;
for (int sindex = 0; sindex < spellLevels.length; ++sindex) {
final int level = spellLevels[sindex];
final int metmagicLevels = totalAddedLevelsFromMetamagic(metaFeats);
if (spellLevel > 0 && spellLevel != (level + metmagicLevels)) {
// Skip spell in class lists that does not match level the character knows it.
continue;
}
if (level < 0) {
Collection<CDOMReference<Spell>> mods = source.getListMods(Spell.SPELLS);
if (mods == null) {
continue;
}
for (CDOMReference<Spell> ref : mods) {
Collection<Spell> refSpells = ref.getContainedObjects();
Collection<AssociatedPrereqObject> assocs = source.getListAssociations(Spell.SPELLS, ref);
for (Spell sp : refSpells) {
if (aSpell.getKeyName().equals(sp.getKeyName())) {
for (AssociatedPrereqObject apo : assocs) {
String sb = apo.getAssociation(AssociationKey.SPELLBOOK);
if (spellBook.equals(sb)) {
found = true;
break;
}
}
}
}
}
continue;
}
found = true;
// do not load auto knownspells into default spellbook
if (spellBook.equals(Globals.getDefaultSpellBook()) && thePC.getSpellSupport(aPCClass).isAutoKnownSpell(aSpell, level, false, thePC) && thePC.getAutoSpells()) {
continue;
}
CharacterSpell aCharacterSpell = thePC.getCharacterSpellForSpell(aPCClass, aSpell, source);
// so we'll need to add it to the list
if (aCharacterSpell == null) {
aCharacterSpell = new CharacterSpell(source, aSpell);
aCharacterSpell.addInfo(level, times, spellBook);
thePC.addCharacterSpell(aPCClass, aCharacterSpell);
}
SpellInfo aSpellInfo = null;
if (source.getKeyName().equals(aPCClass.getKeyName()) || !spellBook.equals(Globals.getDefaultSpellBook())) {
aSpellInfo = aCharacterSpell.getSpellInfoFor(spellBook, spellLevel);
// metaFeats list have to do with this?
if ((aSpellInfo == null) || !metaFeats.isEmpty()) {
aSpellInfo = aCharacterSpell.addInfo(spellLevel, times, spellBook);
}
}
if (aSpellInfo != null) {
if (!metaFeats.isEmpty()) {
aSpellInfo.addFeatsToList(metaFeats);
}
aSpellInfo.setActualPPCost(ppCost);
aSpellInfo.setNumPages(numPages);
book.setNumPagesUsed(book.getNumPagesUsed() + numPages);
book.setNumSpells(book.getNumSpells() + 1);
}
}
if (!found) {
final String message = "Could not find spell " + aSpell.getDisplayName() + " in " + shortClassName(source) + " " + source.getDisplayName();
warnings.add(message);
}
}
use of pcgen.core.character.SpellInfo in project pcgen by PCGen.
the class PCGVer2Creator method appendSpellLines.
/*
* ###############################################################
* Character Spells Information methods
* ###############################################################
*/
/*
* #Character Spells Information
* CLASS:Wizard|CANCASTPERDAY:2,4(Totals the levels all up + includes attribute bonuses)
* SPELLNAME:Blah|SCHOOL:blah|SUBSCHOOL:blah|Etc
*
* completely changed due to new Spell API
*/
private void appendSpellLines(StringBuilder buffer) {
for (PCClass pcClass : charDisplay.getClassSet()) {
Collection<? extends CharacterSpell> sp = charDisplay.getCharacterSpells(pcClass);
List<CharacterSpell> classSpells = new ArrayList<>(sp);
// Add in the spells granted by objects
thePC.addBonusKnownSpellsToList(pcClass, classSpells);
Collections.sort(classSpells);
for (CharacterSpell cSpell : classSpells) {
for (SpellInfo spellInfo : cSpell.getInfoList()) {
CDOMObject owner = cSpell.getOwner();
List<? extends CDOMList<Spell>> lists = charDisplay.getSpellLists(owner);
if (SpellLevel.getFirstLevelForKey(cSpell.getSpell(), lists, thePC) < 0) {
Logging.errorPrint("Ignoring unqualified spell " + cSpell.getSpell() + " in list for class " + pcClass + ".");
continue;
}
if (spellInfo.getBook().equals(Globals.getDefaultSpellBook()) && thePC.getSpellSupport(pcClass).isAutoKnownSpell(cSpell.getSpell(), SpellLevel.getFirstLevelForKey(cSpell.getSpell(), lists, thePC), false, thePC) && thePC.getAutoSpells()) {
continue;
}
buffer.append(IOConstants.TAG_SPELLNAME).append(':');
buffer.append(EntityEncoder.encode(cSpell.getSpell().getKeyName()));
buffer.append('|');
buffer.append(IOConstants.TAG_TIMES).append(':');
buffer.append(spellInfo.getTimes());
buffer.append('|');
buffer.append(IOConstants.TAG_CLASS).append(':');
buffer.append(EntityEncoder.encode(pcClass.getKeyName()));
buffer.append('|');
buffer.append(IOConstants.TAG_SPELL_BOOK).append(':');
buffer.append(EntityEncoder.encode(spellInfo.getBook()));
buffer.append('|');
buffer.append(IOConstants.TAG_SPELLLEVEL).append(':');
buffer.append(spellInfo.getActualLevel());
if (spellInfo.getNumPages() > 0) {
buffer.append('|');
buffer.append(IOConstants.TAG_SPELLNUMPAGES).append(':');
buffer.append(spellInfo.getNumPages());
}
final List<Ability> metaFeats = spellInfo.getFeatList();
if ((metaFeats != null) && (!metaFeats.isEmpty())) {
buffer.append('|');
buffer.append(IOConstants.TAG_FEATLIST).append(':');
buffer.append('[');
String del = Constants.EMPTY_STRING;
for (Ability feat : metaFeats) {
buffer.append(del);
buffer.append(IOConstants.TAG_FEAT).append(':');
buffer.append(EntityEncoder.encode(feat.getKeyName()));
//$NON-NLS-1$
del = "|";
}
buffer.append(']');
}
buffer.append('|');
appendSourceInTaggedFormat(buffer, StringPClassUtil.getStringFor(owner.getClass()) + "|" + owner.getKeyName());
buffer.append(IOConstants.LINE_SEP);
}
}
}
}
use of pcgen.core.character.SpellInfo in project pcgen by PCGen.
the class PlayerCharacter method getCharacterSpells.
/**
* Get a list of CharacterSpells from the character spell list.
* @param spellSource
* @param aSpell
* @param book
* @param level
* @return list of CharacterSpells from the character spell list
*/
public final List<CharacterSpell> getCharacterSpells(CDOMObject spellSource, final Spell aSpell, final String book, final int level) {
List<CharacterSpell> csList = new ArrayList<>(getCharacterSpells(spellSource));
// Add in the spells granted by objects
addBonusKnownSpellsToList(spellSource, csList);
final List<CharacterSpell> aList = new ArrayList<>();
if (csList.isEmpty()) {
return aList;
}
for (CharacterSpell cs : csList) {
if ((aSpell == null) || cs.getSpell().equals(aSpell)) {
final SpellInfo si = cs.getSpellInfoFor(book, level, null);
if (si != null) {
aList.add(cs);
}
}
}
return aList;
}
use of pcgen.core.character.SpellInfo in project pcgen by PCGen.
the class PlayerCharacter method addSpell.
/**
* @param acs
* is the CharacterSpell object containing the spell which is to
* be modified
* @param aFeatList
* is the list of feats to be added to the SpellInfo object
* @param classKey
* is the name of the class whose list of character spells will
* be modified
* @param bookName
* is the name of the book for the SpellInfo object
* @param spellLevel
* is the original (unadjusted) level of the spell not including
* feat adjustments
* @param adjSpellLevel
* is the adjustedLevel (including feat adjustments) of this
* spell, it may be higher if the user chooses a higher level.
*
* @return an empty string on successful completion, otherwise the return
* value indicates the reason the add function failed.
*/
public String addSpell(CharacterSpell acs, final List<Ability> aFeatList, final String classKey, final String bookName, final int adjSpellLevel, final int spellLevel) {
if (acs == null) {
return "Invalid parameter to add spell";
}
PCClass aClass = null;
final Spell aSpell = acs.getSpell();
if ((bookName == null) || (bookName.isEmpty())) {
return "Invalid spell list/book name.";
}
if (!hasSpellBook(bookName)) {
return "Could not find spell list/book " + bookName;
}
if (classKey != null) {
aClass = getClassKeyed(classKey);
if ((aClass == null) && (classKey.lastIndexOf('(') >= 0)) {
aClass = getClassKeyed(classKey.substring(0, classKey.lastIndexOf('(')).trim());
}
}
// If this is a spellbook, the class doesn't have to be one the PC has
// already.
SpellBook spellBook = getSpellBookByName(bookName);
if (aClass == null && spellBook.getType() == SpellBook.TYPE_SPELL_BOOK) {
aClass = Globals.getContext().getReferenceContext().silentlyGetConstructedCDOMObject(PCClass.class, classKey);
if ((aClass == null) && (classKey.lastIndexOf('(') >= 0)) {
aClass = Globals.getContext().getReferenceContext().silentlyGetConstructedCDOMObject(PCClass.class, classKey.substring(0, classKey.lastIndexOf('(')).trim());
}
}
if (aClass == null) {
return "No class keyed " + classKey;
}
if (!aClass.getSafe(ObjectKey.MEMORIZE_SPELLS) && !bookName.equals(Globals.getDefaultSpellBook())) {
return aClass.getDisplayName() + " can only add to " + Globals.getDefaultSpellBook();
}
// don't allow adding spells which are not qualified for.
if (!aSpell.qualifies(this, aSpell)) {
return "You do not qualify for " + acs.getSpell().getDisplayName() + ".";
}
// which can be the case for some spells, then allow it.
if (spellBook.getType() != SpellBook.TYPE_SPELL_BOOK && !acs.isSpecialtySpell(this) && SpellCountCalc.isProhibited(aSpell, aClass, this)) {
return acs.getSpell().getDisplayName() + " is prohibited.";
}
// Now let's see if they should be able to add this spell
// first check for known/cast/threshold
final int known = this.getSpellSupport(aClass).getKnownForLevel(spellLevel, this);
int specialKnown = 0;
final int cast = this.getSpellSupport(aClass).getCastForLevel(adjSpellLevel, bookName, true, true, this);
SpellCountCalc.memorizedSpellForLevelBook(this, aClass, adjSpellLevel, bookName);
final boolean isDefault = bookName.equals(Globals.getDefaultSpellBook());
if (isDefault) {
specialKnown = this.getSpellSupport(aClass).getSpecialtyKnownForLevel(spellLevel, this);
}
int numPages = 0;
// sk4p 13 Dec 2002
if (spellBook.getType() == SpellBook.TYPE_SPELL_BOOK) {
// If this is a spellbook rather than known spells
// or prepared spells, then let them add spells up to
// the page limit of the book.
// Explicitly should *not* set the dirty flag to true.
spellLevelTemp = spellLevel;
/*
* TODO Need to understand more about this context of formula
* resolution (in context of a spell??) in order to understand how
* to put this method into the Formula interface
*/
numPages = getVariableValue(acs, spellBook.getPageFormula().toString(), "").intValue();
// Check number of pages remaining in the book
if (numPages + spellBook.getNumPagesUsed() > spellBook.getNumPages()) {
return "There are not enough pages left to add this spell to the spell book.";
}
spellBook.setNumPagesUsed(numPages + spellBook.getNumPagesUsed());
spellBook.setNumSpells(spellBook.getNumSpells() + 1);
} else if (!aClass.getSafe(ObjectKey.MEMORIZE_SPELLS) && !availableSpells(adjSpellLevel, aClass, bookName, true, acs.isSpecialtySpell(this))) {
String ret;
int maxAllowed;
// If this were a specialty spell, would there be room?
if (!acs.isSpecialtySpell(this) && availableSpells(adjSpellLevel, aClass, bookName, true, true)) {
ret = "Your remaining slot(s) must be filled with your speciality.";
maxAllowed = known;
} else {
ret = "You can only learn " + (known + specialKnown) + " spells for level " + adjSpellLevel + " \nand there are no higher-level slots available.";
maxAllowed = known + specialKnown;
}
int memTot = SpellCountCalc.memorizedSpellForLevelBook(this, aClass, adjSpellLevel, bookName);
int spellDifference = maxAllowed - memTot;
if (spellDifference > 0) {
ret += "\n" + spellDifference + " spells from lower levels are using slots for this level.";
}
return ret;
} else if (aClass.getSafe(ObjectKey.MEMORIZE_SPELLS) && !isDefault && !availableSpells(adjSpellLevel, aClass, bookName, false, acs.isSpecialtySpell(this))) {
String ret;
int maxAllowed;
if (!acs.isSpecialtySpell(this) && availableSpells(adjSpellLevel, aClass, bookName, false, true)) {
ret = "Your remaining slot(s) must be filled with your speciality or domain.";
maxAllowed = this.getSpellSupport(aClass).getCastForLevel(adjSpellLevel, bookName, false, true, this);
} else if (acs.isSpecialtySpell(this) && availableSpells(adjSpellLevel, aClass, bookName, false, false)) {
ret = "Your remaining slot(s) must be filled with spells not from your speciality or domain.";
maxAllowed = this.getSpellSupport(aClass).getCastForLevel(adjSpellLevel, bookName, false, true, this);
} else {
ret = "You can only prepare " + cast + " spells for level " + adjSpellLevel + " \nand there are no higher-level slots available.";
maxAllowed = cast;
int memTot = SpellCountCalc.memorizedSpellForLevelBook(this, aClass, adjSpellLevel, bookName);
int spellDifference = maxAllowed - memTot;
if (spellDifference > 0) {
ret += "\n" + spellDifference + " spells from lower levels are using slots for this level.";
}
}
return ret;
}
// determine if this spell already exists
// for this character in this book at this level
SpellInfo si = null;
final List<CharacterSpell> acsList = getCharacterSpells(aClass, acs.getSpell(), bookName, adjSpellLevel);
if (!acsList.isEmpty()) {
for (int x = acsList.size() - 1; x >= 0; x--) {
final CharacterSpell c = acsList.get(x);
if (!c.equals(acs)) {
acsList.remove(x);
}
}
}
final boolean isEmpty = acsList.isEmpty();
if (!isEmpty) {
// use the passed in spell.
if (acsList.size() == 1) {
final CharacterSpell tcs = acsList.get(0);
si = tcs.getSpellInfoFor(bookName, adjSpellLevel, aFeatList);
} else {
si = acs.getSpellInfoFor(bookName, adjSpellLevel, aFeatList);
}
}
if (si != null) {
// otherwise increment the number of times memorised
if (isDefault) {
return "The Known Spells spellbook contains all spells of this level that you know. You cannot place spells in multiple times.";
}
si.setTimes(si.getTimes() + 1);
} else {
if (isEmpty && !containsCharacterSpell(aClass, acs)) {
addCharacterSpell(aClass, acs);
} else if (isEmpty) {
// Make sure that we are working on the same spell object, not just the same spell
for (CharacterSpell characterSpell : getCharacterSpells(aClass)) {
if (characterSpell.equals(acs)) {
acs = characterSpell;
}
}
}
si = acs.addInfo(spellLevel, adjSpellLevel, 1, bookName, aFeatList);
}
// Set number of pages on the spell
si.setNumPages(si.getNumPages() + numPages);
setDirty(true);
return "";
}
use of pcgen.core.character.SpellInfo in project pcgen by PCGen.
the class SpellSupportFacadeImpl method buildKnownPreparedSpellsForCDOMObject.
private void buildKnownPreparedSpellsForCDOMObject(CDOMObject pObject) {
Collection<? extends CharacterSpell> sp = charDisplay.getCharacterSpells(pObject);
List<CharacterSpell> cSpells = new ArrayList<>(sp);
// Add in the spells granted by objects
pc.addBonusKnownSpellsToList(pObject, cSpells);
PCClass pcClass = (PCClass) (pObject instanceof PCClass ? pObject : null);
for (CharacterSpell charSpell : cSpells) {
for (SpellInfo spellInfo : charSpell.getInfoList()) {
// Create SpellNodeImpl for each spell
String book = spellInfo.getBook();
boolean isKnown = Globals.getDefaultSpellBook().equals(book);
SpellFacadeImplem spellImplem = new SpellFacadeImplem(pc, charSpell.getSpell(), charSpell, spellInfo);
SpellNodeImpl node;
if (pcClass != null) {
node = new SpellNodeImpl(spellImplem, pcClass, String.valueOf(spellInfo.getActualLevel()), getRootNode(book));
} else {
node = new SpellNodeImpl(spellImplem, String.valueOf(spellInfo.getActualLevel()), getRootNode(book));
}
if (spellInfo.getTimes() > 1) {
node.addCount(spellInfo.getTimes() - 1);
}
boolean isSpellBook = charDisplay.getSpellBookByName(book).getType() == SpellBook.TYPE_SPELL_BOOK;
// Add to list
if (isKnown) {
allKnownSpellNodes.addElement(node);
knownSpellNodes.addElement(node);
} else if (isSpellBook) {
bookSpellNodes.addElement(node);
} else if (pObject instanceof Race) {
allKnownSpellNodes.addElement(node);
} else {
preparedSpellNodes.addElement(node);
}
}
}
}
Aggregations