Search in sources :

Example 6 with CharacterSpell

use of pcgen.core.character.CharacterSpell 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 "";
}
Also used : SpellBook(pcgen.core.character.SpellBook) CharacterSpell(pcgen.core.character.CharacterSpell) Spell(pcgen.core.spell.Spell) CharacterSpell(pcgen.core.character.CharacterSpell) SpellInfo(pcgen.core.character.SpellInfo)

Example 7 with CharacterSpell

use of pcgen.core.character.CharacterSpell in project pcgen by PCGen.

the class SpellSupportForPCClass method getCastForLevel.

public int getCastForLevel(int spellLevel, String bookName, boolean includeAdj, boolean limitByStat, PlayerCharacter aPC) {
    int pcLevel = aPC.getLevel(source);
    int total = 0;
    int stat = 0;
    final String classKeyName = "CLASS." + source.getKeyName();
    final String levelSpellLevel = ";LEVEL." + spellLevel;
    final String allSpellLevel = ";LEVEL.All";
    pcLevel += (int) aPC.getTotalBonusTo("PCLEVEL", source.getKeyName());
    pcLevel += (int) aPC.getTotalBonusTo("PCLEVEL", "TYPE." + source.getSpellType());
    if (getNumFromCastList(pcLevel, spellLevel, aPC) < 0) {
        // certain feats
        return (int) aPC.getTotalBonusTo("SPELLCAST", classKeyName + levelSpellLevel);
    }
    total += (int) aPC.getTotalBonusTo("SPELLCAST", classKeyName + levelSpellLevel);
    total += (int) aPC.getTotalBonusTo("SPELLCAST", "TYPE." + source.getSpellType() + levelSpellLevel);
    total += (int) aPC.getTotalBonusTo("SPELLCAST", "CLASS.Any" + levelSpellLevel);
    total += (int) aPC.getTotalBonusTo("SPELLCAST", classKeyName + allSpellLevel);
    total += (int) aPC.getTotalBonusTo("SPELLCAST", "TYPE." + source.getSpellType() + allSpellLevel);
    total += (int) aPC.getTotalBonusTo("SPELLCAST", "CLASS.Any" + allSpellLevel);
    PCStat aStat = source.bonusSpellStat();
    String statString = Constants.NONE;
    if (aStat != null) {
        stat = aPC.getTotalStatFor(aStat);
        statString = aStat.getKeyName();
    }
    final int bonusStat = (int) aPC.getTotalBonusTo("STAT", "CAST." + statString) + (int) aPC.getTotalBonusTo("STAT", "BASESPELLSTAT") + (int) aPC.getTotalBonusTo("STAT", "BASESPELLSTAT;CLASS=" + source.getKeyName());
    if (limitByStat) {
        PCStat ss = source.baseSpellStat();
        if (ss != null) {
            final int maxSpellLevel = aPC.getVariableValue("MAXLEVELSTAT=" + ss.getKeyName(), "").intValue();
            if ((maxSpellLevel + bonusStat) < spellLevel) {
                return total;
            }
        }
    }
    stat += bonusStat;
    // Now we decide whether to adjust the number of slots down
    // the road by adding specialty slots.
    // Reworked to consider the fact that a lower-level
    // specialty spell can go into this level of specialty slot
    //
    int adj = 0;
    if (includeAdj && !bookName.equals(Globals.getDefaultSpellBook()) && (aPC.hasAssocs(source, AssociationKey.SPECIALTY) || aPC.hasDomains())) {
        // we might wind up using THIS level's slots for them.
        for (int ix = 0; ix <= spellLevel; ++ix) {
            Collection<CharacterSpell> aList = aPC.getCharacterSpells(source, ix);
            Collection<Spell> bList = new ArrayList<>();
            if (!aList.isEmpty()) {
                // getNumFromCastList above would have returned -1
                if ((ix > 0) && "DIVINE".equalsIgnoreCase(source.getSpellType())) {
                    for (Domain d : aPC.getDomainSet()) {
                        if (source.getKeyName().equals(aPC.getDomainSource(d).getPcclass().getKeyName())) {
                            bList = aPC.getSpellsIn(d.get(ObjectKey.DOMAIN_SPELLLIST), ix);
                        }
                    }
                }
                for (CharacterSpell cs : aList) {
                    int x = -1;
                    if (!bList.isEmpty()) {
                        if (bList.contains(cs.getSpell())) {
                            x = 0;
                        }
                    } else {
                        x = cs.getInfoIndexFor(aPC, Constants.EMPTY_STRING, ix, 1);
                    }
                    if (x > -1) {
                        PCClass target = source;
                        String subClassKey = aPC.getSubClassName(source);
                        if (subClassKey != null && (!subClassKey.isEmpty()) && !subClassKey.equals(Constants.NONE)) {
                            target = source.getSubClassKeyed(subClassKey);
                        }
                        adj = aPC.getSpellSupport(target).getSpecialtyKnownForLevel(spellLevel, aPC);
                        break;
                    }
                }
            }
            if (adj > 0) {
                break;
            }
        }
    // end of looping up to this level looking for specialty spells that
    // can be cast
    }
    // end of deciding whether there are specialty slots to distribute
    int mult = (int) aPC.getTotalBonusTo("SPELLCASTMULT", classKeyName + levelSpellLevel);
    mult += (int) aPC.getTotalBonusTo("SPELLCASTMULT", "TYPE." + source.getSpellType() + levelSpellLevel);
    if (mult < 1) {
        mult = 1;
    }
    final int t = getNumFromCastList(pcLevel, spellLevel, aPC);
    total += ((t * mult) + adj);
    BonusSpellInfo bsi = Globals.getContext().getReferenceContext().silentlyGetConstructedCDOMObject(BonusSpellInfo.class, String.valueOf(spellLevel));
    if ((bsi != null) && bsi.isValid()) {
        int base = bsi.getStatScore();
        if (stat >= base) {
            int range = bsi.getStatRange();
            total += Math.max(0, (stat - base + range) / range);
        }
    }
    return total;
}
Also used : ArrayList(java.util.ArrayList) BonusSpellInfo(pcgen.cdom.content.BonusSpellInfo) CharacterSpell(pcgen.core.character.CharacterSpell) Spell(pcgen.core.spell.Spell) CharacterSpell(pcgen.core.character.CharacterSpell)

