Noticias:

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

Menú Principal

Advanced Champion Mod

Iniciado por Swarlog, Jul 27, 2025, 12:42 AM

Tema anterior - Siguiente tema

Swarlog

Index: dist/game/config/L2JMods.properties
===================================================================
--- dist/game/config/L2JMods.properties	(revision 6306)
+++ dist/game/config/L2JMods.properties	(working copy)
@@ -14,47 +14,13 @@
 # To set all champion mobs to Passive, set True.
 ChampionPassive = False
 
-# % chance for a mob to became champion (0 to disable).
-ChampionFrequency = 5
-
-# Title of all Champion Mobs.
-ChampionTitle = Champion
-
-# Min and max levels allowed for a mob to be a Champion mob.
-ChampionMinLevel = 20
-ChampionMaxLevel = 70
-
-# Hp multiplier for Champion mobs.
-ChampionHp = 8
-
-# Hp Regen Multiplier for Champion mobs.
-ChampionHpRegen = 1.0
-
-# Standard rewards multiplier for Champion mobs.
-ChampionRewards = 8
-
-# Adena & Seal Stone rewards multiplier for Champion mobs.
-ChampionAdenasRewards = 1.0
-
-# P. Attack and M. Attack bonus for Champion mobs.
-ChampionAtk = 1.0
-
-# Physical/Magical Attack Speed bonus for Champion mobs.
-ChampionSpdAtk = 1.0
-
-# Specified reward item ID
-ChampionRewardItemID = 6393
-
-# The amount of the specified reward a player will receive if they are awarded the item.
-ChampionRewardItemQty = 1
-
 # % Chance to obtain a specified reward item from a higher level Champion mob.
 # Default: 0
 ChampionRewardLowerLvlItemChance = 0
 
-# % Chance to obtain a specified reward item from a lower level Champion mob.
+# Allowed level difference between player and mob, when ChampionRewardLowerLvlItemChance is not applied.
 # Default: 0
-ChampionRewardHigherLvlItemChance = 0
+ChampionLvlDiffAllowed = 0
 
 # Do you want to enable the vitality calculation when killing champion mobs?
 # Be aware that it can lead to huge unbalance on your server, your rate for that mob would
Index: java/com/l2jserver/Config.java
===================================================================
--- java/com/l2jserver/Config.java	(revision 6306)
+++ java/com/l2jserver/Config.java	(working copy)
@@ -686,20 +686,8 @@
 	// --------------------------------------------------
 	public static boolean L2JMOD_CHAMPION_ENABLE;
 	public static boolean L2JMOD_CHAMPION_PASSIVE;
-	public static int L2JMOD_CHAMPION_FREQUENCY;
-	public static String L2JMOD_CHAMP_TITLE;
-	public static int L2JMOD_CHAMP_MIN_LVL;
-	public static int L2JMOD_CHAMP_MAX_LVL;
-	public static int L2JMOD_CHAMPION_HP;
-	public static int L2JMOD_CHAMPION_REWARDS;
-	public static float L2JMOD_CHAMPION_ADENAS_REWARDS;
-	public static float L2JMOD_CHAMPION_HP_REGEN;
-	public static float L2JMOD_CHAMPION_ATK;
-	public static float L2JMOD_CHAMPION_SPD_ATK;
 	public static int L2JMOD_CHAMPION_REWARD_LOWER_LVL_ITEM_CHANCE;
-	public static int L2JMOD_CHAMPION_REWARD_HIGHER_LVL_ITEM_CHANCE;
-	public static int L2JMOD_CHAMPION_REWARD_ID;
-	public static int L2JMOD_CHAMPION_REWARD_QTY;
+	public static int L2JMOD_CHAMPION_LVL_DIFF;
 	public static boolean L2JMOD_CHAMPION_ENABLE_VITALITY;
 	public static boolean L2JMOD_CHAMPION_ENABLE_IN_INSTANCES;
 	public static boolean TVT_EVENT_ENABLED;
@@ -2245,20 +2233,8 @@
 			
 			L2JMOD_CHAMPION_ENABLE = L2JModSettings.getBoolean("ChampionEnable", false);
 			L2JMOD_CHAMPION_PASSIVE = L2JModSettings.getBoolean("ChampionPassive", false);
-			L2JMOD_CHAMPION_FREQUENCY = L2JModSettings.getInt("ChampionFrequency", 0);
-			L2JMOD_CHAMP_TITLE = L2JModSettings.getString("ChampionTitle", "Champion");
-			L2JMOD_CHAMP_MIN_LVL = L2JModSettings.getInt("ChampionMinLevel", 20);
-			L2JMOD_CHAMP_MAX_LVL = L2JModSettings.getInt("ChampionMaxLevel", 60);
-			L2JMOD_CHAMPION_HP = L2JModSettings.getInt("ChampionHp", 7);
-			L2JMOD_CHAMPION_HP_REGEN = L2JModSettings.getFloat("ChampionHpRegen", 1);
-			L2JMOD_CHAMPION_REWARDS = L2JModSettings.getInt("ChampionRewards", 8);
-			L2JMOD_CHAMPION_ADENAS_REWARDS = L2JModSettings.getFloat("ChampionAdenasRewards", 1);
-			L2JMOD_CHAMPION_ATK = L2JModSettings.getFloat("ChampionAtk", 1);
-			L2JMOD_CHAMPION_SPD_ATK = L2JModSettings.getFloat("ChampionSpdAtk", 1);
 			L2JMOD_CHAMPION_REWARD_LOWER_LVL_ITEM_CHANCE = L2JModSettings.getInt("ChampionRewardLowerLvlItemChance", 0);
