All pastes #39592 Raw Edit

Anonymous

public text v1 · immutable
#39592 ·published 2006-02-02 10:54 UTC
rendered paste body
/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 *
 * http://www.gnu.org/copyleft/gpl.html
 */
package net.sf.l2j.gameserver.skills;

import java.util.Random;
import java.util.logging.Logger;

import net.sf.l2j.Config;
import net.sf.l2j.gameserver.instancemanager.SiegeManager;
import net.sf.l2j.gameserver.SevenSigns;
import net.sf.l2j.gameserver.SevenSignsFestival;
import net.sf.l2j.gameserver.SkillTable;
import net.sf.l2j.gameserver.model.entity.Siege;
import net.sf.l2j.gameserver.model.L2Character;
import net.sf.l2j.gameserver.model.L2DoorInstance;
import net.sf.l2j.gameserver.model.L2NpcInstance;
import net.sf.l2j.gameserver.model.L2PcInstance;
import net.sf.l2j.gameserver.model.L2PlayableInstance;  
import net.sf.l2j.gameserver.model.L2RaidBossInstance;  
import net.sf.l2j.gameserver.model.L2SiegeClan;
import net.sf.l2j.gameserver.model.L2SiegeGuardInstance;
import net.sf.l2j.gameserver.model.L2Skill;
import net.sf.l2j.gameserver.model.L2Summon;
import net.sf.l2j.gameserver.model.L2Skill.SkillType;
import net.sf.l2j.gameserver.skills.ConditionPlayerState.CheckPlayerState;
import net.sf.l2j.gameserver.templates.L2PcTemplate;
import net.sf.l2j.gameserver.templates.L2Armor;
import net.sf.l2j.gameserver.templates.L2Weapon;
import net.sf.l2j.gameserver.templates.L2WeaponType;
import net.sf.l2j.gameserver.util.Util;

/**
 * Global calculations, can be modified by server admins
 */
public final class Formulas {

	/** Regen Task period */
    protected static final Logger _log = Logger.getLogger(L2Character.class.getName());
	private static final int HP_REGENERATE_PERIOD = 3000; // 3 secs

	private static final double[] WITpolynomRuben = new double[]{
		+9.9254810689570600E-11,
		-1.7432156601963700E-08,
		+1.6283114716481700E-06,
		-5.6970835467547200E-05,
		+1.7629733457427100E-03,
		+7.0204771689824400E-03,
		-5.9581455760650400E-01 + 1
	};
	private static final double[] MENpolynomRuben = new double[]{
		+6.5556050620594200E-13,
		-1.8638224683763800E-10,
		+2.0018163622572800E-08,
		-7.2108375368351700E-07,
		+6.3289304637999400E-05,
		+1.0029266341299700E-02,
		-1.0175136814796200E-03 + 1
	};
	private static final double[] INTpolynomRuben = new double[]{
		+1.1470901531361600E-12,
		-2.9553917011707800E-10,
		+3.7089973347674800E-08,
		-1.0695713178072000E-06,
		+1.5208868021921400E-04,
		+1.0050328784329600E-02,
		-4.6076900720778700E-01 + 1
	};
	private static final double[] STRpolynomRuben = new double[]{
		+1.1613512208115100E-13,
		-4.6270526432167100E-11,
		+1.1658934786851800E-08,
		-4.6101001831828200E-07,
		+1.1686709259968900E-04,
		+9.4339883191995000E-03,
		-2.9003757344207000E-01 + 1
	};
	private static final double[] DEXpolynomRuben = new double[]{
		-2.1880234745612400E-13,
		+7.3632610232465600E-11,
		-9.1763881163096500E-09,
		+6.4297949462682400E-07,
		+2.1977057725307600E-05,
		+7.5308782907148200E-03,
		-1.5829464582577600E-01 + 1
	};
	private static final double[] CONpolynomRuben = new double[]{
		-1.7186080812322300E-14,
		+2.4793116095651400E-11,
		-8.6283668624209900E-10,
		+5.6169661837635300E-07,
		+9.1066481005104500E-05,
		+1.2367571569199400E-02,
		-1.6963187489087200E-01 + 1
	};
    
    public static int MAX_STAT_VALUE = 100;
    
    protected static final double[] WITbonus = new double[MAX_STAT_VALUE];
    protected static final double[] MENbonus = new double[MAX_STAT_VALUE];
    protected static final double[] INTbonus = new double[MAX_STAT_VALUE];
    protected static final double[] STRbonus = new double[MAX_STAT_VALUE];
    protected static final double[] DEXbonus = new double[MAX_STAT_VALUE];
    protected static final double[] CONbonus = new double[MAX_STAT_VALUE];

	private static double polynom(double[] p, int idx) {
		double val = 0;
		for (int i=0; i < p.length; i++) {
			val *= idx;
			val += p[i];
		}
		return val;
	}

	static {
		for (int i=0; i < WITbonus.length; i++)
			WITbonus[i] = polynom(WITpolynomRuben, i);
		for (int i=0; i < MENbonus.length; i++)
			MENbonus[i] = polynom(MENpolynomRuben, i);
		for (int i=0; i < INTbonus.length; i++)
			INTbonus[i] = polynom(INTpolynomRuben, i);
		for (int i=0; i < STRbonus.length; i++)
			STRbonus[i] = polynom(STRpolynomRuben, i);
		for (int i=0; i < DEXbonus.length; i++)
			DEXbonus[i] = polynom(DEXpolynomRuben, i);
		for (int i=0; i < CONbonus.length; i++)
			CONbonus[i] = polynom(CONpolynomRuben, i);
	}

	static class FuncAddLevel3 extends Func
	{
		static final FuncAddLevel3[] _instancies = new FuncAddLevel3[Stats.NUM_STATS];
		static Func getInstance(Stats stat) {
			int pos = stat.ordinal();
			if (_instancies[pos] == null)
				_instancies[pos] = new FuncAddLevel3(stat);
			return _instancies[pos];
		}
		private FuncAddLevel3(Stats stat)
		{
			super(stat, 0x10, null);
		}
		public void calc(Env env)
		{
			env.value += env._player.getLevel()/3;
		}
	}

	static class FuncMultLevelMod extends Func
	{
		static final FuncMultLevelMod[] _instancies = new FuncMultLevelMod[Stats.NUM_STATS];
		static Func getInstance(Stats stat) {
			int pos = stat.ordinal();
			if (_instancies[pos] == null)
				_instancies[pos] = new FuncMultLevelMod(stat);
			return _instancies[pos];
		}
		private FuncMultLevelMod(Stats stat)
		{
			super(stat, 0x30, null);
		}
		public void calc(Env env)
		{
				env.value *= env._player.getLevelMod();
			}
		}

