Index: config/altsettings.properties =================================================================== --- config/altsettings.properties (revision 703) +++ config/altsettings.properties (working copy) @@ -216,6 +216,29 @@ AltLottery2and1NumberPrize = 200 #------------------------------------------------------------- +# Champion mobs +#------------------------------------------------------------- +# Chance for a mob to become a champion (in percents) - 0 to disable +ChampionFrequency = 8 +# Min and max lvl allowed for a mob to be champion +ChampionMinLevel = 20 +ChampionMaxLevel = 70 +# Hp multiplier +ChampionHp = 7 +# Hp Regen Multiplier +ChampionRegenHp = 1. +# Rewards multiplier +ChampionRewards = 8 +# Adenas & seal stones rewards multiplier +ChampionAdenasRewards = 1 +# Atk bonus for champion (changes apply on patk & matk) +ChampionAtk = 1. +# Spd Atk bonus for champion (changes apply on patkspd & matkspd) +ChampionSpdAtk = 1. +# Chance to obtain a glittering medal from a higher lvl champion (in percents) +ChampionMedal = 0 + +#------------------------------------------------------------- # Debug & Dev config #------------------------------------------------------------- # Don't load quests Index: net/sf/l2j/Config.java =================================================================== --- net/sf/l2j/Config.java (revision 703) +++ net/sf/l2j/Config.java (working copy) @@ -154,6 +154,27 @@ /** Fast or slow multiply coefficient for skill hit time */ public static float ALT_GAME_SKILL_HIT_RATE; + + /** Named mobs. Random spawning mobs with multiples of health and rewards. */ + /** Frequency of spawn */ + public static int CHAMPION_FREQUENCY; + /** Min/max allowed level */ + public static int CHAMP_MIN_LVL; + public static int CHAMP_MAX_LVL; + /** Hp multiplier */ + public static int CHAMPION_HP; + /** Hp Regen Multiplier **/ + public static float CHAMPION_HP_REGEN; + /** Rewards multiplier */ + public static int CHAMPION_REWARDS; + /** Adenas rewards multiplier */ + public static int CHAMPION_ADENAS_REWARDS; + /** Atk bonus for champion **/ + public static float CHAMPION_ATK; + /** Spd Atk bonus for champion **/ + public static float CHAMPION_SPD_ATK; + /*** Chance to obtain a glittering medal from a higher lvl champion **/ + public static int CHAMPION_MEDAL; /** Alternative gameing - loss of XP on death */ public static boolean ALT_GAME_DELEVEL; @@ -1490,6 +1511,16 @@ ALT_GAME_FREIGHTS = Boolean.parseBoolean(altSettings.getProperty("AltGameFreights", "false")); ALT_GAME_FREIGHT_PRICE = Integer.parseInt(altSettings.getProperty("AltGameFreightPrice", "1000")); ALT_GAME_SKILL_HIT_RATE = Float.parseFloat(altSettings.getProperty("AltGameSkillHitRate", "1.")); + CHAMPION_FREQUENCY = Integer.parseInt(altSettings.getProperty("ChampionFrequency", "0")); + CHAMP_MIN_LVL = Integer.parseInt(altSettings.getProperty("ChampionMinLevel", "20")); + CHAMP_MAX_LVL = Integer.parseInt(altSettings.getProperty("ChampionMaxLevel", "60")); + CHAMPION_HP = Integer.parseInt(altSettings.getProperty("ChampionHp", "7")); + CHAMPION_HP_REGEN = Float.parseFloat(altSettings.getProperty("ChampionHpRegen", "1.")); + CHAMPION_REWARDS = Integer.parseInt(altSettings.getProperty("ChampionRewards", "8")); + CHAMPION_ADENAS_REWARDS = Integer.parseInt(altSettings.getProperty("ChampionAdenasRewards", "1")); + CHAMPION_ATK = Float.parseFloat(altSettings.getProperty("ChampionAtk", "1.")); + CHAMPION_SPD_ATK = Float.parseFloat(altSettings.getProperty("ChampionSpdAtk", "1.")); + CHAMPION_MEDAL = Integer.parseInt(altSettings.getProperty("ChampionMedal", "0")); IS_CRAFTING_ENABLED = Boolean.parseBoolean(altSettings.getProperty("CraftingEnabled", "true")); SP_BOOK_NEEDED = Boolean.parseBoolean(altSettings.getProperty("SpBookNeeded", "true")); AUTO_LOOT = altSettings.getProperty("AutoLoot").equalsIgnoreCase("True"); @@ -1986,6 +2017,17 @@ else if (pName.equalsIgnoreCase("AltGameFreightPrice")) ALT_GAME_FREIGHT_PRICE = Integer.parseInt(pValue); else if (pName.equalsIgnoreCase("AltGameSkillHitRate")) ALT_GAME_SKILL_HIT_RATE = Float.parseFloat(pValue); + + else if (pName.equalsIgnoreCase("ChampionFrequency")) CHAMPION_FREQUENCY = Integer.parseInt(pValue); + else if (pName.equalsIgnoreCase("ChampionMinLevel")) CHAMP_MIN_LVL = Integer.parseInt(pValue); + else if (pName.equalsIgnoreCase("ChampionMaxLevel")) CHAMP_MAX_LVL = Integer.parseInt(pValue); + else if (pName.equalsIgnoreCase("ChampionHp")) CHAMPION_HP = Integer.parseInt(pValue); + else if (pName.equalsIgnoreCase("ChampionHpRegen")) CHAMPION_HP_REGEN = Float.parseFloat(pValue); + else if (pName.equalsIgnoreCase("ChampionRewards")) CHAMPION_REWARDS = Integer.parseInt(pValue); + else if (pName.equalsIgnoreCase("ChampionAdenasRewards")) CHAMPION_ADENAS_REWARDS = Integer.parseInt(pValue); + else if (pName.equalsIgnoreCase("ChampionAtk")) CHAMPION_ATK = Float.parseFloat(pValue); + else if (pName.equalsIgnoreCase("ChampionSpdAtk")) CHAMPION_SPD_ATK = Float.parseFloat(pValue); + else if (pName.equalsIgnoreCase("ChampionMedal")) CHAMPION_MEDAL = Integer.parseInt(pValue); else if (pName.equalsIgnoreCase("CraftingEnabled")) IS_CRAFTING_ENABLED = Boolean.valueOf(pValue); else if (pName.equalsIgnoreCase("SpBookNeeded")) SP_BOOK_NEEDED = Boolean.valueOf(pValue); Index: net/sf/l2j/gameserver/handler/admincommandhandlers/AdminKill.java =================================================================== --- net/sf/l2j/gameserver/handler/admincommandhandlers/AdminKill.java (revision 703) +++ net/sf/l2j/gameserver/handler/admincommandhandlers/AdminKill.java (working copy) @@ -140,7 +140,10 @@ if (target instanceof L2PcInstance) target.reduceCurrentHp(target.getMaxHp() + target.getMaxCp() + 1, activeChar); else - target.reduceCurrentHp(target.getMaxHp() + 1, activeChar); + { + if (target.isChampion()) target.reduceCurrentHp(target.getMaxHp()*Config.CHAMPION_HP + 1, activeChar); + else target.reduceCurrentHp(target.getMaxHp() + 1, activeChar); + } if (Config.DEBUG) _log.fine("GM: "+activeChar.getName()+"("+activeChar.getObjectId()+")"+ Index: net/sf/l2j/gameserver/model/actor/stat/CharStat.java =================================================================== --- net/sf/l2j/gameserver/model/actor/stat/CharStat.java (revision 703) +++ net/sf/l2j/gameserver/model/actor/stat/CharStat.java (working copy) @@ -264,8 +264,11 @@ if (_ActiveChar == null) return 1; + float bonusAtk = 1; + if (_ActiveChar.isChampion()) bonusAtk = Config.CHAMPION_ATK; + // Get the base MAtk of the L2Character - double attack = _ActiveChar.getTemplate().baseMAtk; + double attack = _ActiveChar.getTemplate().baseMAtk * bonusAtk; // Get the skill type to calculate its effect in function of base stats // of the L2Character target @@ -337,7 +340,10 @@ if (_ActiveChar == null) return 1; - double val = calcStat(Stats.MAGIC_ATTACK_SPEED, _ActiveChar.getTemplate().baseMAtkSpd, null, null); + float bonusSpdAtk = 1; + if (_ActiveChar.isChampion()) bonusSpdAtk = Config.CHAMPION_SPD_ATK; + + double val = calcStat(Stats.MAGIC_ATTACK_SPEED, _ActiveChar.getTemplate().baseMAtkSpd * bonusSpdAtk, null, null); val /= _ActiveChar.getArmourExpertisePenalty(); return (int) val; } @@ -506,7 +512,10 @@ if (_ActiveChar == null) return 1; - return (int) calcStat(Stats.POWER_ATTACK, _ActiveChar.getTemplate().basePAtk, target, null); + float bonusAtk = 1; + if (_ActiveChar.isChampion()) bonusAtk = Config.CHAMPION_ATK; + + return (int) calcStat(Stats.POWER_ATTACK, _ActiveChar.getTemplate().basePAtk * bonusAtk, target, null); } /** Return the PAtk Modifier against animals. */ @@ -548,7 +557,10 @@ if (_ActiveChar == null) return 1; - return (int) (calcStat(Stats.POWER_ATTACK_SPEED, _ActiveChar.getTemplate().basePAtkSpd, null, null) / _ActiveChar.getArmourExpertisePenalty()); + float bonusSpdAtk = 1; + if (_ActiveChar.isChampion()) bonusSpdAtk = Config.CHAMPION_SPD_ATK; + + return (int) (calcStat(Stats.POWER_ATTACK_SPEED, _ActiveChar.getTemplate().basePAtkSpd * bonusSpdAtk, null, null) / _ActiveChar.getArmourExpertisePenalty()); } /** Return the PAtk Modifier against undead. */ Index: net/sf/l2j/gameserver/model/L2Attackable.java =================================================================== --- net/sf/l2j/gameserver/model/L2Attackable.java (revision 703) +++ net/sf/l2j/gameserver/model/L2Attackable.java (working copy) @@ -438,6 +438,19 @@ } } catch (Exception e) { _log.log(Level.SEVERE, "", e); } + + // --- CHAMPIONS -- + //Set champion on next spawn + setChampion(false); + if (this instanceof L2MonsterInstance && Config.CHAMPION_FREQUENCY > 0 && + (String.valueOf(getTemplate().type).contentEquals("L2Monster") && // many classes extend l2monsterinstance... + (getLevel()>=Config.CHAMP_MIN_LVL && getLevel()<=Config.CHAMP_MAX_LVL))) + { + int random = Rnd.get(100); + if (random < Config.CHAMPION_FREQUENCY) + setChampion(true); + } + // --- CHAMPIONS -- // Kill the L2NpcInstance (the corpse disappeared after 7 seconds) super.doDie(killer); @@ -570,6 +583,14 @@ exp *= 1 - penalty; sp = tmp[1]; + // --- CHAMPIONS -- + if (isChampion()) + { + exp *= Config.CHAMPION_REWARDS; + sp *= Config.CHAMPION_REWARDS; + } + // --- CHAMPIONS -- + // Check for an over-hit enabled strike if (attacker instanceof L2PcInstance) { @@ -632,6 +653,14 @@ exp = tmp[0]; sp = tmp[1]; + // --- CHAMPIONS -- + if (isChampion()) + { + exp *= Config.CHAMPION_REWARDS; + sp *= Config.CHAMPION_REWARDS; + } + // --- CHAMPIONS -- + exp *= partyMul; sp *= partyMul; @@ -906,6 +935,7 @@ if (drop.getItemId() == 57) dropChance *= Config.RATE_DROP_ADENA; else if (isSweep) dropChance *= Config.RATE_DROP_SPOIL; else dropChance *= Config.RATE_DROP_ITEMS; + if (isChampion()) dropChance *= Config.CHAMPION_REWARDS; // Round drop chance dropChance = Math.round(dropChance); @@ -942,6 +972,8 @@ // Prepare for next iteration if dropChance > L2DropData.MAX_CHANCE dropChance -= L2DropData.MAX_CHANCE; } + + if ((drop.getItemId() == 57 || (drop.getItemId() >= 6360 && drop.getItemId() <= 6362)) && isChampion()) itemCount *= Config.CHAMPION_ADENAS_REWARDS; if (itemCount > 0) return new RewardItem(drop.getItemId(), itemCount); else if (itemCount == 0 && Config.DEBUG) _log.fine("Roll produced 0 items to drop..."); @@ -987,6 +1019,7 @@ // Applies Drop rates categoryDropChance *= Config.RATE_DROP_ITEMS; + if (isChampion()) categoryDropChance *= Config.CHAMPION_REWARDS; // Round drop chance categoryDropChance = Math.round(categoryDropChance); @@ -1016,6 +1049,7 @@ int dropChance = drop.getChance(); if (drop.getItemId() == 57) dropChance *= Config.RATE_DROP_ADENA; else dropChance *= Config.RATE_DROP_ITEMS; + if (isChampion()) dropChance *= Config.CHAMPION_REWARDS; dropChance = Math.round(dropChance); @@ -1054,6 +1088,8 @@ dropChance -= L2DropData.MAX_CHANCE; } + if ((drop.getItemId() == 57 || (drop.getItemId() >= 6360 && drop.getItemId() <= 6362)) && isChampion()) itemCount *= Config.CHAMPION_ADENAS_REWARDS; + if (itemCount > 0) return new RewardItem(drop.getItemId(), itemCount); else if (itemCount == 0 && Config.DEBUG) _log.fine("Roll produced 0 items to drop..."); @@ -1227,6 +1263,12 @@ } } } + + // Glittering medals for champions + if (isChampion() && (player.getLevel() <= getLevel()) && (Rnd.get(100) < Config.CHAMPION_MEDAL)) { + RewardItem item = new RewardItem(6393, 1); + player.addItem("ChampionLoot", item.getItemId(), item.getCount(), this, true); + } //Instant Item Drop :> double rateHp = getStat().calcStat(Stats.MAX_HP , 1, this, null); Index: net/sf/l2j/gameserver/model/L2Character.java =================================================================== --- net/sf/l2j/gameserver/model/L2Character.java (revision 703) +++ net/sf/l2j/gameserver/model/L2Character.java (working copy) @@ -153,6 +153,7 @@ private double _hpUpdateIncCheck = .0; private double _hpUpdateDecCheck = .0; private double _hpUpdateInterval = .0; + private boolean _champion = false; /** Table of Calculators containing all used calculator */ private Calculator[] _Calculators; @@ -5315,7 +5316,11 @@ // Method - Public public void addStatusListener(L2Character object) { getStatus().addStatusListener(object); } public void reduceCurrentHp(double i, L2Character attacker) { reduceCurrentHp(i, attacker, true); } - public void reduceCurrentHp(double i, L2Character attacker, boolean awake) { getStatus().reduceHp(i, attacker, awake); } + public void reduceCurrentHp(double i, L2Character attacker, boolean awake) + { + if (isChampion() && Config.CHAMPION_HP != 0) getStatus().reduceHp(i/Config.CHAMPION_HP, attacker, awake); + else getStatus().reduceHp(i, attacker, awake); + } public void reduceCurrentMp(double i) { getStatus().reduceMp(i); } public void removeStatusListener(L2Character object) { getStatus().removeStatusListener(object); } protected synchronized void stopHpMpRegeneration() { getStatus().stopHpMpRegeneration(); } @@ -5374,6 +5379,18 @@ return false; } + + // --- CHAMPIONS -- + public void setChampion(boolean champ) + { + _champion = champ; + } + + public boolean isChampion() + { + return _champion; + } + // --- CHAMPIONS -- } Index: net/sf/l2j/gameserver/serverpackets/NpcInfo.java =================================================================== --- net/sf/l2j/gameserver/serverpackets/NpcInfo.java (revision 703) +++ net/sf/l2j/gameserver/serverpackets/NpcInfo.java (working copy) @@ -63,7 +63,9 @@ if (cha.getTemplate().serverSideName) _name = cha.getTemplate().name; - if (cha.getTemplate().serverSideTitle) + if (cha.isChampion()) + _title = ("Champion"); + else if (cha.getTemplate().serverSideTitle) _title = cha.getTemplate().title; else _title = cha.getTitle(); Index: net/sf/l2j/gameserver/skills/Formulas.java =================================================================== --- net/sf/l2j/gameserver/skills/Formulas.java (revision 703) +++ net/sf/l2j/gameserver/skills/Formulas.java (working copy) @@ -829,6 +829,8 @@ double init = cha.getTemplate().baseHpReg; double hpRegenMultiplier = cha.isRaid() ? Config.RAID_HP_REGEN_MULTIPLIER : Config.HP_REGEN_MULTIPLIER; double hpRegenBonus = 0; + + if (cha.isChampion()) hpRegenMultiplier *= Config.CHAMPION_HP_REGEN; if (cha instanceof L2PcInstance) {