Browse Source

BETA/STABLE: Blow Formula Update by Didldak.

MELERIX 14 years ago
parent
commit
6b3cedfb8f

+ 10 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/model/L2Skill.java

@@ -206,6 +206,7 @@ public abstract class L2Skill implements IChanceSkillTrigger
 	private final boolean _ignoreResists;
 	private final int _minChance;
 	private final int _maxChance;
+	private final int _blowChance;
 	
 	private final boolean _isNeutral;
 	// Effecting area of the skill, in radius.
@@ -525,6 +526,7 @@ public abstract class L2Skill implements IChanceSkillTrigger
 		
 		_numSouls = set.getInteger("num_souls", 0);
 		_soulMaxConsume = set.getInteger("soulMaxConsumeCount", 0);
+		_blowChance = set.getInteger("blowChance", 0);
 		_soulConsume = set.getInteger("soulConsumeCount", 0);
 		_expNeeded = set.getInteger("expNeeded", 0);
 		_critChance = set.getInteger("critChance", 0);
@@ -2861,6 +2863,14 @@ public abstract class L2Skill implements IChanceSkillTrigger
 	{
 		return _attribute;
 	}
+
+	/**
+	 * @return the _blowChance
+	 */
+	public int getBlowChance()
+	{
+		return _blowChance;
+	}
 	
 	public boolean ignoreShield()
 	{

+ 132 - 51
L2J_Server_BETA/java/com/l2jserver/gameserver/skills/Formulas.java

@@ -14,6 +14,7 @@
  */
 package com.l2jserver.gameserver.skills;
 
+import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import com.l2jserver.Config;
@@ -1336,85 +1337,82 @@ public final class Formulas
 		
 		return 1.5; // If all is true, then modifer will be 50% more
 	}