	static class FuncMAtkMod extends Func
	{
		static final FuncMAtkMod _fma_instance = new FuncMAtkMod();
		static Func getInstance() {
			return _fma_instance;
		}
		private FuncMAtkMod()
		{
			super(Stats.MAGIC_ATTACK, 0x30, null);
		}
		public void calc(Env env)
		{
			//{Wpn*(lvlbn^2)*[(1+INTbn)^2]+Msty}
			L2PcInstance p = (L2PcInstance)env._player;
			double ib = INTbonus[p.getINT()];
			double lvlb = env._player.getLevelMod();
			env.value *= (lvlb * lvlb) * (ib * ib) * 1.17;
		}
	}

	static class FuncMultRegenResting extends Func
	{
		static final FuncMultRegenResting[] _instancies = new FuncMultRegenResting[Stats.NUM_STATS];


		/**
		 * Return the Func object corresponding to the state concerned.<BR><BR>
		 */
		static Func getInstance(Stats stat)
		{
			int pos = stat.ordinal();

			if (_instancies[pos] == null)
				_instancies[pos] = new FuncMultRegenResting(stat);

			return _instancies[pos];
		}

		/**
		 * Constructor of the FuncMultRegenResting.<BR><BR>
		 */
		private FuncMultRegenResting(Stats stat)
		{
			super(stat, 0x20, null);
			setCondition(new ConditionPlayerState(CheckPlayerState.RESTING, true));
		}

		/**
		 * Calculate the modifier of the state concerned.<BR><BR>
		 */
		public void calc(Env env)
		{
			if (!_cond.test(env))
				return;

			env.value *= 1.45;
		}
	}

	static class FuncPAtkMod extends Func
	{
		static final FuncPAtkMod _fpa_instance = new FuncPAtkMod();
		static Func getInstance() {
			return _fpa_instance;
		}
		private FuncPAtkMod()
		{
			super(Stats.POWER_ATTACK, 0x30, null);
		}
		public void calc(Env env)
		{
			L2PcInstance p = (L2PcInstance)env._player;
			env.value *= STRbonus[p.getSTR()]*STRbonus[p.getSTR()]/1.25;
			double lvlMod = env._player.getLevelMod();
			//0 added at lvl 1, ~75 added at lvl 75
			env.value += (STRbonus[p.getSTR()]*2)*40*(lvlMod-9.0/10.0);
		}
	}

	static class FuncMDefMod extends Func
	{
		static final FuncMDefMod _fmm_instance = new FuncMDefMod();
		static Func getInstance() {
			return _fmm_instance;
		}
		private FuncMDefMod()
		{
			super(Stats.MAGIC_DEFENCE, 0x20, null);
		}
		public void calc(Env env)
		{
			L2PcInstance p = (L2PcInstance)env._player;
			env.value *= MENbonus[p.getMEN()];
		}
	}

	static class FuncBowAtkRange extends Func
	{
		private static final FuncBowAtkRange _fbar_instance = new FuncBowAtkRange();
		static Func getInstance() {
			return _fbar_instance;
		}
		private FuncBowAtkRange()
		{
			super(Stats.POWER_ATTACK_RANGE, 0x10, null);
			setCondition(new ConditionUsingItemType(L2WeaponType.BOW.mask()));
		}
		public void calc(Env env)
		{
			if (!_cond.test(env))
				return;
			env.value += 450;
		}
	}

	static class FuncAtkAccuracy extends Func
	{
		static final FuncAtkAccuracy _faa_instance = new FuncAtkAccuracy();

		static Func getInstance() {
			return _faa_instance;
		}

		private FuncAtkAccuracy()
		{
			super(Stats.ACCURACY_COMBAT, 0x10, null);
		}

		public void calc(Env env)
		{
			L2Character p = env._player;
			//[Square(DEX)]*6 + lvl + weapon hitbonus;
			env.value += Math.sqrt(p.getDEX())*6;
			env.value += p.getLevel();
		}
	}

	static class FuncAtkEvasion extends Func
	{
		static final FuncAtkEvasion _fae_instance = new FuncAtkEvasion();

		static Func getInstance() {
			return _fae_instance;
		}

		private FuncAtkEvasion()
		{
			super(Stats.EVASION_RATE, 0x10, null);
		}

		public void calc(Env env)
		{
			L2Character p = env._player;
			//[Square(DEX)]*6 + lvl;
			env.value += Math.sqrt(p.getDEX())*6;
			env.value += p.getLevel();
		}
	}

	static class FuncAtkCritical extends Func
	{
		static final FuncAtkCritical _fac_instance = new FuncAtkCritical();
		static Func getInstance() {
			return _fac_instance;
		}
		private FuncAtkCritical()
		{
			super(Stats.CRITICAL_RATE, 0x30, null);
		}
		public void calc(Env env)
		{
			L2Character p = env._player;
			env.value *= DEXbonus[p.getDEX()];
			env.value *= 10;
		}
	}

	static class FuncMoveSpeed extends Func
	{
		static final FuncMoveSpeed _fms_instance = new FuncMoveSpeed();
		static Func getInstance() {
			return _fms_instance;
		}
		private FuncMoveSpeed()
		{
			super(Stats.RUN_SPEED, 0x30, null);
		}
		public void calc(Env env)
		{
			L2PcInstance p = (L2PcInstance)env._player;
			env.value *= DEXbonus[p.getDEX()];
		}
	}

	static class FuncPAtkSpeed extends Func
	{
		static final FuncPAtkSpeed _fas_instance = new FuncPAtkSpeed();
		static Func getInstance() {
			return _fas_instance;
		}
		private FuncPAtkSpeed()
		{
			super(Stats.POWER_ATTACK_SPEED, 0x20, null);
		}
		public void calc(Env env)
		{
			L2PcInstance p = (L2PcInstance)env._player;
			env.value *= DEXbonus[p.getDEX()];
		}
	}

	static class FuncMAtkSpeed extends Func
	{
		static final FuncMAtkSpeed _fas_instance = new FuncMAtkSpeed();
		static Func getInstance() {
			return _fas_instance;
		}
		private FuncMAtkSpeed()
		{
			super(Stats.MAGIC_ATTACK_SPEED, 0x20, null);
		}
		public void calc(Env env)
		{
			L2PcInstance p = (L2PcInstance)env._player;
			env.value *= WITbonus[p.getWIT()];
		}
	}


