Since a lot of community members are requesting for such feature finally i managed to code one simple.
Here's what i've got for now:
- Ability to set custom title when player reach specified amount of pvps.
- Ability to set custom title color when player reach specified amount of pvps.
TODO:
- Ability to receive Item on specified amount of pvps.
- Ability to receive Fame on specified amount of pvps.
- Ability to receive Clan Reputation Points on specified amount of pvps.
- Ability to receive Skill (For certain period of time?)on specified amount of pvps.
- Ability to receive Buff on specified amount of pvps.
Title is updated after each PvP or logging in.
Reloading of xml data is possible through the fallowing command:
//script_load PvPTitle
Requested by: JMD
### Eclipse Workspace Patch 1.0
#P L2J_DataPack_BETA
Index: dist/game/data/scripts/custom/PvPTitle/PvPTitleParser.java
===================================================================
--- dist/game/data/scripts/custom/PvPTitle/PvPTitleParser.java (revision 0)
+++ dist/game/data/scripts/custom/PvPTitle/PvPTitleParser.java (working copy)
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2004-2013 L2J DataPack
+ *
+ * This file is part of L2J DataPack.
+ *
+ * L2J DataPack 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.
+ *
+ * L2J DataPack 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 custom.PvPTitle;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.logging.Level;
+
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+import com.l2jserver.gameserver.engines.DocumentParser;
+import com.l2jserver.gameserver.model.StatsSet;
+import com.l2jserver.gameserver.model.holders.ItemHolder;
+import com.l2jserver.gameserver.model.holders.SkillHolder;
+
+/**
+ * @author UnAfraid
+ */
+public class PvPTitleParser extends DocumentParser
+{
+ private final List<PvPTitleDTO> _pvpData = new LinkedList<>();
+
+ protected PvPTitleParser()
+ {
+ load();
+ }
+
+ @Override
+ public void load()
+ {
+ parseDatapackFile("data/scripts/custom/PvPTitle/data.xml");
+ _log.log(Level.INFO, PvPTitle.class.getSimpleName() + ": Loaded " + _pvpData.size() + " Custom PvP titles.");
+ }
+
+ @Override
+ protected void parseDocument()
+ {
+ Node att;
+ NamedNodeMap attrs;
+ StatsSet set;
+ for (Node n = getCurrentDocument().getFirstChild(); n != null; n = n.getNextSibling())
+ {
+ if ("list".equalsIgnoreCase(n.getNodeName()))
+ {
+ for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
+ {
+ if ("title".equalsIgnoreCase(d.getNodeName()))
+ {
+ attrs = d.getAttributes();
+ set = new StatsSet();
+ for (int i = 0; i < attrs.getLength(); i++)
+ {
+ att = attrs.item(i);
+ set.set(att.getNodeName(), att.getNodeValue());
+ }
+ PvPTitleDTO dto = new PvPTitleDTO(set);
+ for (Node a = d.getFirstChild(); a != null; a = a.getNextSibling())
+ {
+ if ("item".equals(a.getNodeName()))
+ {
+ attrs = a.getAttributes();
+ final int itemId = parseInt(attrs, "id");
+ final int itemAmount = parseInt(attrs, "amount");
+ dto.addItem(new ItemHolder(itemId, itemAmount));
+ }
+ else if ("effect".equals(a.getNodeName()))
+ {
+ attrs = a.getAttributes();
+ final int skillId = parseInt(attrs, "id");
+ final int skillLvl = parseInt(attrs, "level");
+ dto.addEffect(new SkillHolder(skillId, skillLvl));
+ }
+ else if ("skill".equals(a.getNodeName()))
+ {
+ attrs = a.getAttributes();
+ final int skillId = parseInt(attrs, "id");
+ final int skillLvl = parseInt(attrs, "level");
+ final int time = parseInt(attrs, "time");
+ dto.addSkill(new PvPTitleSkill(skillId, skillLvl, time));
+ }
+ }
+ _pvpData.add(new PvPTitleDTO(set));
+ }
+ }
+ }
+ }
+ }
+
+ public List<PvPTitleDTO> getData()
+ {
+ return _pvpData;
+ }
+}
\ No newline at end of file
Index: dist/game/data/scripts/custom/PvPTitle/PvPSkillRemover.java
===================================================================
--- dist/game/data/scripts/custom/PvPTitle/PvPSkillRemover.java (revision 0)
+++ dist/game/data/scripts/custom/PvPTitle/PvPSkillRemover.java (working copy)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2004-2013 L2J DataPack
+ *
+ * This file is part of L2J DataPack.
+ *
+ * L2J DataPack 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.
+ *
+ * L2J DataPack 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 custom.PvPTitle;
+
+import com.l2jserver.gameserver.model.L2World;
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jserver.gameserver.model.holders.SkillHolder;
+
+/**
+ * @author UnAfraid
+ */
+public final class PvPSkillRemover implements Runnable
+{
+ private final int _objectId;
+ private final SkillHolder _holder;
+
+ protected PvPSkillRemover(int objectId, SkillHolder holder)
+ {
+ _objectId = objectId;
+ _holder = holder;
+ }
+
+ @Override
+ public void run()
+ {
+ final L2PcInstance player = L2World.getInstance().getPlayer(_objectId);
+ if (player != null)
+ {
+ player.removeSkill(_holder.getSkill());
+ }
+ }
+}
\ No newline at end of file
Index: dist/game/data/scripts/custom/PvPTitle/PvPTitle.java
===================================================================
--- dist/game/data/scripts/custom/PvPTitle/PvPTitle.java (revision 0)
+++ dist/game/data/scripts/custom/PvPTitle/PvPTitle.java (working copy)
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2004-2013 L2J DataPack
+ *
+ * This file is part of L2J DataPack.
+ *
+ * L2J DataPack 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.
+ *
+ * L2J DataPack 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 custom.PvPTitle;
+
+import ai.npc.AbstractNpcAI;
+
+import com.l2jserver.gameserver.ThreadPoolManager;
+import com.l2jserver.gameserver.datatables.MultiSell;
+import com.l2jserver.gameserver.instancemanager.GlobalVariablesManager;
+import com.l2jserver.gameserver.model.L2World;
+import com.l2jserver.gameserver.model.actor.L2Character;
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jserver.gameserver.model.holders.ItemHolder;
+import com.l2jserver.gameserver.model.holders.SkillHolder;
+import com.l2jserver.gameserver.model.skills.L2Skill;
+import com.l2jserver.gameserver.scripting.scriptengine.events.DeathEvent;
+
+/**
+ * @author UnAfraid
+ */
+public final class PvPTitle extends AbstractNpcAI
+{
+ private final PvPTitleParser _parser = new PvPTitleParser();
+
+ private PvPTitle(String name, String descr)
+ {
+ super(name, descr);
+ addLoginLogoutNotify();
+ }
+
+ /**
+ * When reloading the script would be nice to release all links to current instance of this class.
+ * @param removeFromList
+ */
+ @Override
+ public boolean unload(boolean removeFromList)
+ {
+ removeLoginLogoutNotify();
+ for (L2PcInstance player : L2World.getInstance().getAllPlayersArray())
+ {
+ removeDeathNotify(player);
+ }
+ return super.unload(removeFromList);
+ }
+
+ /**
+ * When player login request death notifications. Also set title if possible
+ * @param player
+ */
+ @Override
+ public void onPlayerLogin(L2PcInstance player)
+ {
+ addDeathNotify(player);
+ applyTitle(player);
+ }
+
+ /**
+ * When player logout removing him from death notification listeners.
+ * @param player
+ */
+ @Override
+ public void onPlayerLogout(L2PcInstance player)
+ {
+ removeDeathNotify(player);
+ }
+
+ /**
+ * Received death event make sure player killed another player and try to change his title if possible.
+ * @param event
+ */
+ @Override
+ public boolean onDeath(DeathEvent event)
+ {
+ final L2Character victim = event.getVictim();
+ final L2Character killer = event.getKiller();
+ if ((killer != null) && killer.isPlayer() && (victim != null) && victim.isPlayer())
+ {
+ applyTitle(killer.getActingPlayer());
+ }
+ return true;
+ }
+
+ /**
+ * Trying to set title.
+ * @param player
+ */
+ private void applyTitle(L2PcInstance player)
+ {
+ PvPTitleDTO dto = null;
+ for (PvPTitleDTO val : _parser.getData())
+ {
+ if ((dto == null) || ((player.getPvpKills() >= val.getMinKills()) && (val.getMinKills() > dto.getMinKills())))
+ {
+ dto = val;
+ }
+ }
+
+ // If we have new title for the player and the current is not the same change it.
+ if ((dto != null) && !hasSameTitle(player, dto))
+ {
+ if (!dto.getTitle().isEmpty()) // If custom title is empty don't set it
+ {
+ player.setTitle(dto.getTitle());
+ }
+ player.getAppearance().setTitleColor(dto.getTitleColor());
+ player.broadcastTitleInfo();
+ applyMisc(player, dto);
+ }
+ }
+
+ /**
+ * Trying to give all available misc rewards if possible and there is.
+ * @param dto
+ * @param player
+ */
+ private void applyMisc(final L2PcInstance player, PvPTitleDTO dto)
+ {
+ // Prevent from useless database entries.
+ if (dto.getItems().isEmpty() && dto.getSkills().isEmpty() && dto.getEffects().isEmpty())
+ {
+ return;
+ }
+
+ final String key = "PvP-" + player.getObjectId() + "-" + dto.getMinKills();
+ if (!GlobalVariablesManager.getInstance().isVariableStored(key)) // Make sure player hasn't received this rewards yet!
+ {
+ // Give items
+ for (ItemHolder holder : dto.getItems())
+ {
+ giveItems(player, holder); // Give item.
+ }
+
+ // Apply effects.
+ for (SkillHolder holder : dto.getEffects())
+ {
+ holder.getSkill().getEffects(player, player); // Activate effect.
+ }
+
+ // Give skills.
+ for (PvPTitleSkill holder : dto.getSkills())
+ {
+ final L2Skill skill = holder.getSkill();
+ if (player.getKnownSkill(skill.getId()) == null) // make sure that player doesn't already knows this skill!
+ {
+ player.addSkill(skill, false); // Give temporarily the skill.
+ ThreadPoolManager.getInstance().scheduleGeneral(new PvPSkillRemover(player.getObjectId(), holder), holder.getTime() * 1000); // Schedule skill removal task.
+ }
+ }
+ // Mark rewards as received.
+ GlobalVariablesManager.getInstance().storeVariable(key, "1");
+ }
+ }
+
+ /**
+ * Overriding giveItems to implement support for special items like Fame, Clan Reputation, etc..
+ * @param player
+ * @param holder
+ */
+ @Override
+ protected void giveItems(L2PcInstance player, ItemHolder holder)
+ {
+ switch (holder.getId())
+ {
+ case MultiSell.PC_BANG_POINTS:
+ case MultiSell.CLAN_REPUTATION:
+ case MultiSell.FAME:
+ {
+ MultiSell.addSpecialProduct(holder.getId(), holder.getCount(), player);
+ break;
+ }
+ default:
+ {
+ super.giveItems(player, holder);
+ break;
+ }
+ }
+ }
+
+ /**
+ * @param player
+ * @param dto
+ * @return {@code true} if player have the same title settings as requested, {@code false} otherwise.
+ */
+ private static boolean hasSameTitle(L2PcInstance player, PvPTitleDTO dto)
+ {
+ return (dto.getTitle().isEmpty() || player.getTitle().equals(dto.getTitle())) && (player.getAppearance().getTitleColor() == dto.getTitleColor());
+ }
+
+ public static void main(String[] args)
+ {
+ new PvPTitle(PvPTitle.class.getSimpleName(), "custom");
+ }
+}
Index: dist/game/data/scripts/custom/PvPTitle/PvPTitleDTO.java
===================================================================
--- dist/game/data/scripts/custom/PvPTitle/PvPTitleDTO.java (revision 0)
+++ dist/game/data/scripts/custom/PvPTitle/PvPTitleDTO.java (working copy)
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2004-2013 L2J DataPack
+ *
+ * This file is part of L2J DataPack.
+ *
+ * L2J DataPack 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.
+ *
+ * L2J DataPack 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 custom.PvPTitle;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import com.l2jserver.gameserver.model.StatsSet;
+import com.l2jserver.gameserver.model.holders.ItemHolder;
+import com.l2jserver.gameserver.model.holders.SkillHolder;
+
+/**
+ * @author UnAfraid
+ */
+public class PvPTitleDTO
+{
+ private final int _minKills;
+ private final int _titleColor;
+ private final String _title;
+
+ private final List<ItemHolder> _items = new LinkedList<>();
+ private final List<SkillHolder> _effects = new LinkedList<>();
+ private final List<PvPTitleSkill> _skills = new LinkedList<>();
+
+ public PvPTitleDTO(StatsSet set)
+ {
+ _minKills = set.getInteger("minKills");
+ _titleColor = Integer.decode(set.getString("color", "0xFFFF77"));
+ _title = set.getString("val", "");
+ }
+
+ public int getMinKills()
+ {
+ return _minKills;
+ }
+
+ public int getTitleColor()
+ {
+ return _titleColor;
+ }
+
+ public String getTitle()
+ {
+ return _title;
+ }
+
+ public void addItem(ItemHolder holder)
+ {
+ _items.add(holder);
+ }
+
+ public void addEffect(SkillHolder holder)
+ {
+ _effects.add(holder);
+ }
+
+ public void addSkill(PvPTitleSkill holder)
+ {
+ _skills.add(holder);
+ }
+
+ public List<ItemHolder> getItems()
+ {
+ return _items;
+ }
+
+ public List<SkillHolder> getEffects()
+ {
+ return _effects;
+ }
+
+ public List<PvPTitleSkill> getSkills()
+ {
+ return _skills;
+ }
+}
Index: dist/game/data/scripts/custom/PvPTitle/data.xsd
===================================================================
--- dist/game/data/scripts/custom/PvPTitle/data.xsd (revision 0)
+++ dist/game/data/scripts/custom/PvPTitle/data.xsd (working copy)
@@ -0,0 +1,36 @@
+<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:element name="list">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="title" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType mixed="true">
+ <xs:sequence>
+ <xs:element name="item" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:attribute type="xs:integer" name="id" />
+ <xs:attribute type="xs:long" name="amount" />
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="skill" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:attribute type="xs:integer" name="id" />
+ <xs:attribute type="xs:integer" name="level" />
+ <xs:attribute type="xs:integer" name="time" />
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="effect" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:attribute type="xs:integer" name="id" />
+ <xs:attribute type="xs:integer" name="level" />
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute type="xs:short" name="minKills" use="required" />
+ <xs:attribute type="xs:string" name="color" use="optional" />
+ <xs:attribute type="xs:string" name="val" use="optional" />
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+</xs:schema>
\ No newline at end of file
Index: dist/game/data/scripts/custom/PvPTitle/data.xml
===================================================================
--- dist/game/data/scripts/custom/PvPTitle/data.xml (revision 0)
+++ dist/game/data/scripts/custom/PvPTitle/data.xml (working copy)
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<list xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="data.xsd">
+ <title minKills="2" color="0x0000FF" /> <!-- Only color change without title is possible -->
+ <title minKills="5" color="0x00FFFF" val="PvP Noobje" />
+ <title minKills="10" color="0xFF00FF" val="PvP Rookie" />
+ <title minKills="20" color="0x00FF00" val="PvP Pro" />
+ <title minKills="40" color="0xF0FF0F" val="PvP Master">
+ <effect id="396" level="1" /> <!-- Heroic Berserker -->
+ </title>
+ <title minKills="80" color="0x0F0FF0" val="PvP Grand Master">
+ <skill id="395" level="1" time="600" /> <!-- Heroic Miracle for 10 mins -->
+ </title>
+ <title minKills="160" color="0x000000" val="Player Ass Raper">
+ <item id="-200" amount="1000" /> <!-- Clan Reputation Points -->
+ <item id="-300" amount="5000" /> <!-- Fame -->
+ <item id="6673" amount="10" /> <!-- Festival Adena -->
+ </title>
+</list>
\ No newline at end of file
Index: dist/game/data/scripts/custom/PvPTitle/PvPTitleSkill.java
===================================================================
--- dist/game/data/scripts/custom/PvPTitle/PvPTitleSkill.java (revision 0)
+++ dist/game/data/scripts/custom/PvPTitle/PvPTitleSkill.java (working copy)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2004-2013 L2J DataPack
+ *
+ * This file is part of L2J DataPack.
+ *
+ * L2J DataPack 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.
+ *
+ * L2J DataPack 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 custom.PvPTitle;
+
+import com.l2jserver.gameserver.model.holders.SkillHolder;
+
+/**
+ * @author UnAfraid
+ */
+public class PvPTitleSkill extends SkillHolder
+{
+ private final int _time;
+
+ /**
+ * @param skillId
+ * @param skillLvl
+ * @param time
+ */
+ public PvPTitleSkill(int skillId, int skillLvl, int time)
+ {
+ super(skillId, skillLvl);
+ _time = time;
+ }
+
+ /**
+ * @return time in seconds.
+ */
+ public int getTime()
+ {
+ return _time;
+ }
+}