-	/** Calculate blow damage based on cAtk */
+	
 	public static double calcBlowDamage(L2Character attacker, L2Character target, L2Skill skill, byte shld, boolean ss)
 	{
-		final boolean isPvP = (attacker instanceof L2Playable) && (target instanceof L2Playable);
-		final boolean isPvE = (attacker instanceof L2Playable) && (target instanceof L2Attackable);
-		double power = skill.getPower(isPvP, isPvE);
-		double damage = attacker.getPAtk(target);
-		damage+=calcValakasAttribute(attacker, target, skill);
 		double defence = target.getPDef(attacker);
-		if (attacker instanceof L2Npc)
-		{
-			if(((L2Npc)attacker)._soulshotcharged)
-			{
-				ss = true;
-			}
-			else
-				ss = false;
-			((L2Npc)attacker)._soulshotcharged = false;
-		}
-		
-		// Def bonusses in PvP fight
-		if(isPvP)
-			defence *= target.calcStat(Stats.PVP_PHYS_SKILL_DEF, 1, null, null);
 		
-		if(ss)
-			damage *= 2.;
 		switch(shld)
 		{
-			case SHIELD_DEFENSE_SUCCEED:
+			case Formulas.SHIELD_DEFENSE_SUCCEED:
 				defence += target.getShldDef();
 				break;
-			case SHIELD_DEFENSE_PERFECT_BLOCK: // perfect block
+			case Formulas.SHIELD_DEFENSE_PERFECT_BLOCK: // perfect block
 				return 1;
 		}
 		
-		if(ss && skill.getSSBoost()>0)
-			power *= skill.getSSBoost();
+		double power =  skill.getPower();
+		//TODO: target instanceof L2Playable && skill.getPvpPower() != 0 ? skill.getPvpPower() : skill.getPower();
+		double damage = 0;
+		double proximityBonus = 1;
+		double graciaPhysSkillBonus = skill.isMagic() ? 1 : 1.10113; // Gracia final physical skill bonus 10.113%
+		double ssboost = ss ? (skill.getSSBoost() > 0 ? skill.getSSBoost() : 2.04) : 1; // 104% bonus with SS
+		double pvpBonus = 1;
 		
-		damage = attacker.calcStat(Stats.CRITICAL_DAMAGE, (damage+power), target, skill);
-		damage *= calcElemental(attacker, target, skill);
-		damage += attacker.calcStat(Stats.CRITICAL_DAMAGE_ADD, 0, target, skill) * 6.5;
-		damage *= target.calcStat(Stats.CRIT_VULN, target.getTemplate().baseCritVuln, target, skill);
-		damage += target.calcStat(Stats.CRIT_ADD_VULN, 0, target, skill) * 6.5;
+		if ((attacker instanceof L2Playable) && (target instanceof L2Playable))
+		{
+			// Dmg bonusses in PvP fight
+			pvpBonus *= attacker.calcStat(Stats.PVP_PHYS_SKILL_DMG, 1, null, null);
+			// Def bonusses in PvP fight
+			defence *= target.calcStat(Stats.PVP_PHYS_SKILL_DEF, 1, null, null);
+		}
+		
+		if (isBehind(attacker, target))
+			proximityBonus = 1.2; // +20% crit dmg when back stabbed
+		else if (isInFrontOf(attacker, target))
+			proximityBonus = 1.1; // +10% crit dmg when side stabbed
+		
+		damage += Formulas.calcValakasAttribute(attacker, target, skill);
+		
+		double element = calcElemental(attacker, target, skill);
+		
+		// SSBoost > 0 have different calculation
+		if (skill.getSSBoost() > 0)
+			damage += 70. * graciaPhysSkillBonus * (attacker.getPAtk(target) + power) / defence * (attacker.calcStat(Stats.CRITICAL_DAMAGE, 1, target, skill))
+			* (target.calcStat(Stats.CRIT_VULN, 1, target, skill)) * ssboost * proximityBonus * element * pvpBonus
+			+ (attacker.calcStat(Stats.CRITICAL_DAMAGE_ADD, 0, target, skill) * 6.1 * 70 / defence * graciaPhysSkillBonus);
+		else
+			damage += 70. * graciaPhysSkillBonus * (power + (attacker.getPAtk(target) * ssboost)) / defence * (attacker.calcStat(Stats.CRITICAL_DAMAGE, 1, target, skill))
+			* (target.calcStat(Stats.CRIT_VULN, 1, target, skill)) * proximityBonus * element * pvpBonus
+			+ (attacker.calcStat(Stats.CRITICAL_DAMAGE_ADD, 0, target, skill) * 6.1 * 70 / defence * graciaPhysSkillBonus);
 		
 		// get the natural vulnerability for the template
 		/*if (target instanceof L2Npc)
 		{
 			damage *= ((L2Npc) target).getTemplate().getVulnerability(Stats.DAGGER_WPN_VULN);
 		}*/
+		
 		// get the vulnerability for the instance due to skills (buffs, passives, toggles, etc)
 		damage = target.calcStat(Stats.DAGGER_WPN_VULN, damage, target, null);
-		damage *= 80 / defence;
-		
 		// Random weapon damage
 		damage *= attacker.getRandomDamageMultiplier();
 		
-		// Physical skill dmg boost
-		damage *= attacker.calcStat(Stats.PHYSICAL_SKILL_POWER, 1, null, null);
-		
-		// Dmg bonusses in PvP fight
-		if(isPvP)
-			damage *= attacker.calcStat(Stats.PVP_PHYS_SKILL_DMG, 1, null, null);
-		else if (target instanceof L2Attackable)
+		if (target instanceof L2Attackable && !target.isRaid() && !target.isRaidMinion() && target.getLevel() >= Config.MIN_NPC_LVL_DMG_PENALTY && attacker.getActingPlayer() != null
+				&& (target.getLevel() - attacker.getActingPlayer().getLevel()) >= 2)
 		{
-			damage *= attacker.calcStat(Stats.PVE_PHYS_SKILL_DMG, 1, null, null);
-			if (!target.isRaid() && !target.isRaidMinion()
-					&& target.getLevel() >= Config.MIN_NPC_LVL_DMG_PENALTY && attacker.getActingPlayer() != null
-					&& (target.getLevel() - attacker.getActingPlayer().getLevel()) >= 2)
-			{
-				int lvlDiff = target.getLevel() - attacker.getActingPlayer().getLevel() - 1;
-				if (lvlDiff > Config.NPC_SKILL_DMG_PENALTY.size())
-					damage *= Config.NPC_SKILL_DMG_PENALTY.get(Config.NPC_SKILL_DMG_PENALTY.size());
-				else
-					damage *= Config.NPC_SKILL_DMG_PENALTY.get(lvlDiff);
-			}
+			int lvlDiff = target.getLevel() - attacker.getActingPlayer().getLevel() - 1;
+			if (lvlDiff > Config.NPC_SKILL_DMG_PENALTY.size())
+				damage *= Config.NPC_SKILL_DMG_PENALTY.get(Config.NPC_SKILL_DMG_PENALTY.size());
+			else
+				damage *= Config.NPC_SKILL_DMG_PENALTY.get(lvlDiff);
+			
 		}
 		
+		//TODO: Formulas.calcStunBreak(target, damage);
+
 		return damage < 1 ? 1. : damage;
 	}