	static class FuncHennaSTR extends Func
	{
		static final FuncHennaSTR _fh_instance = new FuncHennaSTR();
		static Func getInstance() {
			return _fh_instance;
		}
		private FuncHennaSTR()
		{
			super(Stats.STAT_STR, 0x10, null);
		}
		public void calc(Env env)
		{
//			L2PcTemplate t = (L2PcTemplate)env._player.getTemplate();
			L2PcInstance pc = (L2PcInstance)env._player;
			if (pc!=null)
				env.value += pc.getHennaStatSTR();
		}
	}
	static class FuncHennaDEX extends Func
	{
		static final FuncHennaDEX _fh_instance = new FuncHennaDEX();
		static Func getInstance() {
			return _fh_instance;
		}
		private FuncHennaDEX()
		{
			super(Stats.STAT_DEX, 0x10, null);
		}
		public void calc(Env env)
		{
//			L2PcTemplate t = (L2PcTemplate)env._player.getTemplate();
			L2PcInstance pc = (L2PcInstance)env._player;
			if (pc!=null)
				env.value += pc.getHennaStatDEX();
		}
	}
	static class FuncHennaINT extends Func
	{
		static final FuncHennaINT _fh_instance = new FuncHennaINT();
		static Func getInstance() {
			return _fh_instance;
		}
		private FuncHennaINT()
		{
			super(Stats.STAT_INT, 0x10, null);
		}
		public void calc(Env env)
		{
//			L2PcTemplate t = (L2PcTemplate)env._player.getTemplate();
			L2PcInstance pc = (L2PcInstance)env._player;
			if (pc!=null)
				env.value += pc.getHennaStatINT();
		}
	}
	static class FuncHennaMEN extends Func
	{
		static final FuncHennaMEN _fh_instance = new FuncHennaMEN();
		static Func getInstance() {
			return _fh_instance;
		}
		private FuncHennaMEN()
		{
			super(Stats.STAT_MEN, 0x10, null);
		}
		public void calc(Env env)
		{
//			L2PcTemplate t = (L2PcTemplate)env._player.getTemplate();
			L2PcInstance pc = (L2PcInstance)env._player;
			if (pc!=null)
				env.value += pc.getHennaStatMEN();
		}
	}
	static class FuncHennaCON extends Func
	{
		static final FuncHennaCON _fh_instance = new FuncHennaCON();
		static Func getInstance() {
			return _fh_instance;
		}
		private FuncHennaCON()
		{
			super(Stats.STAT_CON, 0x10, null);
		}
		public void calc(Env env)
		{
//			L2PcTemplate t = (L2PcTemplate)env._player.getTemplate();
			L2PcInstance pc = (L2PcInstance)env._player;
			if (pc!=null)
				env.value += pc.getHennaStatCON();
		}
	}
	static class FuncHennaWIT extends Func
	{
		static final FuncHennaWIT _fh_instance = new FuncHennaWIT();
		static Func getInstance() {
			return _fh_instance;
		}
		private FuncHennaWIT()
		{
			super(Stats.STAT_WIT, 0x10, null);
		}
		public void calc(Env env)
		{
//			L2PcTemplate t = (L2PcTemplate)env._player.getTemplate();
			L2PcInstance pc = (L2PcInstance)env._player;
			if (pc!=null)
				env.value += pc.getHennaStatWIT();
		}
	}

	static class FuncMaxHpAdd extends Func
	{
		static final FuncMaxHpAdd _fmha_instance = new FuncMaxHpAdd();
		static Func getInstance() {
			return _fmha_instance;
		}
		private FuncMaxHpAdd()
		{
			super(Stats.MAX_HP, 0x10, null);
		}
		public void calc(Env env)
		{
			L2PcTemplate t = (L2PcTemplate)env._player.getTemplate();
			int lvl = env._player.getLevel() - t.classBaseLevel;
			double hpmod = t.lvlHpMod * lvl;
			double hpmax = (t.lvlHpAdd + hpmod) * lvl;
			double hpmin = (t.lvlHpAdd * lvl) + hpmod;
			env.value += (hpmax + hpmin) / 2;
		}
	}
	static class FuncMaxHpMul extends Func
	{
		static final FuncMaxHpMul _fmhm_instance = new FuncMaxHpMul();
		static Func getInstance() {
			return _fmhm_instance;
		}
		private FuncMaxHpMul()
		{
			super(Stats.MAX_HP, 0x20, null);
		}
		public void calc(Env env)
		{
			L2PcInstance p = (L2PcInstance)env._player;
			env.value *= CONbonus[p.getCON()];
		}
	}
    static class FuncMaxCpAdd extends Func
    {
        static final FuncMaxCpAdd _fmca_instance = new FuncMaxCpAdd();
        static Func getInstance() {
            return _fmca_instance;
        }
        private FuncMaxCpAdd()
        {
            super(Stats.MAX_CP, 0x10, null);
        }
        public void calc(Env env)
        {
            L2PcTemplate t = (L2PcTemplate)env._player.getTemplate();
            int lvl = env._player.getLevel() - t.classBaseLevel;
            double cpmod = t.lvlCpMod * lvl;
            double cpmax = (t.lvlCpAdd + cpmod) * lvl;
            double cpmin = (t.lvlCpAdd * lvl) + cpmod;
            env.value += (cpmax + cpmin) / 2;
        }
    }
    static class FuncMaxCpMul extends Func
    {
        static final FuncMaxCpMul _fmcm_instance = new FuncMaxCpMul();
        static Func getInstance() {
            return _fmcm_instance;
        }
        private FuncMaxCpMul()
        {
            super(Stats.MAX_CP, 0x20, null);
        }
        public void calc(Env env)
        {
            L2PcInstance p = (L2PcInstance)env._player;
            env.value *= CONbonus[p.getCON()];
        }
    }
	static class FuncMaxMpAdd extends Func
	{
		static final FuncMaxMpAdd _fmma_instance = new FuncMaxMpAdd();
		static Func getInstance() {
			return _fmma_instance;
		}
		private FuncMaxMpAdd()
		{
			super(Stats.MAX_MP, 0x10, null);
		}
		public void calc(Env env)
		{
			L2PcTemplate t = (L2PcTemplate)env._player.getTemplate();
			int lvl = env._player.getLevel() - t.classBaseLevel;
			double mpmod = t.lvlMpMod * lvl;
			double mpmax = (t.lvlMpAdd + mpmod) * lvl;
			double mpmin = (t.lvlMpAdd * lvl) + mpmod;
			env.value += (mpmax + mpmin) / 2;
		}
	}
	static class FuncMaxMpMul extends Func
	{
		static final FuncMaxMpMul _fmmm_instance = new FuncMaxMpMul();
		static Func getInstance() {
			return _fmmm_instance;
		}
		private FuncMaxMpMul()
		{
			super(Stats.MAX_MP, 0x20, null);
		}
		public void calc(Env env)
		{
			L2PcInstance p = (L2PcInstance)env._player;
			env.value *= MENbonus[p.getMEN()];
		}
	}