-			L2JMOD_CHAMPION_REWARD_HIGHER_LVL_ITEM_CHANCE = L2JModSettings.getInt("ChampionRewardHigherLvlItemChance", 0);
-			L2JMOD_CHAMPION_REWARD_ID = L2JModSettings.getInt("ChampionRewardItemID", 6393);
-			L2JMOD_CHAMPION_REWARD_QTY = L2JModSettings.getInt("ChampionRewardItemQty", 1);
+			L2JMOD_CHAMPION_LVL_DIFF = L2JModSettings.getInt("ChampionLvlDiffAllowed", 0);
 			L2JMOD_CHAMPION_ENABLE_VITALITY = L2JModSettings.getBoolean("ChampionEnableVitality", false);
 			L2JMOD_CHAMPION_ENABLE_IN_INSTANCES = L2JModSettings.getBoolean("ChampionEnableInInstances", false);
 			
@@ -3516,45 +3492,9 @@
 			case "championenable":
 				L2JMOD_CHAMPION_ENABLE = Boolean.parseBoolean(pValue);
 				break;
-			case "championfrequency":
-				L2JMOD_CHAMPION_FREQUENCY = Integer.parseInt(pValue);
-				break;
-			case "championminlevel":
-				L2JMOD_CHAMP_MIN_LVL = Integer.parseInt(pValue);
-				break;
-			case "championmaxlevel":
-				L2JMOD_CHAMP_MAX_LVL = Integer.parseInt(pValue);
-				break;
-			case "championhp":
-				L2JMOD_CHAMPION_HP = Integer.parseInt(pValue);
-				break;
-			case "championhpregen":
-				L2JMOD_CHAMPION_HP_REGEN = Float.parseFloat(pValue);
-				break;
-			case "championrewards":
-				L2JMOD_CHAMPION_REWARDS = Integer.parseInt(pValue);
-				break;
-			case "championadenasrewards":
-				L2JMOD_CHAMPION_ADENAS_REWARDS = Float.parseFloat(pValue);
-				break;
-			case "championatk":
-				L2JMOD_CHAMPION_ATK = Float.parseFloat(pValue);
-				break;
-			case "championspdatk":
-				L2JMOD_CHAMPION_SPD_ATK = Float.parseFloat(pValue);
-				break;
 			case "championrewardlowerlvlitemchance":
 				L2JMOD_CHAMPION_REWARD_LOWER_LVL_ITEM_CHANCE = Integer.parseInt(pValue);
 				break;
-			case "championrewardhigherlvlitemchance":
-				L2JMOD_CHAMPION_REWARD_HIGHER_LVL_ITEM_CHANCE = Integer.parseInt(pValue);
-				break;
-			case "championrewarditemid":
-				L2JMOD_CHAMPION_REWARD_ID = Integer.parseInt(pValue);
-				break;
-			case "championrewarditemqty":
-				L2JMOD_CHAMPION_REWARD_QTY = Integer.parseInt(pValue);
-				break;
 			case "championenableininstances":
 				L2JMOD_CHAMPION_ENABLE_IN_INSTANCES = Boolean.parseBoolean(pValue);
 				break;