+	
 	/** Calculated damage caused by ATTACK of attacker on target,
 	 * called separatly for each weapon, if dual-weapon is used.
 	 *
@@ -3127,4 +3125,87 @@ public final class Formulas
 		final double damage = cha.calcStat(Stats.FALL, fallHeight * cha.getMaxHp() / 1000, null, null);
 		return damage;
 	}
+	
+	private static double FRONT_MAX_ANGLE = 100;
+	private static double BACK_MAX_ANGLE = 40;
+	
+	/**
+	 * Calculates blow success depending on base chance and relative position of attacker and target
+	 * @param activeChar Target that is performing skill
+	 * @param target Target of this skill
+	 * @param skill Skill which will be used to get base value of blowChance and crit condition
+	 * @return Success of blow
+	 */
+	public static boolean calcBlowSuccess(L2Character activeChar, L2Character target, L2Skill skill)
+	{
+		int blowChance = skill.getBlowChance();
+		
+		// Skill is blow and it has 0% to make dmg... thats just wrong
+		if (blowChance == 0)
+		{
+			_log.log(Level.WARNING, "Skill " + skill.getId() + " - " + skill.getName() + " has 0 blow land chance, yet its a blow skill!");
+			//TODO: return false;
+			//lets add 20 for now, till all skills are corrected
+			blowChance = 20;
+		}
+		
+		if (isBehind(target, activeChar))
+			blowChance *= 2; //double chance from behind
+		else if (isInFrontOf(target, activeChar))
+		{
+			if ((skill.getCondition() & L2Skill.COND_BEHIND) != 0)
+				return false;
+
+			//base chance from front	
+		}
+		else
+			blowChance *= 1.5; //50% better chance from side
+		
+		return activeChar.calcStat(Stats.BLOW_RATE, blowChance * (1.0 + (activeChar.getDEX()) / 100.), target, null) > Rnd.get(100);
+	}
+	
+	/**
+	 * Those are altered formulas for blow lands
+	 * Return True if the target is IN FRONT of the L2Character.<BR><BR>
+	 */
+	public static boolean isInFrontOf(L2Character target, L2Character attacker)
+	{
+		if (target == null)
+			return false;
+		
+		double angleChar, angleTarget, angleDiff;
+		angleTarget = Util.calculateAngleFrom(target, attacker);
+		angleChar = Util.convertHeadingToDegree(target.getHeading());
+		angleDiff = angleChar - angleTarget;
+		if (angleDiff <= -360 + FRONT_MAX_ANGLE)
+			angleDiff += 360;
+		if (angleDiff >= 360 - FRONT_MAX_ANGLE)
+			angleDiff -= 360;
+		if (Math.abs(angleDiff) <= FRONT_MAX_ANGLE)
+			return true;
+		return false;
+	}
+	
+	/**
+	 * Those are altered formulas for blow lands
+	 * Return True if the L2Character is behind the target and can't be seen.<BR><BR>
+	 */
+	public static boolean isBehind(L2Character target, L2Character attacker)
+	{
+		if (target == null)
+			return false;
+		
+		double angleChar, angleTarget, angleDiff;
+		L2Character target1 = target;
+		angleChar = Util.calculateAngleFrom(attacker, target1);
+		angleTarget = Util.convertHeadingToDegree(target1.getHeading());
+		angleDiff = angleChar - angleTarget;
+		if (angleDiff <= -360 + BACK_MAX_ANGLE)
+			angleDiff += 360;
+		if (angleDiff >= 360 - BACK_MAX_ANGLE)
+			angleDiff -= 360;
+		if (Math.abs(angleDiff) <= BACK_MAX_ANGLE)
+			return true;
+		return false;
+	}
 }