	private static final Formulas _instance = new Formulas();

	private static final Random _rnd = new Random();

	public static Formulas getInstance()
	{
		return _instance;
	}

	private Formulas() {}


	/**
	 * Return the period between 2 regenerations task (3s for L2Character, 5 min for L2DoorInstance).<BR><BR>
	 */
	public int getRegeneratePeriod(L2Character cha)
	{
		if (cha instanceof L2DoorInstance)
			return HP_REGENERATE_PERIOD * 100; // 5 mins

		return HP_REGENERATE_PERIOD; // 3s
	}


	/**
	 * Return the standard NPC Calculator set containing ACCURACY_COMBAT and EVASION_RATE.<BR><BR>
	 *
	 * <B><U> Concept</U> :</B><BR><BR>
	 * A calculator is created to manage and dynamically calculate the effect of a character property (ex : MAX_HP, REGENERATE_HP_RATE...).
     * In fact, each calculator is a table of Func object in which each Func represents a mathematic function : <BR><BR>
	 *
	 * FuncAtkAccuracy -> Math.sqrt(_player.getDEX())*6+_player.getLevel()<BR><BR>
	 *
	 * To reduce cache memory use, L2NPCInstances who don't have skills share the same Calculator set called <B>NPC_STD_CALCULATOR</B>.<BR><BR>
	 *
	 */
	public Calculator[] getStdNPCCalculators()
	{
		Calculator[] std = new Calculator[Stats.NUM_STATS];

	    // Add the FuncAtkAccuracy to the Standard Calculator of ACCURACY_COMBAT
		std[Stats.ACCURACY_COMBAT.ordinal()] = new Calculator();
		std[Stats.ACCURACY_COMBAT.ordinal()].addFunc(FuncAtkAccuracy.getInstance());

	    // Add the FuncAtkEvasion to the Standard Calculator of EVASION_RATE
		std[Stats.EVASION_RATE.ordinal()] = new Calculator();
		std[Stats.EVASION_RATE.ordinal()].addFunc(FuncAtkEvasion.getInstance());

		return std;
	}


	/**
	 * Add basics Func objects to L2PcInstance and L2Summon.<BR><BR>
	 *
	 * <B><U> Concept</U> :</B><BR><BR>
	 * A calculator is created to manage and dynamically calculate the effect of a character property (ex : MAX_HP, REGENERATE_HP_RATE...).
     * In fact, each calculator is a table of Func object in which each Func represents a mathematic function : <BR><BR>
	 *
	 * FuncAtkAccuracy -> Math.sqrt(_player.getDEX())*6+_player.getLevel()<BR><BR>
	 *
	 * @param cha L2PcInstance or L2Summon that must obtain basic Func objects
	 */
	public void addFuncsToNewCharacter(L2Character cha)
	{
		if (cha instanceof L2PcInstance)
		{
			cha.addStatFunc(FuncMaxHpAdd.getInstance());
			cha.addStatFunc(FuncMaxHpMul.getInstance());
            cha.addStatFunc(FuncMaxCpAdd.getInstance());
            cha.addStatFunc(FuncMaxCpMul.getInstance());
			cha.addStatFunc(FuncMaxMpAdd.getInstance());
			cha.addStatFunc(FuncMaxMpMul.getInstance());
			cha.addStatFunc(FuncMultRegenResting.getInstance(Stats.REGENERATE_HP_RATE));
            cha.addStatFunc(FuncMultRegenResting.getInstance(Stats.REGENERATE_CP_RATE));
			cha.addStatFunc(FuncMultRegenResting.getInstance(Stats.REGENERATE_MP_RATE));
			cha.addStatFunc(FuncBowAtkRange.getInstance());
			cha.addStatFunc(FuncMultLevelMod.getInstance(Stats.POWER_ATTACK));
			cha.addStatFunc(FuncMultLevelMod.getInstance(Stats.POWER_DEFENCE));
			cha.addStatFunc(FuncMultLevelMod.getInstance(Stats.MAGIC_DEFENCE));
			cha.addStatFunc(FuncPAtkMod.getInstance());
			cha.addStatFunc(FuncMAtkMod.getInstance());
			cha.addStatFunc(FuncMDefMod.getInstance());
			cha.addStatFunc(FuncAtkCritical.getInstance());
			cha.addStatFunc(FuncAtkAccuracy.getInstance());
			cha.addStatFunc(FuncAtkEvasion.getInstance());
			cha.addStatFunc(FuncPAtkSpeed.getInstance());
			cha.addStatFunc(FuncMAtkSpeed.getInstance());
			cha.addStatFunc(FuncMoveSpeed.getInstance());

			cha.addStatFunc(FuncHennaSTR.getInstance());
			cha.addStatFunc(FuncHennaDEX.getInstance());
			cha.addStatFunc(FuncHennaINT.getInstance());
			cha.addStatFunc(FuncHennaMEN.getInstance());
			cha.addStatFunc(FuncHennaCON.getInstance());
			cha.addStatFunc(FuncHennaWIT.getInstance());
		}
		else if (cha instanceof L2Summon)
		{
			cha.addStatFunc(FuncMultRegenResting.getInstance(Stats.REGENERATE_HP_RATE));
			cha.addStatFunc(FuncMultRegenResting.getInstance(Stats.REGENERATE_MP_RATE));
			cha.addStatFunc(FuncAtkCritical.getInstance());
			cha.addStatFunc(FuncAtkAccuracy.getInstance());
			cha.addStatFunc(FuncAtkEvasion.getInstance());
		}

	}

	/**
	 * Calculate the HP regen rate (base + modifiers).<BR><BR>
	 */
	public final double calcHpRegen(L2Character cha)
	{
	    double hpRegenMultiplier = Config.HP_REGEN_MULTIPLIER;
        
        if (cha instanceof L2PcInstance)
        {
            L2PcInstance activeChar = (L2PcInstance)cha;
            
            if (SevenSignsFestival.getInstance().isFestivalInProgress() && activeChar.isFestivalParticipant()) 
                hpRegenMultiplier -= calcFestivalRegenModifier(activeChar);
            else
            {
               double siegeModifier = this.calcSiegeRegenModifer(activeChar);
               if (siegeModifier > 0) hpRegenMultiplier *= siegeModifier;
            }

            if (activeChar.isSitting()) 
                hpRegenMultiplier *= 2;
            else if (!activeChar.isRunning()) 
                hpRegenMultiplier *= 1.5;
            
        }
        else if (cha.isRaid())
            hpRegenMultiplier *= Config.RAID_HP_REGEN_MULTIPLIER;
        
		//double init = cha.getMaxHp()*cha.getTemplate().baseHpReg * (Config.HP_REGEN_MULTIPLIER / 100);
        double init = ((0.1 * cha.getLevel() + cha.getTemplate().baseHpReg) * (1 + CONbonus[cha.getCON()])) * (hpRegenMultiplier / 100);

		return cha.calcStat(Stats.REGENERATE_HP_RATE, init, null, null);
	}