Index: java/com/l2jserver/gameserver/datatables/ChampionData.java
===================================================================
--- java/com/l2jserver/gameserver/datatables/ChampionData.java	(revision 0)
+++ java/com/l2jserver/gameserver/datatables/ChampionData.java	(working copy)
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2004-2013 L2J Server
+ * 
+ * This file is part of L2J Server.
+ * 
+ * L2J Server 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 Server 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 com.l2jserver.gameserver.datatables;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+import com.l2jserver.Config;
+import com.l2jserver.gameserver.engines.DocumentParser;
+import com.l2jserver.gameserver.model.L2DropData;
+import com.l2jserver.gameserver.model.StatsSet;
+import com.l2jserver.gameserver.model.actor.instance.L2MonsterInstance;
+import com.l2jserver.gameserver.model.stats.Stats;
+import com.l2jserver.util.Rnd;
+
+/**
+ * This class holds the data about Champion monster parameters.
+ * @author GKR
+ */
+public final class ChampionData extends DocumentParser
+{
+	private List<StatsSet> _championData;
+	private List<Integer> _championChances;
+	private List<List<L2DropData>> _championRewards;
+	
+	protected ChampionData()
+	{
+		if (Config.L2JMOD_CHAMPION_ENABLE)
+		{
+			_championData = new ArrayList<>();
+			_championChances = new ArrayList<>();
+			_championRewards = new ArrayList<>();
+			load();
+		}
+	}
+	
+	/**
+	 * Loads configuration data.
+	 */
+	@Override
+	public void load()
+	{
+		_championData.clear();
+		_championChances.clear();
+		_championRewards.clear();
+		parseDatapackFile("data/stats/champions.xml");
+		_log.info(getClass().getSimpleName() + ": Loaded " + _championData.size() + " champion templates.");
+	}
+	
+	/**
+	 * Parses configuration files.
+	 */
+	@Override
+	protected void parseDocument()
+	{
+		final Node list = getCurrentDocument().getFirstChild();
+		
+		NamedNodeMap attrs;
+		int sumChance = 0;
+		for (Node n = list.getFirstChild(); n != null; n = n.getNextSibling())
+		{
+			StatsSet dataHolder = new StatsSet();
+			List<L2DropData> rewards = new ArrayList<>();
+			if (n.getNodeName().equals("champion"))
+			{
+				if (sumChance <= 1000000)
+				{
+					for (Node championData = n.getFirstChild(); championData != null; championData = championData.getNextSibling())
+					{
+						if (championData.getNodeName().equals("chance"))
+						{
+							int chance = (int) (Float.parseFloat(championData.getTextContent()) * 10000);
+							sumChance += chance;
+							if (sumChance <= 1000000)
+							{
+								_championChances.add(chance);
+							}
+							else
+							{
+								_log.warning(getClass().getSimpleName() + ": sum of chances is greater, than 100% - champion definition ignored");
+								break;
+							}
+						}
+						else if (championData.getNodeName().equals("reward"))
+						{
+							attrs = championData.getAttributes();
+							final int itemId = parseInteger(attrs, "id");
+							final int min = parseInteger(attrs, "min");
+							final int max = parseInteger(attrs, "max");
+							if (ItemTable.getInstance().getTemplate(itemId) != null)
+							{
+								rewards.add(new L2DropData(itemId, min, max, 0));
+							}
+							else
+							{
+								_log.warning(getClass().getSimpleName() + ": invalid item id: " + itemId);
+							}
+						}
+						else
+						{
+							dataHolder.set(championData.getNodeName(), championData.getTextContent());
+						}
+					}
+					_championData.add(dataHolder);
+					_championRewards.add(rewards);
+				}
+				else
+				{
+					_log.warning(getClass().getSimpleName() + ": sum of chances is greater, than 100% - champion definition ignored");
+				}
+			}
+		}
+	}
+	
+	/**
+	 * @param championType type of champion.
+	 * @param name String name of multiplier.
+	 * @return value of multiplier for given champion type.
+	 */
+	public float getMultiplier(int championType, String name)
+	{
+		float mul;
+		if ((championType >= 0) && (championType < _championData.size()))
+		{
+			mul = _championData.get(championType).getFloat(name, 1);
+		}
+		else
+		{
+			mul = 1;
+		}
+		
+		return mul;
+	}
+	
+	/**
+	 * @param championType type of champion.
+	 * @param stat stat to calculate multiplier.
+	 * @return value of multiplier for given champion type.
+	 */
+	public float getMultiplier(int championType, Stats stat)
+	{
+		return getMultiplier(championType, stat.getValue());
+	}
+	
+	/**
+	 * @param championType type of champion
+	 * @param monster monster to check
+	 * @return {@code true} if given monster meeets level requirements for given type of champion
+	 */
+	private boolean checkLevel(int championType, L2MonsterInstance monster)
+	{
+		boolean result;
+		if ((championType >= 0) && (championType < _championData.size()))
+		{
+			int minLvl = _championData.get(championType).getInt("minLvl", 1);
+			int maxLvl = _championData.get(championType).getInt("maxLvl", 1000);
+			
+			result = (monster.getLevel() >= minLvl) && (monster.getLevel() <= maxLvl);
+		}
+		else
+		{
+			result = false;
+		}
+		
+		return result;
+	}
+	
+	/**
+	 * @param monster monster to check
+	 * @return random type of champion for given monster, based on config rules
+	 */
+	public int calculateChampionType(L2MonsterInstance monster)
+	{
+		int championType = -1;
+		
+		// Check, if monster meets all conditions
+		if (!monster.getTemplate().isQuestMonster() && !monster.isRaid() && !monster.isRaidMinion() && (Config.L2JMOD_CHAMPION_ENABLE_IN_INSTANCES || (monster.getInstanceId() == 0)))
+		{
+			int totalProb = 0;
+			for (int i = 0; i < _championChances.size(); i++)
+			{
+				if (!checkLevel(i, monster))
+				{
+					continue;
+				}
+				
+				final int fortune = Rnd.get(1000000);
+				if ((fortune >= totalProb) && (fortune < (totalProb + _championChances.get(i))))
+				{
+					championType = i;
+					break;
+				}
+				totalProb += _championChances.get(i);
+			}
+		}
+		return championType;
+	}
+	
+	/**
+	 * @param championType type of champion.
+	 * @return glow type for given champion type.
+	 */
+	public int getGlow(int championType)
+	{
+		int teamId;
+		if ((championType >= 0) && (championType < _championData.size()))
+		{
+			teamId = _championData.get(championType).getInt("glow", 0);
+		}
+		else
+		{
+			teamId = 0;
+		}
+		
+		return teamId;
+	}
+	
+	/**
+	 * @param championType type of champion.
+	 * @return title for given champion type.
+	 */
+	public String getTitle(int championType)
+	{
+		String title;
+		if ((championType >= 0) && (championType < _championData.size()))
+		{
+			title = _championData.get(championType).getString("title", "");
+		}
+		else
+		{
+			title = "";
+		}
+		
+		return title;
+	}
+	
+	/**
+	 * @param championType type of champion.
+	 * @return glow List of specific rewards for given champion type.
+	 */
+	public List<L2DropData> getReward(int championType)
+	{
+		if ((championType >= 0) && (championType < _championData.size()))
+		{
+			return _championRewards.get(championType);
+		}
+		
+		return null;
+	}
+	
+	/**
+	 * @param championType type of champion
+	 * @return {@code true} if given type of champion has personal reward.
+	 */
+	public boolean hasPersonalReward(int championType)
+	{
+		return ((getReward(championType) != null) && !getReward(championType).isEmpty());
+	}
+	
+	public static ChampionData getInstance()
+	{
+		return SingletonHolder._instance;
+	}
+	
+	private static class SingletonHolder
+	{
+		protected static final ChampionData _instance = new ChampionData();
+	}
+}
\ No newline at end of file
Index: java/com/l2jserver/gameserver/GameServer.java
===================================================================
--- java/com/l2jserver/gameserver/GameServer.java	(revision 6306)
+++ java/com/l2jserver/gameserver/GameServer.java	(working copy)
@@ -40,6 +40,7 @@
 import com.l2jserver.gameserver.datatables.AdminTable;
 import com.l2jserver.gameserver.datatables.ArmorSetsData;
 import com.l2jserver.gameserver.datatables.AugmentationData;
