lineage2.gameserver.data.xml.parser.StatParser.java Source code

Java tutorial

Introduction

Here is the source code for lineage2.gameserver.data.xml.parser.StatParser.java

Source

/*
 * 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.data.xml.parser;

import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;

import lineage2.commons.data.xml.AbstractDirParser;
import lineage2.commons.data.xml.AbstractHolder;
import lineage2.gameserver.model.entity.residence.ResidenceType;
import lineage2.gameserver.stats.StatTemplate;
import lineage2.gameserver.stats.Stats;
import lineage2.gameserver.stats.conditions.Condition;
import lineage2.gameserver.stats.conditions.ConditionCastleDark;
import lineage2.gameserver.stats.conditions.ConditionCastleDarkClanLeader;
import lineage2.gameserver.stats.conditions.ConditionCastleLight;
import lineage2.gameserver.stats.conditions.ConditionCastleLightClanLeader;
import lineage2.gameserver.stats.conditions.ConditionLogicAnd;
import lineage2.gameserver.stats.conditions.ConditionLogicNot;
import lineage2.gameserver.stats.conditions.ConditionLogicOr;
import lineage2.gameserver.stats.conditions.ConditionPlayerClassId;
import lineage2.gameserver.stats.conditions.ConditionPlayerInstanceZone;
import lineage2.gameserver.stats.conditions.ConditionPlayerMinMaxDamage;
import lineage2.gameserver.stats.conditions.ConditionPlayerOlympiad;
import lineage2.gameserver.stats.conditions.ConditionPlayerRace;
import lineage2.gameserver.stats.conditions.ConditionPlayerResidence;
import lineage2.gameserver.stats.conditions.ConditionSlotItemId;
import lineage2.gameserver.stats.conditions.ConditionTargetPlayable;
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.item.ArmorTemplate;
import lineage2.gameserver.templates.item.WeaponTemplate;

import org.dom4j.Attribute;
import org.dom4j.Element;

/**
 * @author Mobius
 * @version $Revision: 1.0 $
 * @param <H>
 */
abstract class StatParser<H extends AbstractHolder> extends AbstractDirParser<H> {
    /**
     * Constructor for StatParser.
     * @param holder H
     */
    protected StatParser(H holder) {
        super(holder);
    }

    /**
     * Method parseFirstCond.
     * @param sub Element
     * @return Condition
     */
    protected Condition parseFirstCond(Element sub) {
        List<Element> e = sub.elements();

        if (e.isEmpty()) {
            return null;
        }

        Element element = e.get(0);
        return parseCond(element);
    }

    /**
     * Method parseCond.
     * @param element Element
     * @return Condition
     */
    private Condition parseCond(Element element) {
        String name = element.getName();

        if (name.equalsIgnoreCase("and")) {
            return parseLogicAnd(element);
        } else if (name.equalsIgnoreCase("or")) {
            return parseLogicOr(element);
        } else if (name.equalsIgnoreCase("not")) {
            return parseLogicNot(element);
        } else if (name.equalsIgnoreCase("target")) {
            return parseTargetCondition(element);
        } else if (name.equalsIgnoreCase("player")) {
            return parsePlayerCondition(element);
        } else if (name.equalsIgnoreCase("using")) {
            return parseUsingCondition(element);
        } else if (name.equalsIgnoreCase("zone")) {
            return parseZoneCondition(element);
        }

        return null;
    }

    /**
     * Method parseLogicAnd.
     * @param n Element
     * @return Condition
     */
    private Condition parseLogicAnd(Element n) {
        ConditionLogicAnd cond = new ConditionLogicAnd();

        for (Iterator<Element> iterator = n.elementIterator(); iterator.hasNext();) {
            Element condElement = iterator.next();
            cond.add(parseCond(condElement));
        }

        if ((cond._conditions == null) || (cond._conditions.length == 0)) {
            error("Empty <and> condition in " + getCurrentFileName());
        }

        return cond;
    }

    /**
     * Method parseLogicOr.
     * @param n Element
     * @return Condition
     */
    private Condition parseLogicOr(Element n) {
        ConditionLogicOr cond = new ConditionLogicOr();

        for (Iterator<Element> iterator = n.elementIterator(); iterator.hasNext();) {
            Element condElement = iterator.next();
            cond.add(parseCond(condElement));
        }

        if ((cond._conditions == null) || (cond._conditions.length == 0)) {
            error("Empty <or> condition in " + getCurrentFileName());
        }

        return cond;
    }