	/**
	 * Calculate the MP regen rate (base + modifiers).<BR><BR>
	 */
	public final double calcMpRegen(L2Character cha)
	{
        double mpRegenMultiplier = Config.MP_REGEN_MULTIPLIER;
        
        if (cha instanceof L2PcInstance)
        {
            L2PcInstance activeChar = (L2PcInstance)cha;
            
            if (SevenSignsFestival.getInstance().isFestivalInProgress() && activeChar.isFestivalParticipant()) 
                mpRegenMultiplier -= calcFestivalRegenModifier(activeChar);

            if (activeChar.isSitting()) 
                mpRegenMultiplier *= 2;
            
            if (!activeChar.isRunning()) 
                mpRegenMultiplier *= 1.5;
        }
        
		if (cha.isRaid()) mpRegenMultiplier *= Config.RAID_MP_REGEN_MULTIPLIER;
		//double init = cha.getMaxMp()*cha.getTemplate().baseMpReg * (Config.MP_REGEN_MULTIPLIER / 100);
        double init = ((0.03 * cha.getLevel() + cha.getTemplate().baseMpReg) * (1 + MENbonus[cha.getMEN()])) * (mpRegenMultiplier / 100);
		return cha.calcStat(Stats.REGENERATE_MP_RATE, init, null, null);
	}

	/**
	 * Calculate the CP regen rate (base + modifiers).<BR><BR>
	 */
	public final double calcCpRegen(L2Character cha)
	{
        //double init = cha.getMaxCp()*cha.getTemplate().baseCpReg * Config.CP_REGEN_MULTIPLIER / 100;
        double init = ((0.08 * cha.getLevel() + cha.getTemplate().baseCpReg) * (0.6 + CONbonus[cha.getCON()])) * (Config.CP_REGEN_MULTIPLIER / 100);
        return cha.calcStat(Stats.REGENERATE_CP_RATE, init, null, null);
	}
    
    public final double calcFestivalRegenModifier(L2PcInstance activeChar)
    {
        final int[] festivalInfo = SevenSignsFestival.getInstance().getFestivalForPlayer(activeChar);
        final int oracle = festivalInfo[0];
        final int festivalId = festivalInfo[1];
        int[] festivalCenter;
        
        // If the player isn't found in the festival, leave the regen rate as it is.
        if (festivalId < 0) 
            return 0;
        
        // Retrieve the X and Y coords for the center of the festival arena the player is in.
        if (oracle == SevenSigns.CABAL_DAWN)
            festivalCenter = SevenSignsFestival.festivalDawnPlayerSpawns[festivalId];                
        else
            festivalCenter = SevenSignsFestival.festivalDuskPlayerSpawns[festivalId];
        
        // Check the distance between the player and the player spawn point, in the center of the arena.
        double distToCenter = activeChar.getDistance(festivalCenter[0], festivalCenter[1]);
        
        if (Config.DEBUG)
            _log.info("Distance: " + distToCenter + ", RegenMulti: " + (distToCenter * 2.5) / 50);
        
        return (distToCenter * 2.5) / 50; // Maximum Decreased Regen of ~ -65%;
    }

    public final double calcSiegeRegenModifer(L2PcInstance activeChar)
    {
        if (activeChar == null || activeChar.getClan() == null) return 0;

        Siege siege = SiegeManager.getInstance().getSiege(activeChar.getPosition().getX(), activeChar.getPosition().getY());
        if (siege == null || !siege.getIsInProgress()) return 0;

        L2SiegeClan siegeClan = siege.getAttackerClan(activeChar.getClan().getClanId());
        if (siegeClan == null || siegeClan.getFlag().size() == 0 || !Util.checkIfInRange(200, activeChar, siegeClan.getFlag().get(0), true)) return 0;
        
        return 1.5; // If all is true, then modifer will be 50% more
    }
    