Example 8 with CharacterSpell

use of pcgen.core.character.CharacterSpell in project pcgen by PCGen.

the class PlayerCharacter method processSpellBookRemoval.

private void processSpellBookRemoval(String aName) {
    spellBookFacet.removeBookNamed(id, aName);
    setDirty(true);
    for (PCClass pcClass : getClassSet()) {
        for (CharacterSpell cs : getCharacterSpells(pcClass, aName)) {
            cs.removeSpellInfo(cs.getSpellInfoFor(aName, -1));
        }
    }
}
Also used : CharacterSpell(pcgen.core.character.CharacterSpell)

Example 9 with CharacterSpell

use of pcgen.core.character.CharacterSpell in project pcgen by PCGen.

the class SpellSupportFacadeImpl method buildAvailableNodes.

/**
	 * Construct the list of available spells for the character. 
	 */
private void buildAvailableNodes() {
    availableSpellNodes.clearContents();
    // Scan character classes for spell classes
    List<PCClass> classList = getCharactersSpellcastingClasses();
    // Look at each spell on each spellcasting class
    for (PCClass pcClass : classList) {
        DoubleKeyMapToList<SpellFacade, String, SpellNode> existingSpells = buildExistingSpellMap(availableSpellNodes, pcClass);
        for (Spell spell : pc.getAllSpellsInLists(charDisplay.getSpellLists(pcClass))) {
            // Create SpellNodeImpl for each spell
            CharacterSpell charSpell = new CharacterSpell(pcClass, spell);
            SpellFacadeImplem spellImplem = new SpellFacadeImplem(pc, spell, charSpell, null);
            HashMapToList<CDOMList<Spell>, Integer> levelInfo = pc.getSpellLevelInfo(spell);
            for (CDOMList<Spell> spellList : charDisplay.getSpellLists(pcClass)) {
                List<Integer> levels = levelInfo.getListFor(spellList);
                if (levels != null) {
                    for (Integer level : levels) {
                        SpellNodeImpl node = new SpellNodeImpl(spellImplem, pcClass, String.valueOf(level), null);
                        if (!existingSpells.containsInList(spellImplem, node.getSpellLevel(), node)) {
                            // Add to list
                            availableSpellNodes.addElement(node);
                        }
                    }
                }
            }
        }
    }
}
Also used : PCClass(pcgen.core.PCClass) SpellSupportForPCClass(pcgen.core.SpellSupportForPCClass) Spell(pcgen.core.spell.Spell) CharacterSpell(pcgen.core.character.CharacterSpell) CharacterSpell(pcgen.core.character.CharacterSpell) CDOMList(pcgen.cdom.base.CDOMList) SpellFacade(pcgen.facade.core.SpellFacade)

Example 10 with CharacterSpell

use of pcgen.core.character.CharacterSpell 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);
            }
        }
    }
}
Also used : Race(pcgen.core.Race) ArrayList(java.util.ArrayList) CharacterSpell(pcgen.core.character.CharacterSpell) PCClass(pcgen.core.PCClass) SpellSupportForPCClass(pcgen.core.SpellSupportForPCClass) SpellInfo(pcgen.core.character.SpellInfo)

Aggregations

CharacterSpell (pcgen.core.character.CharacterSpell)41 Spell (pcgen.core.spell.Spell)22 ArrayList (java.util.ArrayList)16 PCClass (pcgen.core.PCClass)12 SpellInfo (pcgen.core.character.SpellInfo)12 PObject (pcgen.core.PObject)7 SpellBook (pcgen.core.character.SpellBook)6 Ability (pcgen.core.Ability)5 StringTokenizer (java.util.StringTokenizer)4 CNAbility (pcgen.cdom.content.CNAbility)4 Formula (pcgen.base.formula.Formula)3 CDOMList (pcgen.cdom.base.CDOMList)3 CDOMObject (pcgen.cdom.base.CDOMObject)3 PlayerCharacter (pcgen.core.PlayerCharacter)3 AssociatedPrereqObject (pcgen.cdom.base.AssociatedPrereqObject)2 CDOMReference (pcgen.cdom.base.CDOMReference)2 ClassSource (pcgen.cdom.helper.ClassSource)2 SpellSchool (pcgen.cdom.identifier.SpellSchool)2 ClassSpellList (pcgen.cdom.list.ClassSpellList)2 DomainSpellList (pcgen.cdom.list.DomainSpellList)2