Noticias:

No tienes permiso para ver los enlaces. Para poder verlos Registrate o Conectate.

Menú Principal

Custom PvP Titles

Iniciado por UnAfraid, Jul 24, 2025, 11:45 PM

Tema anterior - Siguiente tema

UnAfraid

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;
+    }
+}