	/** Calculated damage caused by ATTACK of attacker on target,
	 * called separatly for each weapon, if dual-weapon is used.
	 *
	 * @param attacker player or NPC that makes ATTACK
	 * @param target player or NPC, target of ATTACK
	 * @param miss one of ATTACK_XXX constants
	 * @param crit if the ATTACK have critical success
	 * @param dual if dual weapon is used
	 * @param ss if weapon item was changes by soulshot
	 * @return damage points
	 */
    public final double calcPhysDam(L2Character attacker, L2Character target,
			L2Skill skill, boolean shld, boolean crit, boolean dual, boolean ss)
    {
    	double damage = attacker.getPAtk(target);
    	double defence = target.getPDef(attacker);
		// defence modifier depending of the attacker weapon
		L2Weapon weapon = attacker.getActiveWeaponItem();
		if (weapon !=null)
		{
			switch (weapon.getItemType())
			{
			case BOW:
				defence=target.calcStat(Stats.BOW_WPN_RES,defence,target,null);
				break;
			case BLUNT:
				defence=target.calcStat(Stats.BLUNT_WPN_RES,defence,target,null);
				break;
			case DAGGER:
				defence=target.calcStat(Stats.DAGGER_WPN_RES,defence,target,null);
				break;
			case DUAL:
				defence=target.calcStat(Stats.DUAL_WPN_RES,defence,target,null);
				break;
			case DUALFIST:
				defence=target.calcStat(Stats.DUALFIST_WPN_RES,defence,target,null);
				break;
			case ETC:
				defence=target.calcStat(Stats.ETC_WPN_RES,defence,target,null);
				break;
			case FIST:
				defence=target.calcStat(Stats.FIST_WPN_RES,defence,target,null);
				break;
			case POLE:
				defence=target.calcStat(Stats.POLE_WPN_RES,defence,target,null);
				break;
			case SWORD:
				defence=target.calcStat(Stats.SWORD_WPN_RES,defence,target,null);
				break;
			case BIGSWORD: //TODO: have a proper resitance for Big swords
				defence=target.calcStat(Stats.SWORD_WPN_RES,defence,target,null);
				break;
			}
		}
			if(dual)
				damage /= 1.5;		
			if (skill != null)
			    damage += skill.getPower();
			if (crit)
				damage += attacker.getCriticalDmg(target, damage);    		
			if (ss)
			{
			    if (skill != null)
			        damage *= 1.44;
			    else
					damage *= 2;
			}
		if (shld && !Config.ALT_GAME_SHIELD_BLOCKS) {
			defence += target.getShldDef();
		}
		if (attacker instanceof L2NpcInstance || attacker instanceof L2SiegeGuardInstance){
		    //damage = damage * attacker.getSTR() * attacker.getAccuracy() * 0.05 / defence;
		    damage = damage * attacker.getSTR()*  (attacker.getSTR() + attacker.getLevel()) * 0.025 / defence;
    		    damage += _rnd.nextDouble() * damage / 10 ;
		}
		else {
		    damage = damage * 70 / defence;
    		    damage += _rnd.nextDouble()* attacker.getRandomDamage(target);
		}
		if (shld && Config.ALT_GAME_SHIELD_BLOCKS) {
			damage -= target.getShldDef();
			if (damage < 0)
				damage = 0;
		}
        if (target instanceof L2PcInstance && weapon != null && weapon.getItemType() == L2WeaponType.DAGGER && skill != null)
        {
        		L2Armor armor = ((L2PcInstance)target).getActiveChestArmorItem();
            if (armor != null)
            {
                if(((L2PcInstance)target).isWearingHeavyArmor())
                    damage /=2.2;
                if(((L2PcInstance)target).isWearingLightArmor())
                    damage /=1.5;               
            }            
        }
        if (target instanceof L2RaidBossInstance)  
        {  
                int cLevel = attacker.getLevel();  
                int tLevel = target.getLevel();  
                int rDamage = 1;  
                if ( cLevel > tLevel )  
                {  
                        rDamage = cLevel - tLevel;  
                        if (rDamage > 9)  
                                damage /= rDamage;  
                        if  (damage < 1)  
                                damage = 1;  
                }  
        }  

        if (target instanceof L2PlayableInstance && attacker instanceof L2RaidBossInstance)  
        {  
                int cLevel = attacker.getLevel();  
                int tLevel = target.getLevel();  
                int rDamage = 1;  
                if ( cLevel < tLevel )  
                {  
                        rDamage = tLevel - cLevel;  
                        if (rDamage > 9)  
                                damage *= rDamage;  
                }  
        }  
        if (target instanceof L2NpcInstance)
        {
	    int raceId = ((L2NpcInstance)target).getTemplate().race;
            //Skill Race : Undead
            if (raceId == 4290)
        	damage *= attacker.getPAtkUndead(target);
            //Skill Race : Beast
            if (raceId == 4292)
        	damage *= attacker.getPAtkMonsters(target);
            //Skill Race : Animal
            if (raceId == 4293)
                damage *= attacker.getPAtkAnimals(target);
            //Skill Race : Plant
            if (raceId == 4294)
                damage *= attacker.getPAtkPlants(target);
            //Skill Race : Dragon
            if (raceId == 4299)
                damage *= attacker.getPAtkDragons(target);
            //Skill Race : Bug
            if (raceId == 4301)
                damage *= attacker.getPAtkInsects(target);
        }



        if  (damage > 0 && damage < 1)
        {
            damage  = 1;
        }
        else if (damage < 0)
        {
            damage  = 0;
        }

        if (target instanceof L2RaidBossInstance)  
        {  
                int cLevel = attacker.getLevel();  
                int tLevel = target.getLevel();  
                int rDamage = 1;  
                if ( cLevel > tLevel )  
                 {  
                        rDamage = cLevel - tLevel;  
                        if (rDamage > 9)  
                                damage /= rDamage;  
                        if  (damage < 1)  
                                damage = 1;  
                }  
        }  

        if (target instanceof L2PlayableInstance && attacker instanceof L2RaidBossInstance)  
        {  
                int cLevel = attacker.getLevel();  
                int tLevel = target.getLevel();  
                int rDamage = 1;  
                if ( cLevel < tLevel )  
                {  
                        rDamage = tLevel - cLevel;  
                        if (rDamage > 9)  
                                damage *= rDamage;  
                }  
        }  
		return damage;
    }

	public final double calcMagicDam(L2Character attacker, L2Character target,
			L2Skill skill, boolean ss, boolean bss, boolean mcrit)
	{
		double mAtk = attacker.getMAtk(target, skill);
		double mDef = target.getMDef(attacker, skill);
		if (bss)
			mAtk *= 4;
		else if (ss)
			mAtk *= 2;

		//double damage = Math.sqrt(mAtk/mDef)*skill.getPower()*10.18;
        //double damage = 91*Math.sqrt(mAtk)/mDef*skill.getPower(attacker);
        //double damage = 5*Math.sqrt(mAtk/mDef)*skill.getPower(attacker);
        double damage = 40/Math.pow(mAtk*mDef,1./6)*Math.sqrt(mAtk/mDef)*skill.getPower(attacker);
        if(attacker instanceof L2PcInstance && target instanceof L2PcInstance) damage *= 0.9; // PvP modifier (-10%)
		if(mcrit) damage *= 2;

        if (Config.ALT_GAME_MAGICFAILURES) // Failure calculation
        {
            /* Level difference: 
             *  less then 7 : full chance
             *  7 - 20      : reduced chance
             *  20 and more : min chance
             */
            int rate = (int)(200 - 10 * (target.getLevel() - skill.getMagicLevel()));

            if (target.isRaid()) rate /= 2; // chance is reduced for RaidBoss

            if (rate > 123) rate = 123;
            if (rate < 1) rate = 1;
            int check = _rnd.nextInt(100);
            if (rate <= check) damage = 1;
            else if (rate <= check +25) damage /= 2;
        }
         
		return damage;
	}

	/** Returns true in case of critical hit */
	public final boolean calcCrit(double rate)
	{
		int critHit = _rnd.nextInt(1000);
		return rate > critHit;
	}
	public final boolean calcMCrit(double mRate)
	{
		int mcritHit = _rnd.nextInt(1000);
		return mRate > mcritHit;
	}
	/** Returns true in case when ATTACK is canceled due to hit */
	public final boolean calcAtkBreak(L2Character cha, double cancel)
	{
		if (Config.ALT_GAME_CANCEL_CAST && cha.isCastingNow())
			return cancel > _rnd.nextInt(100);
		if (Config.ALT_GAME_CANCEL_BOW && cha.isAttackingNow()) {
			L2Weapon wpn = cha.getActiveWeaponItem();
			if (wpn != null && wpn.getItemType() == L2WeaponType.BOW)
				return cancel > _rnd.nextInt(100);
		}
		return false;
	}