+import com.l2jserver.gameserver.datatables.ChampionData;
 import com.l2jserver.gameserver.datatables.BotReportTable;
 import com.l2jserver.gameserver.datatables.BuyListData;
 import com.l2jserver.gameserver.datatables.CategoryData;
@@ -274,6 +275,10 @@
 		HerbDropTable.getInstance();
 		SkillLearnData.getInstance();
 		NpcTable.getInstance();
+		if (Config.L2JMOD_CHAMPION_ENABLE)
+		{
+			ChampionData.getInstance();
+		}		
 		WalkingManager.getInstance();
 		StaticObjects.getInstance();
 		ZoneManager.getInstance();
Index: java/com/l2jserver/gameserver/model/actor/L2Attackable.java
===================================================================
--- java/com/l2jserver/gameserver/model/actor/L2Attackable.java	(revision 6306)
+++ java/com/l2jserver/gameserver/model/actor/L2Attackable.java	(working copy)
@@ -34,6 +34,7 @@
 import com.l2jserver.gameserver.ai.L2CharacterAI;
 import com.l2jserver.gameserver.ai.L2FortSiegeGuardAI;
 import com.l2jserver.gameserver.ai.L2SiegeGuardAI;
+import com.l2jserver.gameserver.datatables.ChampionData;
 import com.l2jserver.gameserver.datatables.EventDroplist;
 import com.l2jserver.gameserver.datatables.EventDroplist.DateDrop;
 import com.l2jserver.gameserver.datatables.HerbDropTable;
@@ -80,7 +81,7 @@
 {
 	private boolean _isRaid = false;
 	private boolean _isRaidMinion = false;
-	private boolean _champion = false;
+	private int _championType = -1;
 	private final Map<L2Character, AggroInfo> _aggroList = new ConcurrentHashMap<>();
 	private boolean _isReturningToSpawnPoint = false;
 	private boolean _canReturnToSpawnPoint = true;
@@ -521,10 +522,10 @@
 							long exp = expSp[0];
 							int sp = expSp[1];
 							
-							if (Config.L2JMOD_CHAMPION_ENABLE && isChampion())
+							if (isChampion())
 							{
-								exp *= Config.L2JMOD_CHAMPION_REWARDS;
-								sp *= Config.L2JMOD_CHAMPION_REWARDS;
+								exp *= ChampionData.getInstance().getMultiplier(getChampionType(), Stats.BONUS_EXP);
+								sp *= ChampionData.getInstance().getMultiplier(getChampionType(), Stats.BONUS_SP);
 							}
 							
 							exp *= 1 - penalty;
@@ -630,10 +631,10 @@
 						long exp = expSp[0];
 						int sp = expSp[1];
 						
-						if (Config.L2JMOD_CHAMPION_ENABLE && isChampion())
+						if (isChampion())
 						{
-							exp *= Config.L2JMOD_CHAMPION_REWARDS;
-							sp *= Config.L2JMOD_CHAMPION_REWARDS;
+							exp *= ChampionData.getInstance().getMultiplier(getChampionType(), Stats.BONUS_EXP);
+							sp *= ChampionData.getInstance().getMultiplier(getChampionType(), Stats.BONUS_SP);
 						}
 						
 						exp *= partyMul;
@@ -1045,9 +1046,9 @@
 			dropChance *= isRaid() && !isRaidMinion() ? Config.RATE_DROP_ITEMS_BY_RAID : Config.RATE_DROP_ITEMS;
 		}
 		
-		if (Config.L2JMOD_CHAMPION_ENABLE && isChampion())
+		if (isChampion())
 		{
-			dropChance *= Config.L2JMOD_CHAMPION_REWARDS;
+			dropChance *= ChampionData.getInstance().getMultiplier(getChampionType(), "bonusDrop");
 		}
 		
 		// Set our limits for chance of drop
@@ -1103,9 +1104,9 @@
 			dropChance -= L2DropData.MAX_CHANCE;
 		}
 		
-		if (Config.L2JMOD_CHAMPION_ENABLE && isChampion() && ((drop.getItemId() == PcInventory.ADENA_ID) || Util.contains(SevenSigns.SEAL_STONE_IDS, drop.getItemId())))
+		if (isChampion() && ((drop.getItemId() == PcInventory.ADENA_ID) || Util.contains(SevenSigns.SEAL_STONE_IDS, drop.getItemId())))
 		{
-			itemCount *= Config.L2JMOD_CHAMPION_ADENAS_REWARDS;
+			itemCount *= ChampionData.getInstance().getMultiplier(getChampionType(), "bonusDropAdena");
 		}
 		
 		if (itemCount > 0)
@@ -1163,9 +1164,9 @@
 		// Applies Drop rates
 		categoryDropChance *= isRaid() && !isRaidMinion() ? Config.RATE_DROP_ITEMS_BY_RAID : Config.RATE_DROP_ITEMS;
 		
-		if (Config.L2JMOD_CHAMPION_ENABLE && isChampion())
+		if (isChampion())
 		{
-			categoryDropChance *= Config.L2JMOD_CHAMPION_REWARDS;
+			categoryDropChance *= ChampionData.getInstance().getMultiplier(getChampionType(), "bonusDrop");
 		}
 		
 		// Set our limits for chance of drop
@@ -1207,9 +1208,9 @@
 				dropChance *= isRaid() && !isRaidMinion() ? Config.RATE_DROP_ITEMS_BY_RAID : Config.RATE_DROP_ITEMS;
 			}
 			
-			if (Config.L2JMOD_CHAMPION_ENABLE && isChampion())
+			if (isChampion())
 			{
-				dropChance *= Config.L2JMOD_CHAMPION_REWARDS;
+				dropChance *= ChampionData.getInstance().getMultiplier(getChampionType(), "bonusDrop");
 			}
 			
 			dropChance = Math.round(dropChance);