    /**
     * Method parseLogicNot.
     * @param n Element
     * @return Condition
     */
    private Condition parseLogicNot(Element n) {
        for (Object element : n.elements()) {
            return new ConditionLogicNot(parseCond((Element) element));
        }

        error("Empty <not> condition in " + getCurrentFileName());
        return null;
    }

    /**
     * Method parseTargetCondition.
     * @param element Element
     * @return Condition
     */
    private Condition parseTargetCondition(Element element) {
        Condition cond = null;

        for (Iterator<Attribute> iterator = element.attributeIterator(); iterator.hasNext();) {
            Attribute attribute = iterator.next();
            String name = attribute.getName();
            String value = attribute.getValue();

            if (name.equalsIgnoreCase("pvp")) {
                cond = joinAnd(cond, new ConditionTargetPlayable(Boolean.valueOf(value)));
            }
        }

        return cond;
    }

    /**
     * Method parseZoneCondition.
     * @param element Element
     * @return Condition
     */
    private Condition parseZoneCondition(Element element) {
        Condition cond = null;

        for (Iterator<Attribute> iterator = element.attributeIterator(); iterator.hasNext();) {
            Attribute attribute = iterator.next();
            String name = attribute.getName();
            String value = attribute.getValue();

            if (name.equalsIgnoreCase("type")) {
                cond = joinAnd(cond, new ConditionZoneType(value));
            }
        }

        return cond;
    }

    /**
     * Method parsePlayerCondition.
     * @param element Element
     * @return Condition
     */
    private Condition parsePlayerCondition(Element element) {
        Condition cond = null;

        for (Iterator<Attribute> iterator = element.attributeIterator(); iterator.hasNext();) {
            Attribute attribute = iterator.next();
            String name = attribute.getName();
            String value = attribute.getValue();

            if (name.equalsIgnoreCase("residence")) {
                String[] st = value.split(";");
                cond = joinAnd(cond,
                        new ConditionPlayerResidence(Integer.parseInt(st[1]), ResidenceType.valueOf(st[0])));
            } else if (name.equalsIgnoreCase("classId")) {
                cond = joinAnd(cond, new ConditionPlayerClassId(value.split(",")));
            } else if (name.equalsIgnoreCase("olympiad")) {
                cond = joinAnd(cond, new ConditionPlayerOlympiad(Boolean.valueOf(value)));
            } else if (name.equalsIgnoreCase("instance_zone")) {
                cond = joinAnd(cond, new ConditionPlayerInstanceZone(Integer.parseInt(value)));
            } else if (name.equalsIgnoreCase("race")) {
                cond = joinAnd(cond, new ConditionPlayerRace(value));
            } else if (name.equalsIgnoreCase("damage")) {
                String[] st = value.split(";");
                cond = joinAnd(cond,
                        new ConditionPlayerMinMaxDamage(Double.parseDouble(st[0]), Double.parseDouble(st[1])));
            } else if (name.equalsIgnoreCase("castleLight")) {
                cond = joinAnd(cond, new ConditionCastleLight());
            } else if (name.equalsIgnoreCase("castleLightClanLeader")) {
                cond = joinAnd(cond, new ConditionCastleLightClanLeader());
            } else if (name.equalsIgnoreCase("castleDark")) {
                cond = joinAnd(cond, new ConditionCastleDark());
            } else if (name.equalsIgnoreCase("castleDarkClanLeader")) {
                cond = joinAnd(cond, new ConditionCastleDarkClanLeader());
            }
        }

        return cond;
    }