	/** Calculate delay (in milliseconds) before next ATTACK */
	public final int calcPAtkSpd(@SuppressWarnings("unused") L2Character attacker, @SuppressWarnings("unused") L2Character target, double rate)
	{
		//will fix freeze at >1000 atkspd, optimum calcation between 0 to 1400
		return (int) (3*Math.pow(rate, 2)/2000 - 4*rate + 2700);
	}

	/** Calculate delay (in milliseconds) for skills cast */
	public final int calcMAtkSpd(L2Character attacker, @SuppressWarnings("unused") L2Character target, L2Skill skill, double skillTime)
	{
		if (skill.isMagic())
			return (int)(skillTime * 333 / attacker.getMAtkSpd());
        return (int)(skillTime * 333 / attacker.getPAtkSpd());
	}

	/** Returns true if hit missed (taget evaded) */
    public boolean calcHitMiss(L2Character attacker, L2Character target) {
		// accuracy+dexterity => probability to hit in percents
		int acc_attacker;
		int evas_target;
		acc_attacker = attacker.getAccuracy();
		evas_target = target.getEvasionRate(attacker);
		int d = 85 + acc_attacker - evas_target;
		return d < _rnd.nextInt(100);
	}

	/** Returns true if shield defence successfull */
    public boolean calcShldUse(L2Character attacker, L2Character target) {
		double shldRate = target.calcStat(Stats.SHIELD_RATE, 0, attacker, null);
		return shldRate > _rnd.nextInt(80);
    }

    public boolean calcMagicAffected(L2Character actor, L2Character target, L2Skill skill)
    {
    	double defence = 0;
    	if (skill.isActive() && skill.isOffensive())
    		defence = target.getMDef(actor, skill);
    	double attack = 2 * actor.getMAtk(target, skill);
    	double d = attack - defence;
    	d /= attack + defence;
		d += 0.5 * _rnd.nextGaussian();
		return d > 0;
    }

    public boolean calcSkillSuccessOld(L2Character player, L2Character target, L2Skill skill, boolean ss, boolean sps, boolean bss )
    {
        if(Config.ALT_GAME_SKILL_FORMULAS.equalsIgnoreCase("alt") ||
            Config.ALT_GAME_SKILL_FORMULAS.equalsIgnoreCase("true"))
            return calcAltSkillSuccess(player, target, skill);

        SkillType type = skill.getSkillType();

        int rate = 1;
        int check = _rnd.nextInt(100);

        if (target.isRaid() && (type == SkillType.CONFUSION || type == SkillType.MUTE || type == SkillType.PARALYZE || type == SkillType.ROOT)) 
            return (check < rate); // these skills should not work on RaidBoss

        double modifier = 1;
        int ssmodifier = 100;
        int value = 1;
        int maxLevel = SkillTable.getInstance().getMaxLevel(skill.getId(),skill.getLevel());
        double pAtk, pDef, mAtk, mDef;
        if (bss)
            ssmodifier = 200;
        else if (sps)
            ssmodifier = 150;        
        else if (ss)
            ssmodifier = 150;
    
        switch(type)
        {
        case STUN:
            // For normal Stun Attack, with skillType = STUN
        pAtk = player.getPAtk(target);
        pDef = target.getPDef(player);
        pDef = target.calcStat(Stats.STUN_RES,pDef,target,null);
        value = 30 * 100 + (int)(70 * 100 * ((float)skill.getLevel()/maxLevel));
        if (pDef > 0 && pAtk > 0)
            value *= 0.6 * pAtk/pDef;
            modifier    = 100 * target.getCON()/30;
            break;
        case CONFUSION:
            mAtk = player.getMAtk(target, skill);
            mDef = target.getMDef(player, skill);
            value = 30 * 100 + (int)(70 * 100 * ((float)skill.getLevel()/maxLevel));
            if (mDef > 0 && mAtk > 0)
                value *= 0.6 * mAtk/mDef;
                modifier    = 100 * target.getMEN()/15;
            //_log.fine(player.getName()+" matk:"+mAtk+",mdef="+mDef+",value="+value+",modifier="+modifier+",maxlevel="+maxLevel+",level="+skill.getLevel());
                break;
        case MUTE:
            mAtk = player.getMAtk(target, skill);
            mDef = target.getMDef(player, skill);
            value = 30 * 100 + (int)(70 * 100 * ((float)skill.getLevel()/maxLevel));
            if (mDef > 0 && mAtk > 0)
                value *= 0.6 * mAtk/mDef;
                modifier    = 100 * target.getMEN()/15;
            //_log.fine(player.getName()+" matk:"+mAtk+",mdef="+mDef+",value="+value+",modifier="+modifier+",maxlevel="+maxLevel+",level="+skill.getLevel());
                break;
        case MDAM:                
        case PARALYZE:
            mAtk = player.getMAtk(target, skill);
            mDef = target.getMDef(player, skill);
            value = 30 * 100 + (int)(70 * 100 * ((float)skill.getLevel()/maxLevel));
            mDef = target.calcStat(Stats.ROOT_RES,mDef,target,null);
            if (mDef > 0 && mAtk > 0)
                value *= 0.6 * mAtk/mDef;
            modifier    = 100 * target.getMEN()/15;
        //_log.fine(player.getName()+" matk:"+mAtk+",mdef="+mDef+",value="+value+",modifier="+modifier+",maxlevel="+maxLevel+",level="+skill.getLevel());
            break;
        case SLEEP:
        mAtk = player.getMAtk(target, skill);
        mDef = target.getMDef(player, skill);
        value = 30 * 100 + (int)(70 * 100 * ((float)skill.getLevel()/maxLevel));
        mDef = target.calcStat(Stats.SLEEP_RES,mDef,target,null);
        if (mDef > 0 && mAtk > 0)
            value *= 0.6 * mAtk/mDef;
            modifier    = 100 * target.getWIT()/15;
        //_log.fine(player.getName()+" matk:"+mAtk+",mdef="+mDef+",value="+value+",modifier="+modifier+",maxlevel="+maxLevel+",level="+skill.getLevel());
            break;
        case ROOT:
        mAtk = player.getMAtk(target, skill);
        mDef = target.getMDef(player, skill);
        value = 30 * 100 + (int)(70 * 100 * ((float)skill.getLevel()/maxLevel));
        mDef = target.calcStat(Stats.ROOT_RES,mDef,target,null);
        if (mDef > 0 && mAtk > 0)
            value *= 0.6 * mAtk/mDef;
            modifier    = 100 * target.getDEX()/30;
            break;
        default:
            // For normal Stun attack with skillType = PDAM
            pAtk = (int)skill.getPower();
        pDef = target.getPDef(player);
        pDef = target.calcStat(Stats.STUN_RES,pDef,target,null);
//      value = 30 * 100 + (int)(70 * 100 * ((float)skill.getLevel()/maxLevel));
        value = 100 * 100;
        if (pDef > 0 && pAtk > 0)
            value *= 0.6 * pAtk/pDef;
            modifier    = 100 * target.getCON()/30;
            break;
        }

        if (modifier == 0)
        {
            _log.warning("Name: "+target.getName()+" has bad base stat value. Fix datapack or notify dp ppl");
            modifier = 1;
        }

//        rate = (int)(((player.getLevel() - target.getLevel()) + (int)(value / modifier)) * ssmodifier);
        rate = ((player.getLevel() - target.getLevel()) + (int)(value / modifier)) *60 / 100;
        //_log.fine(player.getName()+" rate:"+rate);

        if (rate > 10000/(100+ssmodifier))
            rate = 100-(100-rate)*100/ssmodifier;
        else rate = rate*ssmodifier/100;
        
        if (rate > 100) rate = 100;
        else if (rate < 1) rate = 1;

        return (check < rate);
    }