@@ -1269,9 +1270,9 @@
 				dropChance -= L2DropData.MAX_CHANCE;
 			}
 			
-			if (Config.L2JMOD_CHAMPION_ENABLE && isChampion() && ((drop.getItemId() == PcInventory.ADENA_ID) || Util.contains(SevenSigns.SEAL_STONE_IDS, drop.getItemId())))
+			if (isChampion() && ((drop.getItemId() == PcInventory.ADENA_ID) || Util.contains(SevenSigns.SEAL_STONE_IDS, drop.getItemId())))
 			{
-				itemCount *= Config.L2JMOD_CHAMPION_ADENAS_REWARDS;
+				itemCount *= ChampionData.getInstance().getMultiplier(getChampionType(), "bonusDropAdena");
 			}
 			
 			if (!Config.MULTIPLE_ITEM_DROP && !ItemTable.getInstance().getTemplate(drop.getItemId()).isStackable() && (itemCount > 1))
@@ -1580,33 +1581,27 @@
 			}
 		}
 		// Apply Special Item drop with random(rnd) quantity(qty) for champions.
-		if (Config.L2JMOD_CHAMPION_ENABLE && isChampion() && ((Config.L2JMOD_CHAMPION_REWARD_LOWER_LVL_ITEM_CHANCE > 0) || (Config.L2JMOD_CHAMPION_REWARD_HIGHER_LVL_ITEM_CHANCE > 0)))
+		if (isChampion() && ChampionData.getInstance().hasPersonalReward(getChampionType()) && (((getLevel() + Config.L2JMOD_CHAMPION_LVL_DIFF) >= player.getLevel()) || (Config.L2JMOD_CHAMPION_REWARD_LOWER_LVL_ITEM_CHANCE > 0)))
 		{
-			int champqty = Rnd.get(Config.L2JMOD_CHAMPION_REWARD_QTY);
-			ItemHolder item = new ItemHolder(Config.L2JMOD_CHAMPION_REWARD_ID, ++champqty);
-			
-			if ((player.getLevel() <= getLevel()) && (Rnd.get(100) < Config.L2JMOD_CHAMPION_REWARD_LOWER_LVL_ITEM_CHANCE))
+			for (L2DropData reward : ChampionData.getInstance().getReward(getChampionType()))
 			{
-				if (Config.AUTO_LOOT || isFlying())
+				int champqty = Rnd.get(reward.getMinDrop(), reward.getMaxDrop());
+				
+				if (champqty > 0)
 				{
-					player.addItem("ChampionLoot", item.getId(), item.getCount(), this, true); // Give the item(s) to the L2PcInstance that has killed the L2Attackable
+					if (((getLevel() + Config.L2JMOD_CHAMPION_LVL_DIFF) >= player.getLevel()) || ((Rnd.get(100) < Config.L2JMOD_CHAMPION_REWARD_LOWER_LVL_ITEM_CHANCE)))
+					{
+						if (Config.AUTO_LOOT || isFlying())
+						{
+							player.addItem("ChampionLoot", reward.getItemId(), champqty, this, true); // Give the item(s) to the L2PcInstance that has killed the L2Attackable
+						}
+						else
+						{
+							dropItem(player, reward.getItemId(), champqty);
+						}
+					}
 				}
-				else
-				{
-					dropItem(player, item);
-				}
 			}
-			else if ((player.getLevel() > getLevel()) && (Rnd.get(100) < Config.L2JMOD_CHAMPION_REWARD_HIGHER_LVL_ITEM_CHANCE))
-			{
-				if (Config.AUTO_LOOT || isFlying())
-				{
-					player.addItem("ChampionLoot", item.getId(), item.getCount(), this, true); // Give the item(s) to the L2PcInstance that has killed the L2Attackable
-				}
-				else
-				{
-					dropItem(player, item);
-				}
-			}
 		}
 		
 		// Instant Item Drop :>
@@ -2312,15 +2307,29 @@
 		return null;
 	}
 	
-	public void setChampion(boolean champ)
+	/**
+	 * Set this champion type of this Npc.
+	 * @param champType
+	 */
+	public void setChampionType(int champType)
 	{
-		_champion = champ;
+		_championType = champType;
+		setTeam(ChampionData.getInstance().getGlow(champType));
 	}
 	
+	/**
+	 * @return champion type of this L2Attackable.
+	 */
 	@Override
+	public int getChampionType()
+	{
+		return _championType;
+	}
+	
+	@Override
 	public boolean isChampion()
 	{
-		return _champion;
+		return (Config.L2JMOD_CHAMPION_ENABLE && (_championType >= 0));
 	}
 	
 	@Override
Index: java/com/l2jserver/gameserver/model/actor/L2Character.java
===================================================================
--- java/com/l2jserver/gameserver/model/actor/L2Character.java	(revision 6306)
+++ java/com/l2jserver/gameserver/model/actor/L2Character.java	(working copy)
@@ -44,6 +44,7 @@
 import com.l2jserver.gameserver.ai.CtrlIntention;
 import com.l2jserver.gameserver.ai.L2AttackableAI;
 import com.l2jserver.gameserver.ai.L2CharacterAI;
+import com.l2jserver.gameserver.datatables.ChampionData;
 import com.l2jserver.gameserver.datatables.DoorTable;
 import com.l2jserver.gameserver.datatables.ItemTable;
 import com.l2jserver.gameserver.datatables.SkillTable;