    /**
     * Method parseUsingCondition.
     * @param element Element
     * @return Condition
     */
    private Condition parseUsingCondition(Element element) {
        Condition cond = null;

        for (Iterator<Attribute> iterator = element.attributeIterator(); iterator.hasNext();) {
            Attribute attribute = iterator.next();
            String name = attribute.getName();
            String value = attribute.getValue();

            if (name.equalsIgnoreCase("slotitem")) {
                StringTokenizer st = new StringTokenizer(value, ";");
                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));
            } else if (name.equalsIgnoreCase("kind") || name.equalsIgnoreCase("weapon")) {
                long mask = 0;
                StringTokenizer st = new StringTokenizer(value, ",");
                tokens:

                while (st.hasMoreTokens()) {
                    String item = st.nextToken().trim();

                    for (WeaponTemplate.WeaponType wt : WeaponTemplate.WeaponType.VALUES) {
                        if (wt.toString().equalsIgnoreCase(item)) {
                            mask |= wt.mask();
                            continue tokens;
                        }
                    }

                    for (ArmorTemplate.ArmorType at : ArmorTemplate.ArmorType.VALUES) {
                        if (at.toString().equalsIgnoreCase(item)) {
                            mask |= at.mask();
                            continue tokens;
                        }
                    }

                    error("Invalid item kind: \"" + item + "\" in " + getCurrentFileName());
                }

                if (mask != 0) {
                    cond = joinAnd(cond, new ConditionUsingItemType(mask));
                }
            } else if (name.equalsIgnoreCase("skill")) {
                cond = joinAnd(cond, new ConditionUsingSkill(Integer.parseInt(value)));
            }
        }

        return cond;
    }

    /**
     * Method joinAnd.
     * @param cond Condition
     * @param c Condition
     * @return Condition
     */
    private 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;
    }

    /**
     * Method parseFor.
     * @param forElement Element
     * @param template StatTemplate
     */
    protected void parseFor(Element forElement, StatTemplate template) {
        for (Iterator<Element> iterator = forElement.elementIterator(); iterator.hasNext();) {
            Element element = iterator.next();
            final String elementName = element.getName();

            if (elementName.equalsIgnoreCase("add")) {
                attachFunc(element, template, "Add");
            } else if (elementName.equalsIgnoreCase("set")) {
                attachFunc(element, template, "Set");
            } else if (elementName.equalsIgnoreCase("sub")) {
                attachFunc(element, template, "Sub");
            } else if (elementName.equalsIgnoreCase("mul")) {
                attachFunc(element, template, "Mul");
            } else if (elementName.equalsIgnoreCase("div")) {
                attachFunc(element, template, "Div");
            } else if (elementName.equalsIgnoreCase("enchant")) {
                attachFunc(element, template, "Enchant");
            }
        }
    }

    /**
     * Method parseTriggers.
     * @param f Element
     * @param triggerable StatTemplate
     */
    protected void parseTriggers(Element f, StatTemplate triggerable) {
        for (Iterator<Element> iterator = f.elementIterator(); iterator.hasNext();) {
            Element element = iterator.next();
            int id = parseNumber(element.attributeValue("id")).intValue();
            int level = parseNumber(element.attributeValue("level")).intValue();
            TriggerType t = TriggerType.valueOf(element.attributeValue("type"));
            double chance = parseNumber(element.attributeValue("chance")).doubleValue();
            TriggerInfo trigger = new TriggerInfo(id, level, t, chance);
            triggerable.addTrigger(trigger);

            for (Iterator<Element> subIterator = element.elementIterator(); subIterator.hasNext();) {
                Element subElement = subIterator.next();
                Condition condition = parseFirstCond(subElement);

                if (condition != null) {
                    trigger.addCondition(condition);
                }
            }
        }
    }

    /**
     * Method attachFunc.
     * @param n Element
     * @param template StatTemplate
     * @param name String
     */
    private void attachFunc(Element n, StatTemplate template, String name) {
        Stats stat = Stats.valueOfXml(n.attributeValue("stat"));
        String order = n.attributeValue("order");
        int ord = parseNumber(order).intValue();
        Condition applyCond = parseFirstCond(n);
        double val = 0;

        if (n.attributeValue("value") != null) {
            val = parseNumber(n.attributeValue("value")).doubleValue();
        }

        template.attachFunc(new FuncTemplate(applyCond, name, stat, ord, val));
    }

    /**
     * Method parseNumber.
     * @param value String
     * @return Number
     */
    protected Number parseNumber(String value) {
        if (value.charAt(0) == '#') {
            value = getTableValue(value).toString();
        }

        try {
            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 getTableValue.
     * @param name String
     * @return Object
     */
    protected abstract Object getTableValue(String name);
}