use of pcgen.cdom.list.ClassSpellList in project pcgen by PCGen.
the class SpellLevel method isLevel.
/**
* isLevel(int aLevel)
*
* @param aLevel
* level of the spell
* @param aPC
* @return true if the spell is of the given level in any spell list
*/
public static boolean isLevel(Spell sp, int aLevel, PlayerCharacter aPC) {
Integer levelKey = aLevel;
MasterListInterface masterLists = SettingsHandler.getGame().getMasterLists();
for (PCClass pcc : aPC.getClassSet()) {
ClassSpellList csl = pcc.get(ObjectKey.CLASS_SPELLLIST);
Collection<AssociatedPrereqObject> assoc = masterLists.getAssociations(csl, sp);
if (assoc != null) {
for (AssociatedPrereqObject apo : assoc) {
if (PrereqHandler.passesAll(apo.getPrerequisiteList(), aPC, sp)) {
if (levelKey.equals(apo.getAssociation(AssociationKey.SPELL_LEVEL))) {
return true;
}
}
}
}
}
for (Domain domain : aPC.getDomainSet()) {
DomainSpellList dsl = domain.get(ObjectKey.DOMAIN_SPELLLIST);
Collection<AssociatedPrereqObject> assoc = masterLists.getAssociations(dsl, sp);
if (assoc != null) {
for (AssociatedPrereqObject apo : assoc) {
if (PrereqHandler.passesAll(apo.getPrerequisiteList(), aPC, sp)) {
if (levelKey.equals(apo.getAssociation(AssociationKey.SPELL_LEVEL))) {
return true;
}
}
}
}
}
return false;
}
use of pcgen.cdom.list.ClassSpellList 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.cdom.list.ClassSpellList in project pcgen by PCGen.
the class SpellBuilderFacadeImpl method addSpellInfoToList.
private void addSpellInfoToList(final Spell aSpell, List<PCClass> classes, List<Domain> domains, String spellType) {
Set<String> unfoundItems = new HashSet<>();
final HashMapToList<CDOMList<Spell>, Integer> levelInfo = character.getSpellLevelInfo(aSpell);
if ((levelInfo == null) || (levelInfo.isEmpty())) {
return;
}
for (CDOMList<Spell> spellList : levelInfo.getKeySet()) {
if (spellList instanceof ClassSpellList) {
String key = spellList.getKeyName();
final PCClass aClass = Globals.getContext().getReferenceContext().silentlyGetConstructedCDOMObject(PCClass.class, key);
if (aClass != null) {
if (!("".equals(spellType)) && (!spellType.contains(aClass.getSpellType()))) {
continue;
}
if (!classes.contains(aClass)) {
classes.add(aClass);
}
} else {
key = 'C' + key;
if (!unfoundItems.contains(key)) {
unfoundItems.add(key);
Logging.errorPrint("Class " + key.substring(1) + " not found. Was used in spell " + aSpell);
}
}
} else if (spellList instanceof DomainSpellList) {
if (!("".equals(spellType)) && (!spellType.contains("Divine"))) {
continue;
}
String key = spellList.getKeyName();
final Domain aDomain = Globals.getContext().getReferenceContext().silentlyGetConstructedCDOMObject(Domain.class, key);
if (aDomain != null) {
if (!domains.contains(aDomain)) {
domains.add(aDomain);
}
} else {
key = 'D' + key;
if (!unfoundItems.contains(key)) {
unfoundItems.add(key);
Logging.errorPrint("Domain " + key.substring(1) + " not found. Was used in spell " + aSpell);
}
}
} else {
Logging.errorPrint("Unknown spell source: " + spellList);
}
}
}
use of pcgen.cdom.list.ClassSpellList in project pcgen by PCGen.
the class AbstractReferenceContext method buildDerivedObjects.
public void buildDerivedObjects() {
Collection<Domain> domains = getConstructedCDOMObjects(Domain.class);
for (Domain d : domains) {
DomainSpellList dsl = constructCDOMObject(DOMAINSPELLLIST_CLASS, d.getKeyName());
dsl.addType(Type.DIVINE);
d.put(ObjectKey.DOMAIN_SPELLLIST, dsl);
}
Collection<PCClass> classes = getConstructedCDOMObjects(PCClass.class);
for (PCClass pcc : classes) {
String key = pcc.getKeyName();
ClassSkillList skl = constructCDOMObject(CLASSSKILLLIST_CLASS, key);
boolean isMonster = pcc.isMonster();
if (isMonster) {
skl.addType(Type.MONSTER);
}
pcc.put(ObjectKey.CLASS_SKILLLIST, skl);
/*
* TODO Need to limit which are built to only spellcasters... If you
* do that, please see TO-DO in SpellListFacet
*/
ClassSpellList csl = constructCDOMObject(CLASSSPELLLIST_CLASS, key);
FactKey<String> fk = FactKey.valueOf("SpellType");
String spelltype = pcc.getResolved(fk);
if (spelltype != null) {
csl.addType(Type.getConstant(spelltype));
}
pcc.put(ObjectKey.CLASS_SPELLLIST, csl);
// for (CDOMSubClass subcl : subclasses)
if (pcc.containsListFor(ListKey.SUB_CLASS)) {
SubClassCategory cat = SubClassCategory.getConstant(key);
boolean needSelf = pcc.getSafe(ObjectKey.ALLOWBASECLASS).booleanValue();
for (SubClass subcl : pcc.getListFor(ListKey.SUB_CLASS)) {
String subKey = subcl.getKeyName();
if (subKey.equalsIgnoreCase(key)) {
//Now an error to explicitly create this match, see CODE-1928
Logging.errorPrint("Cannot explicitly create a SUBCLASS that matches the parent class. " + "Use ALLOWBASECLASS. " + "Tokens on the offending SUBCLASS line will be ignored");
pcc.removeFromListFor(ListKey.SUB_CLASS, subcl);
continue;
}
skl = constructCDOMObject(CLASSSKILLLIST_CLASS, subKey);
if (isMonster) {
skl.addType(Type.MONSTER);
}
subcl.put(ObjectKey.CLASS_SKILLLIST, skl);
// TODO Need to limit which are built to only
// spellcasters...
csl = constructCDOMObject(CLASSSPELLLIST_CLASS, subKey);
if (spelltype != null) {
csl.addType(Type.getConstant(spelltype));
}
subcl.put(ObjectKey.CLASS_SPELLLIST, csl);
// constructCDOMObject(SPELLPROGRESSION_CLASS, subKey);
/*
* CONSIDER For right now, this is easiest to do here, though
* doing this 'live' may be more appropriate in the end.
*/
subcl.setCDOMCategory(cat);
importObject(subcl);
}
if (needSelf) {
SubClass self = constructCDOMObject(SUBCLASS_CLASS, key);
reassociateCategory(SUBCLASS_CLASS, self, null, cat);
}
}
}
}
use of pcgen.cdom.list.ClassSpellList in project pcgen by PCGen.
the class ClassesToken method unparse.
@Override
public String[] unparse(LoadContext context, Spell spell) {
DoubleKeyMapToList<Prerequisite, Integer, CDOMReference<ClassSpellList>> dkmtl = new DoubleKeyMapToList<>();
List<String> list = new ArrayList<>();
Changes<CDOMReference<ClassSpellList>> masterChanges = context.getListContext().getMasterListChanges(getTokenName(), spell, SPELLLIST_CLASS);
if (masterChanges.includesGlobalClear()) {
list.add(Constants.LST_DOT_CLEAR_ALL);
}
if (masterChanges.hasRemovedItems()) {
for (CDOMReference<ClassSpellList> swl : masterChanges.getRemoved()) {
AssociatedChanges<Spell> changes = context.getListContext().getChangesInMasterList(getTokenName(), spell, swl);
MapToList<Spell, AssociatedPrereqObject> map = changes.getRemovedAssociations();
if (map != null && !map.isEmpty()) {
for (Spell added : map.getKeySet()) {
if (!spell.getLSTformat().equals(added.getLSTformat())) {
context.addWriteMessage("Spell " + getTokenName() + " token cannot remove another Spell " + "(must only remove itself)");
return null;
}
for (AssociatedPrereqObject assoc : map.getListFor(added)) {
List<Prerequisite> prereqs = assoc.getPrerequisiteList();
if (prereqs != null && !prereqs.isEmpty()) {
context.addWriteMessage("Incoming Remove " + "Edge to " + spell.getKeyName() + " had a " + "Prerequisite: " + prereqs.size());
return null;
}
dkmtl.addToListFor(null, -1, swl);
}
}
}
}
}
for (CDOMReference<ClassSpellList> swl : masterChanges.getAdded()) {
AssociatedChanges<Spell> changes = context.getListContext().getChangesInMasterList(getTokenName(), spell, swl);
Collection<Spell> removedItems = changes.getRemoved();
if (removedItems != null && !removedItems.isEmpty() || changes.includesGlobalClear()) {
context.addWriteMessage(getTokenName() + " does not support .CLEAR.");
return null;
}
MapToList<Spell, AssociatedPrereqObject> map = changes.getAddedAssociations();
if (map != null && !map.isEmpty()) {
for (Spell added : map.getKeySet()) {
if (!spell.getLSTformat().equals(added.getLSTformat())) {
context.addWriteMessage("Spell " + getTokenName() + " token cannot allow another Spell " + "(must only allow itself)");
return null;
}
for (AssociatedPrereqObject assoc : map.getListFor(added)) {
List<Prerequisite> prereqs = assoc.getPrerequisiteList();
Prerequisite prereq;
if (prereqs == null || prereqs.isEmpty()) {
prereq = null;
} else if (prereqs.size() == 1) {
prereq = prereqs.get(0);
} else {
context.addWriteMessage("Incoming Edge to " + spell.getKeyName() + " had more than one " + "Prerequisite: " + prereqs.size());
return null;
}
Integer level = assoc.getAssociation(AssociationKey.SPELL_LEVEL);
if (level == null) {
context.addWriteMessage("Incoming Allows Edge to " + spell.getKeyName() + " had no Spell Level defined");
return null;
}
if (level.intValue() < 0) {
context.addWriteMessage("Incoming Allows Edge to " + spell.getKeyName() + " had invalid Level: " + level + ". Must be >= 0.");
return null;
}
dkmtl.addToListFor(prereq, level, swl);
}
}
}
}
if (dkmtl.isEmpty()) {
if (list.isEmpty()) {
// Legal if no CLASSES was present in the Spell
return null;
} else {
return list.toArray(new String[list.size()]);
}
}
PrerequisiteWriter prereqWriter = new PrerequisiteWriter();
SortedSet<CDOMReference<ClassSpellList>> set = new TreeSet<>(ReferenceUtilities.REFERENCE_SORTER);
SortedSet<Integer> levelSet = new TreeSet<>();
for (Prerequisite prereq : dkmtl.getKeySet()) {
StringBuilder sb = new StringBuilder();
boolean needPipe = false;
levelSet.clear();
levelSet.addAll(dkmtl.getSecondaryKeySet(prereq));
for (Integer i : levelSet) {
set.clear();
set.addAll(dkmtl.getListFor(prereq, i));
if (needPipe) {
sb.append(Constants.PIPE);
}
sb.append(ReferenceUtilities.joinLstFormat(set, Constants.COMMA));
sb.append('=').append(i);
needPipe = true;
}
if (prereq != null) {
sb.append('[');
StringWriter swriter = new StringWriter();
try {
prereqWriter.write(swriter, prereq);
} catch (PersistenceLayerException e) {
context.addWriteMessage("Error writing Prerequisite: " + e);
return null;
}
sb.append(swriter.toString());
sb.append(']');
}
list.add(sb.toString());
}
return list.toArray(new String[list.size()]);
}
Aggregations