@@ -6538,9 +6539,9 @@
 	
 	public void reduceCurrentHp(double i, L2Character attacker, boolean awake, boolean isDOT, L2Skill skill)
 	{
-		if (Config.L2JMOD_CHAMPION_ENABLE && isChampion() && (Config.L2JMOD_CHAMPION_HP != 0))
+		if (isChampion())
 		{
-			getStatus().reduceHp(i / Config.L2JMOD_CHAMPION_HP, attacker, awake, isDOT, false);
+			getStatus().reduceHp(i / ChampionData.getInstance().getMultiplier(getChampionType(), Stats.MAX_HP), attacker, awake, isDOT, false);
 		}
 		else
 		{
@@ -6651,6 +6652,14 @@
 	}
 	
 	/**
+	 * @return champion type of this L2Attackable.
+	 */
+	public int getChampionType()
+	{
+		return -1;
+	}
+	
+	/**
 	 * Check player max buff count
 	 * @return max buff count
 	 */
Index: java/com/l2jserver/gameserver/model/actor/stat/CharStat.java
===================================================================
--- java/com/l2jserver/gameserver/model/actor/stat/CharStat.java	(revision 6306)
+++ java/com/l2jserver/gameserver/model/actor/stat/CharStat.java	(working copy)
@@ -21,6 +21,7 @@
 import java.util.Arrays;
 
 import com.l2jserver.Config;
+import com.l2jserver.gameserver.datatables.ChampionData;
 import com.l2jserver.gameserver.model.Elementals;
 import com.l2jserver.gameserver.model.PcCondOverride;
 import com.l2jserver.gameserver.model.actor.L2Character;
@@ -297,9 +298,9 @@
 	public int getMAtk(L2Character target, L2Skill skill)
 	{
 		float bonusAtk = 1;
-		if (Config.L2JMOD_CHAMPION_ENABLE && _activeChar.isChampion())
+		if (_activeChar.isChampion())
 		{
-			bonusAtk = Config.L2JMOD_CHAMPION_ATK;
+			bonusAtk = ChampionData.getInstance().getMultiplier(_activeChar.getChampionType(), Stats.MAGIC_ATTACK);
 		}
 		if (_activeChar.isRaid())
 		{
@@ -316,9 +317,9 @@
 	public int getMAtkSpd()
 	{
 		float bonusSpdAtk = 1;
-		if (Config.L2JMOD_CHAMPION_ENABLE && _activeChar.isChampion())
+		if (_activeChar.isChampion())
 		{
-			bonusSpdAtk = Config.L2JMOD_CHAMPION_SPD_ATK;
+			bonusSpdAtk = ChampionData.getInstance().getMultiplier(_activeChar.getChampionType(), Stats.MAGIC_ATTACK_SPEED);
 		}
 		
 		double val = calcStat(Stats.MAGIC_ATTACK_SPEED, _activeChar.getTemplate().getBaseMAtkSpd() * bonusSpdAtk);
@@ -359,6 +360,11 @@
 		// Get the base MDef of the L2Character
 		double defence = _activeChar.getTemplate().getBaseMDef();
 		
+		if (_activeChar.isChampion())
+		{
+			defence *= ChampionData.getInstance().getMultiplier(_activeChar.getChampionType(), Stats.MAGIC_DEFENCE);
+		}
+
 		// Calculate modifier for Raid Bosses
 		if (_activeChar.isRaid())
 		{
@@ -415,9 +421,9 @@
 	public int getPAtk(L2Character target)
 	{
 		float bonusAtk = 1;
-		if (Config.L2JMOD_CHAMPION_ENABLE && _activeChar.isChampion())
+		if (_activeChar.isChampion())
 		{
-			bonusAtk = Config.L2JMOD_CHAMPION_ATK;
+			bonusAtk = ChampionData.getInstance().getMultiplier(_activeChar.getChampionType(), Stats.POWER_ATTACK);
 		}
 		if (_activeChar.isRaid())
 		{
@@ -432,9 +438,9 @@
 	public int getPAtkSpd()
 	{
 		float bonusAtk = 1;
-		if (Config.L2JMOD_CHAMPION_ENABLE && _activeChar.isChampion())
+		if (_activeChar.isChampion())
 		{
-			bonusAtk = Config.L2JMOD_CHAMPION_SPD_ATK;
+			bonusAtk = ChampionData.getInstance().getMultiplier(_activeChar.getChampionType(), Stats.POWER_ATTACK_SPEED);
 		}
 		int val = (int) Math.round(calcStat(Stats.POWER_ATTACK_SPEED, _activeChar.getTemplate().getBasePAtkSpd() * bonusAtk, null, null));
 		return val;
@@ -446,7 +452,19 @@
 	 */
 	public int getPDef(L2Character target)
 	{
-		return (int) calcStat(Stats.POWER_DEFENCE, (_activeChar.isRaid()) ? _activeChar.getTemplate().getBasePDef() * Config.RAID_PDEFENCE_MULTIPLIER : _activeChar.getTemplate().getBasePDef(), target, null);
+		float bonus = 1;
+		
+		if (_activeChar.isChampion())
+		{
+			bonus = ChampionData.getInstance().getMultiplier(_activeChar.getChampionType(), Stats.POWER_DEFENCE);
+		}
+		
+		if (_activeChar.isRaid())
+		{
+			bonus *= Config.RAID_PDEFENCE_MULTIPLIER;
+		}
+		
+		return (int) calcStat(Stats.POWER_DEFENCE, _activeChar.getTemplate().getBasePDef() * bonus, target, null);
 	}
 	
 	/**
@@ -471,12 +489,17 @@
 	 */
 	public int getRunSpeed()
 	{
-		final float baseRunSpd = _activeChar.isInsideZone(ZoneId.WATER) ? getSwimRunSpeed() : getBaseMoveSpeed(MoveType.RUN);
+		float baseRunSpd = _activeChar.isInsideZone(ZoneId.WATER) ? getSwimRunSpeed() : getBaseMoveSpeed(MoveType.RUN);
 		if (baseRunSpd == 0)
 		{
 			return 0;
 		}
 		
+		if (_activeChar.isChampion())
+		{
+			baseRunSpd *= ChampionData.getInstance().getMultiplier(_activeChar.getChampionType(), "moveSpd");
+		}
+		
 		return (int) Math.round(calcStat(Stats.MOVE_SPEED, baseRunSpd, null, null));
 	}
 	
@@ -522,12 +545,17 @@
 	 */
 	public int getWalkSpeed()
 	{
-		final float baseWalkSpd = _activeChar.isInsideZone(ZoneId.WATER) ? getSwimWalkSpeed() : getBaseMoveSpeed(MoveType.WALK);
+		float baseWalkSpd = _activeChar.isInsideZone(ZoneId.WATER) ? getSwimWalkSpeed() : getBaseMoveSpeed(MoveType.WALK);
 		if (baseWalkSpd == 0)
 		{
 			return 0;
 		}
 		
+		if (_activeChar.isChampion())
+		{
+			baseWalkSpd *= ChampionData.getInstance().getMultiplier(_activeChar.getChampionType(), "moveSpd");
+		}
+		
 		return (int) Math.round(calcStat(Stats.MOVE_SPEED, baseWalkSpd));
 	}
 	
Index: java/com/l2jserver/gameserver/model/actor/status/CharStatus.java
===================================================================
--- java/com/l2jserver/gameserver/model/actor/status/CharStatus.java	(revision 6306)
+++ java/com/l2jserver/gameserver/model/actor/status/CharStatus.java	(working copy)
@@ -27,10 +27,12 @@
 
 import com.l2jserver.Config;
 import com.l2jserver.gameserver.ThreadPoolManager;
+import com.l2jserver.gameserver.datatables.ChampionData;
 import com.l2jserver.gameserver.model.actor.L2Character;
 import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
 import com.l2jserver.gameserver.model.actor.stat.CharStat;
 import com.l2jserver.gameserver.model.stats.Formulas;
+import com.l2jserver.gameserver.model.stats.Stats;
 import com.l2jserver.util.Rnd;
 
 public class CharStatus
@@ -186,7 +188,14 @@
 	
 	public void reduceMp(double value)
 	{
-		setCurrentMp(Math.max(getCurrentMp() - value, 0));
+		if (getActiveChar().isChampion())
+		{
+			setCurrentMp(Math.max(getCurrentMp() - (value / ChampionData.getInstance().getMultiplier(getActiveChar().getChampionType(), Stats.MAX_MP)), 0));
+		}
+		else
+		{
+			setCurrentMp(Math.max(getCurrentMp() - value, 0));
+		}
 	}
 	
 	/**
Index: java/com/l2jserver/gameserver/model/L2Spawn.java
===================================================================
--- java/com/l2jserver/gameserver/model/L2Spawn.java	(revision 6306)
+++ java/com/l2jserver/gameserver/model/L2Spawn.java	(working copy)
@@ -30,6 +30,7 @@
 import com.l2jserver.Config;
 import com.l2jserver.gameserver.GeoData;
 import com.l2jserver.gameserver.ThreadPoolManager;
+import com.l2jserver.gameserver.datatables.ChampionData;
 import com.l2jserver.gameserver.datatables.NpcPersonalAIData;
 import com.l2jserver.gameserver.datatables.TerritoryTable;
 import com.l2jserver.gameserver.idfactory.IdFactory;
@@ -36,6 +37,7 @@
 import com.l2jserver.gameserver.model.actor.L2Attackable;
 import com.l2jserver.gameserver.model.actor.L2Character;
 import com.l2jserver.gameserver.model.actor.L2Npc;
+import com.l2jserver.gameserver.model.actor.instance.L2MonsterInstance;
 import com.l2jserver.gameserver.model.actor.templates.L2NpcTemplate;
 import com.l2jserver.gameserver.model.interfaces.IIdentifiable;
 import com.l2jserver.gameserver.model.interfaces.ILocational;
@@ -640,23 +642,11 @@
 			mob.setHeading(getHeading());
 		}
 		
-		if (mob instanceof L2Attackable)
+		if (Config.L2JMOD_CHAMPION_ENABLE && mob.isMonster())
 		{
-			((L2Attackable) mob).setChampion(false);
+			((L2MonsterInstance) mob).setChampionType(ChampionData.getInstance().calculateChampionType((L2MonsterInstance) mob));
 		}
 		
-		if (Config.L2JMOD_CHAMPION_ENABLE)
-		{
-			// Set champion on next spawn
-			if (mob.isMonster() && !getTemplate().isQuestMonster() && !mob.isRaid() && !mob.isRaidMinion() && (Config.L2JMOD_CHAMPION_FREQUENCY > 0) && (mob.getLevel() >= Config.L2JMOD_CHAMP_MIN_LVL) && (mob.getLevel() <= Config.L2JMOD_CHAMP_MAX_LVL) && (Config.L2JMOD_CHAMPION_ENABLE_IN_INSTANCES || (getInstanceId() == 0)))
-			{
-				if (Rnd.get(100) < Config.L2JMOD_CHAMPION_FREQUENCY)
-				{
-					((L2Attackable) mob).setChampion(true);
-				}
-			}
-		}
-		
 		// Link the L2NpcInstance to this L2Spawn
 		mob.setSpawn(this);
 		
Index: java/com/l2jserver/gameserver/model/quest/Quest.java
===================================================================
--- java/com/l2jserver/gameserver/model/quest/Quest.java	(revision 6306)
+++ java/com/l2jserver/gameserver/model/quest/Quest.java	(working copy)
@@ -39,6 +39,7 @@
 import com.l2jserver.gameserver.GameTimeController;
 import com.l2jserver.gameserver.ThreadPoolManager;
 import com.l2jserver.gameserver.cache.HtmCache;
+import com.l2jserver.gameserver.datatables.ChampionData;
 import com.l2jserver.gameserver.datatables.DoorTable;
 import com.l2jserver.gameserver.datatables.ItemTable;
 import com.l2jserver.gameserver.datatables.NpcTable;
@@ -3370,18 +3371,18 @@
 		minAmount *= Config.RATE_QUEST_DROP;
 		maxAmount *= Config.RATE_QUEST_DROP;
 		dropChance *= Config.RATE_QUEST_DROP; // TODO separate configs for rate and amount
-		if ((npc != null) && Config.L2JMOD_CHAMPION_ENABLE && npc.isChampion())
+		if ((npc != null) && npc.isChampion())
 		{
-			dropChance *= Config.L2JMOD_CHAMPION_REWARDS;
+			dropChance *= ChampionData.getInstance().getMultiplier(npc.getChampionType(), "bonusDrop");
 			if ((itemId == PcInventory.ADENA_ID) || (itemId == PcInventory.ANCIENT_ADENA_ID))
 			{
-				minAmount *= Config.L2JMOD_CHAMPION_ADENAS_REWARDS;
-				maxAmount *= Config.L2JMOD_CHAMPION_ADENAS_REWARDS;
+				minAmount *= ChampionData.getInstance().getMultiplier(npc.getChampionType(), "bonusDropAdena");
+				maxAmount *= ChampionData.getInstance().getMultiplier(npc.getChampionType(), "bonusDropAdena");
 			}
 			else
 			{
-				minAmount *= Config.L2JMOD_CHAMPION_REWARDS;
-				maxAmount *= Config.L2JMOD_CHAMPION_REWARDS;
+				minAmount *= ChampionData.getInstance().getMultiplier(npc.getChampionType(), "bonusDrop");
+				maxAmount *= ChampionData.getInstance().getMultiplier(npc.getChampionType(), "bonusDrop");
 			}
 		}
 		
Index: java/com/l2jserver/gameserver/model/stats/Formulas.java
===================================================================
--- java/com/l2jserver/gameserver/model/stats/Formulas.java	(revision 6306)
+++ java/com/l2jserver/gameserver/model/stats/Formulas.java	(working copy)
@@ -25,6 +25,7 @@
 import com.l2jserver.Config;
 import com.l2jserver.gameserver.SevenSigns;
 import com.l2jserver.gameserver.SevenSignsFestival;
+import com.l2jserver.gameserver.datatables.ChampionData;
 import com.l2jserver.gameserver.datatables.HitConditionBonus;
 import com.l2jserver.gameserver.datatables.KarmaData;
 import com.l2jserver.gameserver.instancemanager.CastleManager;
@@ -262,12 +263,12 @@
 		double hpRegenMultiplier = cha.isRaid() ? Config.RAID_HP_REGEN_MULTIPLIER : Config.HP_REGEN_MULTIPLIER;
 		double hpRegenBonus = 0;
 		
-		if (Config.L2JMOD_CHAMPION_ENABLE && cha.isChampion())
+		if (cha.isChampion())
 		{
-			hpRegenMultiplier *= Config.L2JMOD_CHAMPION_HP_REGEN;
+			hpRegenMultiplier *= ChampionData.getInstance().getMultiplier(cha.getChampionType(), Stats.REGENERATE_HP_RATE);
 		}
 		
-		if (cha.isPlayer())
+		else if (cha.isPlayer())
 		{
 			L2PcInstance player = cha.getActingPlayer();
 			
@@ -383,7 +384,11 @@
 		double mpRegenMultiplier = cha.isRaid() ? Config.RAID_MP_REGEN_MULTIPLIER : Config.MP_REGEN_MULTIPLIER;
 		double mpRegenBonus = 0;
 		
-		if (cha.isPlayer())
+		if (cha.isChampion())
+ 		{
+			mpRegenMultiplier *= ChampionData.getInstance().getMultiplier(cha.getChampionType(), Stats.REGENERATE_MP_RATE);
+		}
+		else if (cha.isPlayer())
 		{
 			L2PcInstance player = cha.getActingPlayer();
 			
Index: java/com/l2jserver/gameserver/network/serverpackets/AbstractNpcInfo.java
===================================================================
--- java/com/l2jserver/gameserver/network/serverpackets/AbstractNpcInfo.java	(revision 6306)
+++ java/com/l2jserver/gameserver/network/serverpackets/AbstractNpcInfo.java	(working copy)
@@ -19,6 +19,7 @@
 package com.l2jserver.gameserver.network.serverpackets;
 
 import com.l2jserver.Config;
+import com.l2jserver.gameserver.datatables.ChampionData;
 import com.l2jserver.gameserver.datatables.ClanTable;
 import com.l2jserver.gameserver.instancemanager.TownManager;
 import com.l2jserver.gameserver.model.L2Clan;
@@ -99,9 +100,9 @@
 				_name = cha.getName();// On every subclass
 			}
 			
-			if (Config.L2JMOD_CHAMPION_ENABLE && cha.isChampion())
+			if (cha.isChampion() && !ChampionData.getInstance().getTitle(cha.getChampionType()).isEmpty())
 			{
-				_title = (Config.L2JMOD_CHAMP_TITLE); // On every subclass
+				_title = ChampionData.getInstance().getTitle(cha.getChampionType()); // On every subclass
 			}
 			else if (cha.getTemplate().isServerSideTitle())
 			{

By GKR, up  VlLight.