    public int calcSkillSuccessModifier(SkillType type, L2Character target)
    {
        switch(type)
        {
            case STUN: return (int) target.calcStat(Stats.STUN_RES,target.getCON(),target,null);
            case ROOT: return (int) target.calcStat(Stats.ROOT_RES,target.getDEX(),target,null);
            case SLEEP: return (int) target.calcStat(Stats.SLEEP_RES,target.getWIT(),target,null);
            case MUTE: return target.getMEN();
            case PARALYZE: return (int) target.calcStat(Stats.ROOT_RES,target.getMEN(),target,null);
            default: return 0;
        }
    }

    public boolean calcSkillSuccess(L2Character player, L2Character target, L2Skill skill, boolean ss, boolean sps, boolean bss )
    {
        if(Config.ALT_GAME_SKILL_FORMULAS.equalsIgnoreCase("alt") ||
        	Config.ALT_GAME_SKILL_FORMULAS.equalsIgnoreCase("true"))
        	return calcAltSkillSuccess(player, target, skill);

    	SkillType type = skill.getSkillType();

        if (target.isRaid() && (type == SkillType.CONFUSION || type == SkillType.MUTE || type == SkillType.PARALYZE || type == SkillType.ROOT)) 
            return false; // these skills should not work on RaidBoss

        int value = (int)skill.getPower();
        if (type == SkillType.PDAM) // For additional effects on PDAM skills (like STUN, SHOCK,...)
        {
            value = 50;
            type = SkillType.STUN;
        }
        // TODO: Temporary fix for NPC skills with MagicLevel not set
        // int lvlmodifier = (skill.getMagicLevel() - target.getLevel()) * skill.getLevelDepend();
        int lvlmodifier = ((skill.getMagicLevel()>0?skill.getMagicLevel():player.getLevel()) - target.getLevel()) * skill.getLevelDepend();
        int modifier = calcSkillSuccessModifier(type, target);
        if(Config.DEVELOPER) System.out.println(skill.getName() + ": " + value + ", " + lvlmodifier + ", " + modifier);

        // TODO: Temporary fix for skills with Power = 0 or LevelDepend not set
        if(value == 0) value = (type == SkillType.PARALYZE)? 50 : 80;
        if(skill.getLevelDepend() == 0) lvlmodifier = ((skill.getMagicLevel()>0?skill.getMagicLevel():player.getLevel()) - target.getLevel()) * ((type == SkillType.PARALYZE)? 1 : 2);
        

        int ssmodifier = 100;
        if (bss) ssmodifier = 200;
        else if (sps) ssmodifier = 150;        
        else if (ss) ssmodifier = 150;

//        int rate = value + lvlmodifier - modifier;
        int rate = (value + lvlmodifier) * (100- modifier) / 100;
        int check = _rnd.nextInt(100);
        //_log.fine(player.getName()+" rate:"+rate);

        if (skill.isMagic()) rate *= Math.sqrt(player.getMAtk(target, skill)/target.getMDef(player, skill));

        if (rate > 99) rate = 99;
        else if (rate < 1) rate = 1;

        if (ssmodifier != 100)
        {
            if (rate > 10000/(100+ssmodifier))
                rate = 100-(100-rate)*100/ssmodifier;
            else rate = rate*ssmodifier/100;
        }

        return (check < rate);
    }

    public boolean calcAltSkillSuccess(L2Character activeChar, L2Character target, L2Skill skill)
    {
        // Get our numbers and base success rate
        SkillType type = skill.getSkillType();
        boolean success = true;
        int skillPower = (int)skill.getPower();
        int skillLevel = skill.getLevel();
        int attackerLevel = activeChar.getLevel();
        int targetLevel = target.getLevel();
        int CONModifier = (100 - target.getCON());
        int DEXModifier = (90 - target.getDEX());
        int WITModifier = (80 - target.getWIT());
        int powerModifier = Math.round(skillPower/100);
        int levelModifier = Math.round(skillLevel/2);
        int baseRate = (attackerLevel - targetLevel) + powerModifier + levelModifier;
        int rate = baseRate;
        int check = _rnd.nextInt(100);

        switch (type) {
            case STUN:
                rate += CONModifier;    // uses CON Modifier for STUN types
                break;
            case ROOT:
                rate += DEXModifier;    // uses DEX Modifier for ROOT types
                break;
            case PARALYZE:
            case SLEEP:
                rate += WITModifier;    // uses WIT Modifier for SLEEP and PARALYZE types
                break;
            default:
                rate += CONModifier;    // uses CON Modifier for any other types (like PDAM ones)
                break;
        }

        if (rate > 100) rate = 100;         // We shouldn't have more than 100% success rate
        if (rate < 1) rate = 1;             // We shouldn't have less than 1% success rate

        if (check > rate) success = false;
        return success;
    }

	public boolean calculateUnlockChance(L2Skill skill)
	{
		int level = skill.getLevel();
		int chance = 0;
		switch (level)
		{
	     case 1:
			 chance = 30;
	         break;

	     case 2:
			 chance = 50;
	         break;

	     case 3:
			 chance = 75;
	         break;

	     case 4:
	     case 5:
	     case 6:
	     case 7:
	     case 8:
	     case 9:
	     case 10:
	     case 11:
	     case 12:
	     case 13:
	     case 14:
			 chance = 100;
	         break;
		}
	     if(L2Character.getRnd().nextInt(120) > chance)
	     {
			 return false;
	     }

		return true;
	}
}