/*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package lineage2.gameserver.skills;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import javax.xml.parsers.DocumentBuilderFactory;
import lineage2.gameserver.model.Skill;
import lineage2.gameserver.skills.effects.EffectTemplate;
import lineage2.gameserver.stats.StatTemplate;
import lineage2.gameserver.stats.Stats;
import lineage2.gameserver.stats.conditions.Condition;
import lineage2.gameserver.stats.conditions.ConditionFirstEffectSuccess;
import lineage2.gameserver.stats.conditions.ConditionGameTime;
import lineage2.gameserver.stats.conditions.ConditionGameTime.CheckGameTime;
import lineage2.gameserver.stats.conditions.ConditionHasSkill;
import lineage2.gameserver.stats.conditions.ConditionLogicAnd;
import lineage2.gameserver.stats.conditions.ConditionLogicNot;
import lineage2.gameserver.stats.conditions.ConditionLogicOr;
import lineage2.gameserver.stats.conditions.ConditionPlayerAgathion;
import lineage2.gameserver.stats.conditions.ConditionPlayerClassId;
import lineage2.gameserver.stats.conditions.ConditionPlayerCubic;
import lineage2.gameserver.stats.conditions.ConditionPlayerHasBuff;
import lineage2.gameserver.stats.conditions.ConditionPlayerHasBuffId;
import lineage2.gameserver.stats.conditions.ConditionPlayerInstanceZone;
import lineage2.gameserver.stats.conditions.ConditionPlayerMaxLevel;
import lineage2.gameserver.stats.conditions.ConditionPlayerMaxPK;
import lineage2.gameserver.stats.conditions.ConditionPlayerMinLevel;
import lineage2.gameserver.stats.conditions.ConditionPlayerMinMaxDamage;
import lineage2.gameserver.stats.conditions.ConditionPlayerOlympiad;
import lineage2.gameserver.stats.conditions.ConditionPlayerPercentCp;
import lineage2.gameserver.stats.conditions.ConditionPlayerPercentHp;
import lineage2.gameserver.stats.conditions.ConditionPlayerPercentMp;
import lineage2.gameserver.stats.conditions.ConditionPlayerRace;
import lineage2.gameserver.stats.conditions.ConditionPlayerRiding;
import lineage2.gameserver.stats.conditions.ConditionPlayerRiding.CheckPlayerRiding;
import lineage2.gameserver.stats.conditions.ConditionPlayerState;
import lineage2.gameserver.stats.conditions.ConditionPlayerState.CheckPlayerState;
import lineage2.gameserver.stats.conditions.ConditionPlayerSummonSiegeGolem;
import lineage2.gameserver.stats.conditions.ConditionSlotItemId;
import lineage2.gameserver.stats.conditions.ConditionTargetAggro;
import lineage2.gameserver.stats.conditions.ConditionTargetCastleDoor;
import lineage2.gameserver.stats.conditions.ConditionTargetClan;
import lineage2.gameserver.stats.conditions.ConditionTargetDirection;
import lineage2.gameserver.stats.conditions.ConditionTargetForbiddenClassId;
import lineage2.gameserver.stats.conditions.ConditionTargetHasBuff;
import lineage2.gameserver.stats.conditions.ConditionTargetHasBuffId;
import lineage2.gameserver.stats.conditions.ConditionTargetHasForbiddenSkill;
import lineage2.gameserver.stats.conditions.ConditionTargetMob;
import lineage2.gameserver.stats.conditions.ConditionTargetMobId;
import lineage2.gameserver.stats.conditions.ConditionTargetNpcClass;
import lineage2.gameserver.stats.conditions.ConditionTargetPercentCp;
import lineage2.gameserver.stats.conditions.ConditionTargetPercentHp;
import lineage2.gameserver.stats.conditions.ConditionTargetPercentMp;
import lineage2.gameserver.stats.conditions.ConditionTargetPlayable;
import lineage2.gameserver.stats.conditions.ConditionTargetPlayer;
import lineage2.gameserver.stats.conditions.ConditionTargetPlayerRace;
import lineage2.gameserver.stats.conditions.ConditionTargetRace;
import lineage2.gameserver.stats.conditions.ConditionTargetSummon;
import lineage2.gameserver.stats.conditions.ConditionUsingArmor;
import lineage2.gameserver.stats.conditions.ConditionUsingItemType;
import lineage2.gameserver.stats.conditions.ConditionUsingSkill;
import lineage2.gameserver.stats.conditions.ConditionZoneType;
import lineage2.gameserver.stats.funcs.FuncTemplate;
import lineage2.gameserver.stats.triggers.TriggerInfo;
import lineage2.gameserver.stats.triggers.TriggerType;
import lineage2.gameserver.templates.StatsSet;
import lineage2.gameserver.templates.item.ArmorTemplate.ArmorType;
import lineage2.gameserver.templates.item.WeaponTemplate.WeaponType;
import lineage2.gameserver.utils.PositionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
/**
* @author Mobius
* @version $Revision: 1.0 $
*/
abstract class DocumentBase
{
/**
* Field _log.
*/
private static final Logger _log = LoggerFactory.getLogger(DocumentBase.class);
/**
* Field file.
*/
private final File file;
/**
* Field tables.
*/
protected Map<String, Object[]> tables;
/**
* Constructor for DocumentBase.
* @param file File
*/
DocumentBase(File file)
{
this.file = file;
tables = new HashMap<>();
}
/**
* Method parse.
* @return Document
*/
Document parse()
{
Document doc;
try
{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
factory.setIgnoringComments(true);
doc = factory.newDocumentBuilder().parse(file);
}
catch (Exception e)
{
_log.error("Error loading file " + file, e);
return null;
}
try
{
parseDocument(doc);
}
catch (Exception e)
{
_log.error("Error in file " + file, e);
return null;
}
return doc;
}
/**
* Method parseDocument.
* @param doc Document
*/
protected abstract void parseDocument(Document doc);
/**
* Method getTableValue.
* @param name String
* @return Object
*/
protected abstract Object getTableValue(String name);
/**
* Method getTableValue.
* @param name String
* @param idx int
* @return Object
*/
protected abstract Object getTableValue(String name, int idx);
/**
* Method resetTable.
*/
protected void resetTable()
{
tables = new HashMap<>();
}
/**
* Method setTable.
* @param name String
* @param table Object[]
*/
protected void setTable(String name, Object[] table)
{
tables.put(name, table);
}
/**
* Method parseTemplate.
* @param n Node
* @param template StatTemplate
*/
protected void parseTemplate(Node n, StatTemplate template)
{
n = n.getFirstChild();
if (n == null)
{
return;
}
for (; n != null; n = n.getNextSibling())
{
String nodeName = n.getNodeName();
if ("add".equalsIgnoreCase(nodeName))
{
attachFunc(n, template, "Add");
}
else if ("sub".equalsIgnoreCase(nodeName))
{
attachFunc(n, template, "Sub");
}
else if ("mul".equalsIgnoreCase(nodeName))
{
attachFunc(n, template, "Mul");
}
else if ("div".equalsIgnoreCase(nodeName))
{
attachFunc(n, template, "Div");
}
else if ("set".equalsIgnoreCase(nodeName))
{
attachFunc(n, template, "Set");
}
else if ("enchant".equalsIgnoreCase(nodeName))
{
attachFunc(n, template, "Enchant");
}
else if ("effect".equalsIgnoreCase(nodeName))
{
if (template instanceof EffectTemplate)
{
throw new RuntimeException("Nested effects");
}
attachEffect(n, template);
}
else if (template instanceof EffectTemplate)
{
if ("def".equalsIgnoreCase(nodeName))
{
parseBeanSet(n, ((EffectTemplate) template).getParam(), ((Skill) ((EffectTemplate) template).getParam().getObject("object")).getLevel());
}
else
{
Condition cond = parseCondition(n);
if (cond != null)
{
((EffectTemplate) template).attachCond(cond);
}
}
}
}
}
/**
* Method parseTrigger.
* @param n Node
* @param template StatTemplate
*/
protected void parseTrigger(Node n, StatTemplate template)
{
for (n = n.getFirstChild(); n != null; n = n.getNextSibling())
{
if ("trigger".equalsIgnoreCase(n.getNodeName()))
{
NamedNodeMap map = n.getAttributes();
int id = parseNumber(map.getNamedItem("id").getNodeValue()).intValue();
int level = parseNumber(map.getNamedItem("level").getNodeValue()).intValue();
TriggerType t = TriggerType.valueOf(map.getNamedItem("type").getNodeValue());
double chance = parseNumber(map.getNamedItem("chance").getNodeValue()).doubleValue();
TriggerInfo trigger = new TriggerInfo(id, level, t, chance);
template.addTrigger(trigger);
for (Node n2 = n.getFirstChild(); n2 != null; n2 = n2.getNextSibling())
{
Condition condition = parseCondition(n.getFirstChild());
if (condition != null)
{
trigger.addCondition(condition);
}
}
}
}
}
/**
* Method attachFunc.
* @param n Node
* @param template StatTemplate
* @param name String
*/
protected void attachFunc(Node n, StatTemplate template, String name)
{
Stats stat = Stats.valueOfXml(n.getAttributes().getNamedItem("stat").getNodeValue());
String order = n.getAttributes().getNamedItem("order").getNodeValue();
int ord = parseNumber(order).intValue();
Condition applyCond = parseCondition(n.getFirstChild());
double val = 0;
if (n.getAttributes().getNamedItem("val") != null)
{
val = parseNumber(n.getAttributes().getNamedItem("val").getNodeValue()).doubleValue();
}
template.attachFunc(new FuncTemplate(applyCond, name, stat, ord, val));
}
/**
* Method attachEffect.
* @param n Node
* @param template Object
*/
protected void attachEffect(Node n, Object template)
{
NamedNodeMap attrs = n.getAttributes();
StatsSet set = new StatsSet();
set.set("name", attrs.getNamedItem("name").getNodeValue());
set.set("object", template);
if (attrs.getNamedItem("count") != null)
{
set.set("count", parseNumber(attrs.getNamedItem("count").getNodeValue()).intValue());
}
if (attrs.getNamedItem("time") != null)
{
int time = parseNumber(attrs.getNamedItem("time").getNodeValue()).intValue();
set.set("time", time);
}
set.set("value", attrs.getNamedItem("val") != null ? parseNumber(attrs.getNamedItem("val").getNodeValue()).doubleValue() : 0.);
set.set("abnormal", AbnormalEffect.NULL);
set.set("abnormal2", AbnormalEffect.NULL);
set.set("abnormal3", AbnormalEffect.NULL);
if (attrs.getNamedItem("abnormal") != null)
{
AbnormalEffect ae = AbnormalEffect.getByName(attrs.getNamedItem("abnormal").getNodeValue());
if (ae.isSpecial())
{
set.set("abnormal2", ae);
}
if (ae.isEvent())
{
set.set("abnormal3", ae);
}
else
{
set.set("abnormal", ae);
}
}
if (attrs.getNamedItem("stackType") != null)
{
set.set("stackType", attrs.getNamedItem("stackType").getNodeValue());
}
if (attrs.getNamedItem("stackType2") != null)
{
set.set("stackType2", attrs.getNamedItem("stackType2").getNodeValue());
}
if (attrs.getNamedItem("stackOrder") != null)
{
set.set("stackOrder", parseNumber(attrs.getNamedItem("stackOrder").getNodeValue()).intValue());
}
if (attrs.getNamedItem("applyOnCaster") != null)
{
set.set("applyOnCaster", Boolean.valueOf(attrs.getNamedItem("applyOnCaster").getNodeValue()));
}
if (attrs.getNamedItem("applyOnSummon") != null)
{
set.set("applyOnSummon", Boolean.valueOf(attrs.getNamedItem("applyOnSummon").getNodeValue()));
}
if (attrs.getNamedItem("displayId") != null)
{
set.set("displayId", parseNumber(attrs.getNamedItem("displayId").getNodeValue()).intValue());
}
if (attrs.getNamedItem("displayLevel") != null)
{
set.set("displayLevel", parseNumber(attrs.getNamedItem("displayLevel").getNodeValue()).intValue());
}
if (attrs.getNamedItem("chance") != null)
{
set.set("chance", parseNumber(attrs.getNamedItem("chance").getNodeValue()).intValue());
}
if (attrs.getNamedItem("cancelOnAction") != null)
{
set.set("cancelOnAction", Boolean.valueOf(attrs.getNamedItem("cancelOnAction").getNodeValue()));
}
if (attrs.getNamedItem("cancelOnAttacked") != null)
{
set.set("cancelOnAttacked", Boolean.valueOf(attrs.getNamedItem("cancelOnAttacked").getNodeValue()));
}
if (attrs.getNamedItem("isOffensive") != null)
{
set.set("isOffensive", Boolean.valueOf(attrs.getNamedItem("isOffensive").getNodeValue()));
}
if (attrs.getNamedItem("isReflectable") != null)
{
set.set("isReflectable", Boolean.valueOf(attrs.getNamedItem("isReflectable").getNodeValue()));
}
EffectTemplate lt = new EffectTemplate(set);
parseTemplate(n, lt);
for (Node n1 = n.getFirstChild(); n1 != null; n1 = n1.getNextSibling())
{
if ("triggers".equalsIgnoreCase(n1.getNodeName()))
{
parseTrigger(n1, lt);
}
}
if (template instanceof Skill)
{
((Skill) template).attach(lt);
}
}
/**
* Method parseCondition.
* @param n Node
* @return Condition
*/
protected Condition parseCondition(Node n)
{
while ((n != null) && (n.getNodeType() != Node.ELEMENT_NODE))
{
n = n.getNextSibling();
}
if (n == null)
{
return null;
}
if ("and".equalsIgnoreCase(n.getNodeName()))
{
return parseLogicAnd(n);
}
if ("or".equalsIgnoreCase(n.getNodeName()))
{
return parseLogicOr(n);
}
if ("not".equalsIgnoreCase(n.getNodeName()))
{
return parseLogicNot(n);
}
if ("player".equalsIgnoreCase(n.getNodeName()))
{
return parsePlayerCondition(n);
}
if ("target".equalsIgnoreCase(n.getNodeName()))
{
return parseTargetCondition(n);
}
if ("has".equalsIgnoreCase(n.getNodeName()))
{
return parseHasCondition(n);
}
if ("using".equalsIgnoreCase(n.getNodeName()))
{
return parseUsingCondition(n);
}
if ("game".equalsIgnoreCase(n.getNodeName()))
{
return parseGameCondition(n);
}
if ("zone".equalsIgnoreCase(n.getNodeName()))
{
return parseZoneCondition(n);
}
return null;
}
/**
* Method parseLogicAnd.
* @param n Node
* @return Condition
*/
protected Condition parseLogicAnd(Node n)
{
ConditionLogicAnd cond = new ConditionLogicAnd();
for (n = n.getFirstChild(); n != null; n = n.getNextSibling())
{
if (n.getNodeType() == Node.ELEMENT_NODE)
{
cond.add(parseCondition(n));
}
}
if ((cond._conditions == null) || (cond._conditions.length == 0))
{
_log.error("Empty <and> condition in " + file);
}
return cond;
}
/**
* Method parseLogicOr.
* @param n Node
* @return Condition
*/
protected Condition parseLogicOr(Node n)
{
ConditionLogicOr cond = new ConditionLogicOr();
for (n = n.getFirstChild(); n != null; n = n.getNextSibling())
{
if (n.getNodeType() == Node.ELEMENT_NODE)
{
cond.add(parseCondition(n));
}
}
if ((cond._conditions == null) || (cond._conditions.length == 0))
{
_log.error("Empty <or> condition in " + file);
}
return cond;
}
/**
* Method parseLogicNot.
* @param n Node
* @return Condition
*/
protected Condition parseLogicNot(Node n)
{
for (n = n.getFirstChild(); n != null; n = n.getNextSibling())
{
if (n.getNodeType() == Node.ELEMENT_NODE)
{
return new ConditionLogicNot(parseCondition(n));
}
}
_log.error("Empty <not> condition in " + file);
return null;
}
/**
* Method parsePlayerCondition.
* @param n Node
* @return Condition
*/
protected Condition parsePlayerCondition(Node n)
{
Condition cond = null;
NamedNodeMap attrs = n.getAttributes();
for (int i = 0; i < attrs.getLength(); i++)
{
Node a = attrs.item(i);
String nodeName = a.getNodeName();
if ("race".equalsIgnoreCase(nodeName))
{
cond = joinAnd(cond, new ConditionPlayerRace(a.getNodeValue()));
}
else if ("minLevel".equalsIgnoreCase(nodeName))
{
int lvl = parseNumber(a.getNodeValue()).intValue();
cond = joinAnd(cond, new ConditionPlayerMinLevel(lvl));
}
else if ("summon_siege_golem".equalsIgnoreCase(nodeName))
{
cond = joinAnd(cond, new ConditionPlayerSummonSiegeGolem());
}
else if ("maxLevel".equalsIgnoreCase(nodeName))
{
int lvl = parseNumber(a.getNodeValue()).intValue();
cond = joinAnd(cond, new ConditionPlayerMaxLevel(lvl));
}
else if ("maxPK".equalsIgnoreCase(nodeName))
{
int pk = parseNumber(a.getNodeValue()).intValue();
cond = joinAnd(cond, new ConditionPlayerMaxPK(pk));
}
else if ("resting".equalsIgnoreCase(nodeName))
{
boolean val = Boolean.valueOf(a.getNodeValue());
cond = joinAnd(cond, new ConditionPlayerState(CheckPlayerState.RESTING, val));
}
else if ("moving".equalsIgnoreCase(nodeName))
{
boolean val = Boolean.valueOf(a.getNodeValue());
cond = joinAnd(cond, new ConditionPlayerState(CheckPlayerState.MOVING, val));
}
else if ("running".equalsIgnoreCase(nodeName))
{
boolean val = Boolean.valueOf(a.getNodeValue());
cond = joinAnd(cond, new ConditionPlayerState(CheckPlayerState.RUNNING, val));
}
else if ("standing".equalsIgnoreCase(nodeName))
{
boolean val = Boolean.valueOf(a.getNodeValue());
cond = joinAnd(cond, new ConditionPlayerState(CheckPlayerState.STANDING, val));
}
else if ("flying".equalsIgnoreCase(a.getNodeName()))
{
boolean val = Boolean.valueOf(a.getNodeValue());
cond = joinAnd(cond, new ConditionPlayerState(CheckPlayerState.FLYING, val));
}
else if ("flyingTransform".equalsIgnoreCase(a.getNodeName()))
{
boolean val = Boolean.valueOf(a.getNodeValue());
cond = joinAnd(cond, new ConditionPlayerState(CheckPlayerState.FLYING_TRANSFORM, val));
}
else if ("olympiad".equalsIgnoreCase(a.getNodeName()))
{
boolean val = Boolean.valueOf(a.getNodeValue());
cond = joinAnd(cond, new ConditionPlayerOlympiad(val));
}
else if ("percentHP".equalsIgnoreCase(nodeName))
{
int percentHP = parseNumber(a.getNodeValue()).intValue();
cond = joinAnd(cond, new ConditionPlayerPercentHp(percentHP));
}
else if ("percentMP".equalsIgnoreCase(nodeName))
{
int percentMP = parseNumber(a.getNodeValue()).intValue();
cond = joinAnd(cond, new ConditionPlayerPercentMp(percentMP));
}
else if ("percentCP".equalsIgnoreCase(nodeName))
{
int percentCP = parseNumber(a.getNodeValue()).intValue();
cond = joinAnd(cond, new ConditionPlayerPercentCp(percentCP));
}
else if ("agathion".equalsIgnoreCase(nodeName))
{
int agathionId = parseNumber(a.getNodeValue()).intValue();
cond = joinAnd(cond, new ConditionPlayerAgathion(agathionId));
}
else if ("cubic".equalsIgnoreCase(nodeName))
{
int cubicId = parseNumber(a.getNodeValue()).intValue();
cond = joinAnd(cond, new ConditionPlayerCubic(cubicId));
}
else if ("instance_zone".equalsIgnoreCase(nodeName))
{
int id = parseNumber(a.getNodeValue()).intValue();
cond = joinAnd(cond, new ConditionPlayerInstanceZone(id));
}
else if ("riding".equalsIgnoreCase(nodeName))
{
String riding = a.getNodeValue();
if ("strider".equalsIgnoreCase(riding))
{
cond = joinAnd(cond, new ConditionPlayerRiding(CheckPlayerRiding.STRIDER));
}
else if ("wyvern".equalsIgnoreCase(riding))
{
cond = joinAnd(cond, new ConditionPlayerRiding(CheckPlayerRiding.WYVERN));
}
else if ("none".equalsIgnoreCase(riding))
{
cond = joinAnd(cond, new ConditionPlayerRiding(CheckPlayerRiding.NONE));
}
}
else if ("classId".equalsIgnoreCase(nodeName))
{
cond = joinAnd(cond, new ConditionPlayerClassId(a.getNodeValue().split(",")));
}
else if ("hasBuffId".equalsIgnoreCase(nodeName))
{
StringTokenizer st = new StringTokenizer(a.getNodeValue(), ";");
int id = Integer.parseInt(st.nextToken().trim());
int level = -1;
if (st.hasMoreTokens())
{
level = Integer.parseInt(st.nextToken().trim());
}
cond = joinAnd(cond, new ConditionPlayerHasBuffId(id, level));
}
else if ("hasBuff".equalsIgnoreCase(nodeName))
{
StringTokenizer st = new StringTokenizer(a.getNodeValue(), ";");
EffectType et = Enum.valueOf(EffectType.class, st.nextToken().trim());
int level = -1;
if (st.hasMoreTokens())
{
level = Integer.parseInt(st.nextToken().trim());
}
cond = joinAnd(cond, new ConditionPlayerHasBuff(et, level));
}
else if ("damage".equalsIgnoreCase(nodeName))
{
String[] st = a.getNodeValue().split(";");
cond = joinAnd(cond, new ConditionPlayerMinMaxDamage(Double.parseDouble(st[0]), Double.parseDouble(st[1])));
}
}
if (cond == null)
{
_log.error("Unrecognized <player> condition in " + file);
}
return cond;
}
/**
* Method parseTargetCondition.
* @param n Node
* @return Condition
*/
protected Condition parseTargetCondition(Node n)
{
Condition cond = null;
NamedNodeMap attrs = n.getAttributes();
for (int i = 0; i < attrs.getLength(); i++)
{
Node a = attrs.item(i);
String nodeName = a.getNodeName();
String nodeValue = a.getNodeValue();
if ("aggro".equalsIgnoreCase(nodeName))
{
cond = joinAnd(cond, new ConditionTargetAggro(Boolean.valueOf(nodeValue)));
}
else if ("pvp".equalsIgnoreCase(nodeName))
{
cond = joinAnd(cond, new ConditionTargetPlayable(Boolean.valueOf(nodeValue)));
}
else if ("player".equalsIgnoreCase(nodeName))
{
cond = joinAnd(cond, new ConditionTargetPlayer(Boolean.valueOf(nodeValue)));
}
else if ("summon".equalsIgnoreCase(nodeName))
{
cond = joinAnd(cond, new ConditionTargetSummon(Boolean.valueOf(nodeValue)));
}
else if ("mob".equalsIgnoreCase(nodeName))
{
cond = joinAnd(cond, new ConditionTargetMob(Boolean.valueOf(nodeValue)));
}
else if ("mobId".equalsIgnoreCase(nodeName))
{
cond = joinAnd(cond, new ConditionTargetMobId(Integer.parseInt(nodeValue)));
}
else if ("race".equalsIgnoreCase(nodeName))
{
cond = joinAnd(cond, new ConditionTargetRace(nodeValue));
}
else if ("npc_class".equalsIgnoreCase(nodeName))
{
cond = joinAnd(cond, new ConditionTargetNpcClass(nodeValue));
}
else if ("playerRace".equalsIgnoreCase(nodeName))
{
cond = joinAnd(cond, new ConditionTargetPlayerRace(nodeValue));
}
else if ("forbiddenClassIds".equalsIgnoreCase(nodeName))
{
cond = joinAnd(cond, new ConditionTargetForbiddenClassId(nodeValue.split(";")));
}
else if ("playerSameClan".equalsIgnoreCase(nodeName))
{
cond = joinAnd(cond, new ConditionTargetClan(nodeValue));
}
else if ("castledoor".equalsIgnoreCase(nodeName))
{
cond = joinAnd(cond, new ConditionTargetCastleDoor(Boolean.valueOf(nodeValue)));
}
else if ("direction".equalsIgnoreCase(nodeName))
{
cond = joinAnd(cond, new ConditionTargetDirection(PositionUtils.TargetDirection.valueOf(nodeValue.toUpperCase())));
}
else if ("percentHP".equalsIgnoreCase(nodeName))
{
cond = joinAnd(cond, new ConditionTargetPercentHp(parseNumber(a.getNodeValue()).intValue()));
}
else if ("percentMP".equalsIgnoreCase(nodeName))
{
cond = joinAnd(cond, new ConditionTargetPercentMp(parseNumber(a.getNodeValue()).intValue()));
}
else if ("percentCP".equalsIgnoreCase(nodeName))
{
cond = joinAnd(cond, new ConditionTargetPercentCp(parseNumber(a.getNodeValue()).intValue()));
}
else if ("hasBuffId".equalsIgnoreCase(nodeName))
{
StringTokenizer st = new StringTokenizer(nodeValue, ";");
int id = Integer.parseInt(st.nextToken().trim());
int level = -1;
if (st.hasMoreTokens())
{
level = Integer.parseInt(st.nextToken().trim());
}
cond = joinAnd(cond, new ConditionTargetHasBuffId(id, level));
}
else if ("hasBuff".equalsIgnoreCase(nodeName))
{
StringTokenizer st = new StringTokenizer(nodeValue, ";");
EffectType et = Enum.valueOf(EffectType.class, st.nextToken().trim());
int level = -1;
if (st.hasMoreTokens())
{
level = Integer.parseInt(st.nextToken().trim());
}
cond = joinAnd(cond, new ConditionTargetHasBuff(et, level));
}
else if ("hasForbiddenSkill".equalsIgnoreCase(nodeName))
{
cond = joinAnd(cond, new ConditionTargetHasForbiddenSkill(parseNumber(a.getNodeValue()).intValue()));
}
}
if (cond == null)
{
_log.error("Unrecognized <target> condition in " + file);
}
return cond;
}
/**
* Method parseUsingCondition.
* @param n Node
* @return Condition
*/
protected Condition parseUsingCondition(Node n)
{
Condition cond = null;
NamedNodeMap attrs = n.getAttributes();
for (int i = 0; i < attrs.getLength(); i++)
{
Node a = attrs.item(i);
String nodeName = a.getNodeName();
String nodeValue = a.getNodeValue();
if ("kind".equalsIgnoreCase(nodeName) || "weapon".equalsIgnoreCase(nodeName))
{
long mask = 0;
StringTokenizer st = new StringTokenizer(nodeValue, ",");
tokens:
while (st.hasMoreTokens())
{
String item = st.nextToken().trim();
for (WeaponType wt : WeaponType.VALUES)
{
if (wt.toString().equalsIgnoreCase(item))
{
mask |= wt.mask();
continue tokens;
}
}
for (ArmorType at : ArmorType.VALUES)
{
if (at.toString().equalsIgnoreCase(item))
{
mask |= at.mask();
continue tokens;
}
}
_log.error("Invalid item kind: \"" + item + "\" in " + file);
}
if (mask != 0)
{
cond = joinAnd(cond, new ConditionUsingItemType(mask));
}
}
else if ("armor".equalsIgnoreCase(nodeName))
{
ArmorType armor = ArmorType.valueOf(nodeValue.toUpperCase());
cond = joinAnd(cond, new ConditionUsingArmor(armor));
}
else if ("skill".equalsIgnoreCase(nodeName))
{
cond = joinAnd(cond, new ConditionUsingSkill(Integer.parseInt(nodeValue)));
}
else if ("slotitem".equalsIgnoreCase(nodeName))
{
StringTokenizer st = new StringTokenizer(nodeValue, ";");
int id = Integer.parseInt(st.nextToken().trim());
int slot = Integer.parseInt(st.nextToken().trim());
int enchant = 0;
if (st.hasMoreTokens())
{
enchant = Integer.parseInt(st.nextToken().trim());
}
cond = joinAnd(cond, new ConditionSlotItemId(slot, id, enchant));
}
}
if (cond == null)
{
_log.error("Unrecognized <using> condition in " + file);
}
return cond;
}
/**
* Method parseHasCondition.
* @param n Node
* @return Condition
*/
protected Condition parseHasCondition(Node n)
{
Condition cond = null;
NamedNodeMap attrs = n.getAttributes();
for (int i = 0; i < attrs.getLength(); i++)
{
Node a = attrs.item(i);
String nodeName = a.getNodeName();
String nodeValue = a.getNodeValue();
if ("skill".equalsIgnoreCase(nodeName))
{
StringTokenizer st = new StringTokenizer(nodeValue, ";");
Integer id = parseNumber(st.nextToken().trim()).intValue();
int level = parseNumber(st.nextToken().trim()).shortValue();
cond = joinAnd(cond, new ConditionHasSkill(id, level));
}
else if ("success".equalsIgnoreCase(nodeName))
{
cond = joinAnd(cond, new ConditionFirstEffectSuccess(Boolean.valueOf(nodeValue)));
}
}
if (cond == null)
{
_log.error("Unrecognized <has> condition in " + file);
}
return cond;
}
/**
* Method parseGameCondition.
* @param n Node
* @return Condition
*/
protected Condition parseGameCondition(Node n)
{
Condition cond = null;
NamedNodeMap attrs = n.getAttributes();
for (int i = 0; i < attrs.getLength(); i++)
{
Node a = attrs.item(i);
if ("night".equalsIgnoreCase(a.getNodeName()))
{
boolean val = Boolean.valueOf(a.getNodeValue());
cond = joinAnd(cond, new ConditionGameTime(CheckGameTime.NIGHT, val));
}
}
if (cond == null)
{
_log.error("Unrecognized <game> condition in " + file);
}
return cond;
}
/**
* Method parseZoneCondition.
* @param n Node
* @return Condition
*/
protected Condition parseZoneCondition(Node n)
{
Condition cond = null;
NamedNodeMap attrs = n.getAttributes();
for (int i = 0; i < attrs.getLength(); i++)
{
Node a = attrs.item(i);
if ("type".equalsIgnoreCase(a.getNodeName()))
{
cond = joinAnd(cond, new ConditionZoneType(a.getNodeValue()));
}
}
if (cond == null)
{
_log.error("Unrecognized <zone> condition in " + file);
}
return cond;
}
/**
* Method parseTable.
* @param n Node
* @return Object[]
*/
protected Object[] parseTable(Node n)
{
NamedNodeMap attrs = n.getAttributes();
String name = attrs.getNamedItem("name").getNodeValue();
if (name.charAt(0) != '#')
{
throw new IllegalArgumentException("Table name must start with #");
}
StringTokenizer data = new StringTokenizer(n.getFirstChild().getNodeValue());
List<String> array = new ArrayList<>();
while (data.hasMoreTokens())
{
array.add(data.nextToken());
}
Object[] res = array.toArray(new Object[array.size()]);
setTable(name, res);
return res;
}
/**
* Method parseBeanSet.
* @param n Node
* @param set StatsSet
* @param level int
*/
protected void parseBeanSet(Node n, StatsSet set, int level)
{
try
{
String name = n.getAttributes().getNamedItem("name").getNodeValue().trim();
String value = n.getAttributes().getNamedItem("val").getNodeValue().trim();
char ch = value.length() == 0 ? ' ' : value.charAt(0);
if (value.contains("#") && (ch != '#'))
{
for (String str : value.split("[;: ]+"))
{
if (str.charAt(0) == '#')
{
value = value.replace(str, String.valueOf(getTableValue(str, level)));
}
}
}
if (ch == '#')
{
Object tableVal = getTableValue(value, level);
Number parsedVal = parseNumber(tableVal.toString());
set.set(name, parsedVal == null ? tableVal : String.valueOf(parsedVal));
}
else if ((Character.isDigit(ch) || (ch == '-')) && !value.contains(" ") && !value.contains(";"))
{
set.set(name, String.valueOf(parseNumber(value)));
}
else
{
set.set(name, value);
}
}
catch (Exception e)
{
System.out.println(n.getAttributes().getNamedItem("name") + " " + set.get("skill_id"));
e.printStackTrace();
}
}
/**
* Method parseNumber.
* @param value String
* @return Number
*/
protected Number parseNumber(String value)
{
if (value.charAt(0) == '#')
{
value = getTableValue(value).toString();
}
try
{
if (value.equalsIgnoreCase("max"))
{
return Double.POSITIVE_INFINITY;
}
if (value.equalsIgnoreCase("min"))
{
return Double.NEGATIVE_INFINITY;
}
if (value.indexOf('.') == -1)
{
int radix = 10;
if ((value.length() > 2) && value.substring(0, 2).equalsIgnoreCase("0x"))
{
value = value.substring(2);
radix = 16;
}
return Integer.valueOf(value, radix);
}
return Double.valueOf(value);
}
catch (NumberFormatException e)
{
return null;
}
}
/**
* Method joinAnd.
* @param cond Condition
* @param c Condition
* @return Condition
*/
protected Condition joinAnd(Condition cond, Condition c)
{
if (cond == null)
{
return c;
}
if (cond instanceof ConditionLogicAnd)
{
((ConditionLogicAnd) cond).add(c);
return cond;
}
ConditionLogicAnd and = new ConditionLogicAnd();
and.add(cond);
and.add(c);
return and;
}
}