/*
* Copyright (c) 2008 Tom Parker <thpr@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package plugin.lsttokens.race;
import pcgen.base.formula.AddingFormula;
import pcgen.base.formula.DividingFormula;
import pcgen.base.formula.MultiplyingFormula;
import pcgen.base.formula.SubtractingFormula;
import pcgen.cdom.base.CDOMReference;
import pcgen.cdom.base.Constants;
import pcgen.cdom.content.HitDie;
import pcgen.cdom.content.Processor;
import pcgen.cdom.enumeration.ObjectKey;
import pcgen.cdom.processor.ContextProcessor;
import pcgen.cdom.processor.HitDieFormula;
import pcgen.cdom.processor.HitDieLock;
import pcgen.cdom.processor.HitDieStep;
import pcgen.core.PCClass;
import pcgen.core.Race;
import pcgen.rules.context.LoadContext;
import pcgen.rules.persistence.token.AbstractNonEmptyToken;
import pcgen.rules.persistence.token.CDOMPrimaryToken;
import pcgen.rules.persistence.token.ParseResult;
/**
* Class deals with HITDIE Token
*/
public class HitdieToken extends AbstractNonEmptyToken<Race> implements
CDOMPrimaryToken<Race>
{
private static final Class<PCClass> PCCLASS_CLASS = PCClass.class;
@Override
public String getTokenName()
{
return "HITDIE";
}
@Override
protected ParseResult parseNonEmptyToken(LoadContext context, Race race,
String value)
{
try
{
String lock = value;
int pipeLoc = lock.indexOf(Constants.PIPE);
if (pipeLoc != lock.lastIndexOf(Constants.PIPE))
{
return new ParseResult.Fail(getTokenName() + " has more than one pipe, "
+ "is not of format: <int>[|<prereq>]", context);
}
// Do not initialize, null is significant
CDOMReference<PCClass> owner = null;
if (pipeLoc != -1)
{
// Has a limitation
String lockPre = lock.substring(pipeLoc + 1);
if (lockPre.startsWith("CLASS.TYPE="))
{
String substring = lock.substring(pipeLoc + 12);
if (substring.isEmpty())
{
return new ParseResult.Fail(
"Cannot have Empty Type Limitation in " + getTokenName()
+ ": " + value, context);
}
ParseResult pr = checkForIllegalSeparator('.', substring);
if (!pr.passed())
{
return pr;
}
owner = context.getReferenceContext().getCDOMTypeReference(PCCLASS_CLASS,
substring.split("\\."));
}
else if (lockPre.startsWith(Constants.LST_CLASS_EQUAL))
{
String substring = lock.substring(pipeLoc + 7);
if (substring.isEmpty())
{
return new ParseResult.Fail(
"Cannot have Empty Class Limitation in " + getTokenName()
+ ": " + value, context);
}
owner = context.getReferenceContext().getCDOMReference(PCCLASS_CLASS,
substring);
}
else
{
return new ParseResult.Fail("Invalid Limitation in HITDIE: "
+ lockPre, context);
}
lock = lock.substring(0, pipeLoc);
}
Processor<HitDie> hdm;
if (lock.startsWith("%/"))
{
// HITDIE:%/num --- divides the classes hit die by num.
int denom = Integer.parseInt(lock.substring(2));
if (denom <= 0)
{
return new ParseResult.Fail(getTokenName()
+ " was expecting a Positive Integer "
+ "for dividing Lock, was : " + lock.substring(2), context);
}
hdm = new HitDieFormula(new DividingFormula(denom));
}
else if (lock.startsWith("%*"))
{
// HITDIE:%*num --- multiplies the classes hit die by num.
int mult = Integer.parseInt(lock.substring(2));
if (mult <= 0)
{
return new ParseResult.Fail(getTokenName()
+ " was expecting a Positive "
+ "Integer for multiplying Lock, was : "
+ lock.substring(2), context);
}
hdm = new HitDieFormula(new MultiplyingFormula(mult));
}
else if (lock.startsWith("%+"))
{
// possibly redundant with BONUS:HD MAX|num
// HITDIE:%+num --- adds num to the classes hit die.
int add = Integer.parseInt(lock.substring(2));
if (add <= 0)
{
return new ParseResult.Fail(getTokenName()
+ " was expecting a Positive "
+ "Integer for adding Lock, was : "
+ lock.substring(2), context);
}
hdm = new HitDieFormula(new AddingFormula(add));
}
else if (lock.startsWith("%-"))
{
// HITDIE:%-num --- subtracts num from the classes hit die.
// possibly redundant with BONUS:HD MAX|num if that will
// take negative numbers.
int sub = Integer.parseInt(lock.substring(2));
if (sub <= 0)
{
return new ParseResult.Fail(getTokenName()
+ " was expecting a Positive "
+ "Integer for subtracting Lock, was : "
+ lock.substring(2), context);
}
hdm = new HitDieFormula(new SubtractingFormula(sub));
}
else if (lock.startsWith("%up"))
{
// HITDIE:%upnum --- moves the hit die num steps up the die size
// list d4,d6,d8,d10,d12. Stops at d12.
int steps = Integer.parseInt(lock.substring(3));
if (steps <= 0)
{
return new ParseResult.Fail("Invalid Step Count: " + steps + " in "
+ getTokenName() + " up (must be positive)", context);
}
if (steps >= 5)
{
return new ParseResult.Fail("Invalid Step Count: " + steps + " in "
+ getTokenName() + " up (too large)", context);
}
hdm = new HitDieStep(steps, new HitDie(12));
}
else if (lock.startsWith("%Hup"))
{
// HITDIE:%upnum --- moves the hit die num steps up the die size
// list d4,d6,d8,d10,d12. Stops at d12.
int steps = Integer.parseInt(lock.substring(4));
if (steps <= 0)
{
return new ParseResult.Fail("Invalid Step Count: " + steps + " in "
+ getTokenName(), context);
}
hdm = new HitDieStep(steps, null);
}
else if (lock.startsWith("%down"))
{
// HITDIE:%downnum --- moves the hit die num steps down the die
// size
// list d4,d6,d8,d10,d12. Stops at d4.
int steps = Integer.parseInt(lock.substring(5));
if (steps <= 0)
{
return new ParseResult.Fail("Invalid Step Count: " + steps + " in "
+ getTokenName() + " down (must be positive)", context);
}
if (steps >= 5)
{
return new ParseResult.Fail("Invalid Step Count: " + steps + " in "
+ getTokenName() + " down (too large)", context);
}
hdm = new HitDieStep(-steps, new HitDie(4));
}
else if (lock.startsWith("%Hdown"))
{
// HITDIE:%downnum --- moves the hit die num steps down the die
// size
// list. No limit.
int steps = Integer.parseInt(lock.substring(6));
if (steps <= 0)
{
return new ParseResult.Fail("Invalid Step Count: " + steps + " in "
+ getTokenName(), context);
}
hdm = new HitDieStep(-steps, null);
}
else
{
int i = Integer.parseInt(lock);
if (i <= 0)
{
return new ParseResult.Fail("Invalid HitDie: " + i + " in "
+ getTokenName(), context);
}
// HITDIE:num --- sets the hit die to num regardless of class.
hdm = new HitDieLock(new HitDie(i));
}
Processor<HitDie> mod = owner == null ? hdm
: new ContextProcessor<>(hdm, owner);
context.getObjectContext().put(race, ObjectKey.HITDIE, mod);
return ParseResult.SUCCESS;
}
catch (NumberFormatException nfe)
{
return new ParseResult.Fail("Invalid Number (must be an Integer) in " + getTokenName() + ": "
+ nfe.getLocalizedMessage(), context);
}
}
@Override
public String[] unparse(LoadContext context, Race race)
{
Processor<HitDie> hdcf = context.getObjectContext().getObject(race,
ObjectKey.HITDIE);
if (hdcf == null)
{
return null;
}
return new String[] { hdcf.getLSTformat() };
}
@Override
public Class<Race> getTokenClass()
{
return Race.class;
}
}