Перейти к содержанию
Авторизация  
nemo

Формула попадания blow скилов

Рекомендуемые сообщения

Здравствуйте. Подскажите где в исходниках основанных на First Team найти формулу попадания blow скилов?

В интернете нашел вот такую формулу-

prelim_chance = dex_bonus * (base_weapon_crit / 10) * crit_loc_bonus * crit_height_bonus * ((land_chance_bonus + 100) / 100) * fatal_blow_rate_multiplier *skill_res_multiplier

Но ни чего такого похожего у себя не нашел.

Может она как то по другому в First Team рассчитывает? Или по другому написана?

Подскажите кто сталкивался, где смотреть?

Спасибо.

Изменено пользователем nemo

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Здравствуйте. Подскажите где в исходниках основанных на First Team найти формулу попадания blow скилов?

В интернете нашел вот такую формулу-

prelim_chance = dex_bonus * (base_weapon_crit / 10) * crit_loc_bonus * crit_height_bonus * ((land_chance_bonus + 100) / 100) * fatal_blow_rate_multiplier *skill_res_multiplier

Но ни чего такого похожего у себя не нашел.

Может она как то по другому в First Team рассчитывает? Или по другому написана?

Подскажите кто сталкивался, где смотреть?

Спасибо.

Что то вроде Formulas.java

L2J
public static double calcBlowDamage(L2Character attacker, L2Character target, Skill skill, byte shld, boolean ss)
	{
		double defence = target.getPDef(attacker);
		
		switch (shld)
		{
			case Formulas.SHIELD_DEFENSE_SUCCEED:
			{
				defence += target.getShldDef();
				break;
			}
			case Formulas.SHIELD_DEFENSE_PERFECT_BLOCK: // perfect block
			{
				return 1;
			}
		}
		
		final boolean isPvP = attacker.isPlayable() && target.isPlayable();
		final boolean isPvE = attacker.isPlayable() && target.isAttackable();
		double power = skill.getPower(isPvP, isPvE);
		double damage = 0;
		double proximityBonus = attacker.isBehindTarget() ? 1.2 : attacker.isInFrontOfTarget() ? 1 : 1.1; // Behind: +20% - Side: +10% (TODO: values are unconfirmed, possibly custom, remove or update when confirmed);
		double ssboost = ss ? 1.458 : 1;
		double pvpBonus = 1;
		
		if (isPvP)
		{
			// Damage bonuses in PvP fight
			pvpBonus = attacker.calcStat(Stats.PVP_PHYS_SKILL_DMG, 1, null, null);
			// Defense bonuses in PvP fight
			defence *= target.calcStat(Stats.PVP_PHYS_SKILL_DEF, 1, null, null);
		}
		
		// Initial damage
		double baseMod = ((77 * (power + (attacker.getPAtk(target) * ssboost))) / defence);
		// Critical
		double criticalMod = (attacker.calcStat(Stats.CRITICAL_DAMAGE, 1, target, skill));
		double criticalModPos = (((attacker.calcStat(Stats.CRITICAL_DAMAGE_POS, 1, target, skill) - 1) / 2) + 1);
		double criticalVulnMod = (target.calcStat(Stats.DEFENCE_CRITICAL_DAMAGE, 1, target, skill));
		double criticalAddMod = ((attacker.getStat().calcStat(Stats.CRITICAL_DAMAGE_ADD, 0) * 6.1 * 77) / defence);
		double criticalAddVuln = target.calcStat(Stats.DEFENCE_CRITICAL_DAMAGE_ADD, 0, target, skill);
		// Trait, elements
		double weaponTraitMod = calcWeaponTraitBonus(attacker, target);
		double generalTraitMod = calcGeneralTraitBonus(attacker, target, skill.getTraitType(), false);
		double attributeMod = calcAttributeBonus(attacker, target, skill);
		double weaponMod = attacker.getRandomDamageMultiplier();
		
		double penaltyMod = 1;
		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))
		{
			int lvlDiff = target.getLevel() - attacker.getActingPlayer().getLevel() - 1;
			if (lvlDiff >= Config.NPC_SKILL_DMG_PENALTY.size())
			{
				penaltyMod *= Config.NPC_SKILL_DMG_PENALTY.get(Config.NPC_SKILL_DMG_PENALTY.size() - 1);
			}
			else
			{
				penaltyMod *= Config.NPC_SKILL_DMG_PENALTY.get(lvlDiff);
			}
		}
		damage = (baseMod * criticalMod * criticalModPos * criticalVulnMod * proximityBonus * pvpBonus) + criticalAddMod + criticalAddVuln;
		damage *= weaponTraitMod;
		damage *= generalTraitMod;
		damage *= attributeMod;
		damage *= weaponMod;
		damage *= penaltyMod;
		
		if (attacker.isDebug())
		{
			final StatsSet set = new StatsSet();
			set.set("skillPower", skill.getPower(isPvP, isPvE));
			set.set("ssboost", ssboost);
			set.set("proximityBonus", proximityBonus);
			set.set("pvpBonus", pvpBonus);
			set.set("baseMod", baseMod);
			set.set("criticalMod", criticalMod);
			set.set("criticalModPos", criticalModPos);
			set.set("criticalVulnMod", criticalVulnMod);
			set.set("criticalAddMod", criticalAddMod);
			set.set("criticalAddVuln", criticalAddVuln);
			set.set("weaponTraitMod", weaponTraitMod);
			set.set("generalTraitMod", generalTraitMod);
			set.set("attributeMod", attributeMod);
			set.set("weaponMod", weaponMod);
			set.set("penaltyMod", penaltyMod);
			set.set("damage", (int) damage);
			Debug.sendSkillDebug(attacker, target, skill, set);
		}
		
		return Math.max(damage, 1);
	} 

 

 

Изменено пользователем LifeGame32

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Что то вроде Formulas.java

L2J
public static double calcBlowDamage(L2Character attacker, L2Character target, Skill skill, byte shld, boolean ss)
	{
		double defence = target.getPDef(attacker);
		
		switch (shld)
		{
			case Formulas.SHIELD_DEFENSE_SUCCEED:
			{
				defence += target.getShldDef();
				break;
			}
			case Formulas.SHIELD_DEFENSE_PERFECT_BLOCK: // perfect block
			{
				return 1;
			}
		}
		
		final boolean isPvP = attacker.isPlayable() && target.isPlayable();
		final boolean isPvE = attacker.isPlayable() && target.isAttackable();
		double power = skill.getPower(isPvP, isPvE);
		double damage = 0;
		double proximityBonus = attacker.isBehindTarget() ? 1.2 : attacker.isInFrontOfTarget() ? 1 : 1.1; // Behind: +20% - Side: +10% (TODO: values are unconfirmed, possibly custom, remove or update when confirmed);
		double ssboost = ss ? 1.458 : 1;
		double pvpBonus = 1;
		
		if (isPvP)
		{
			// Damage bonuses in PvP fight
			pvpBonus = attacker.calcStat(Stats.PVP_PHYS_SKILL_DMG, 1, null, null);
			// Defense bonuses in PvP fight
			defence *= target.calcStat(Stats.PVP_PHYS_SKILL_DEF, 1, null, null);
		}
		
		// Initial damage
		double baseMod = ((77 * (power + (attacker.getPAtk(target) * ssboost))) / defence);
		// Critical
		double criticalMod = (attacker.calcStat(Stats.CRITICAL_DAMAGE, 1, target, skill));
		double criticalModPos = (((attacker.calcStat(Stats.CRITICAL_DAMAGE_POS, 1, target, skill) - 1) / 2) + 1);
		double criticalVulnMod = (target.calcStat(Stats.DEFENCE_CRITICAL_DAMAGE, 1, target, skill));
		double criticalAddMod = ((attacker.getStat().calcStat(Stats.CRITICAL_DAMAGE_ADD, 0) * 6.1 * 77) / defence);
		double criticalAddVuln = target.calcStat(Stats.DEFENCE_CRITICAL_DAMAGE_ADD, 0, target, skill);
		// Trait, elements
		double weaponTraitMod = calcWeaponTraitBonus(attacker, target);
		double generalTraitMod = calcGeneralTraitBonus(attacker, target, skill.getTraitType(), false);
		double attributeMod = calcAttributeBonus(attacker, target, skill);
		double weaponMod = attacker.getRandomDamageMultiplier();
		
		double penaltyMod = 1;
		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))
		{
			int lvlDiff = target.getLevel() - attacker.getActingPlayer().getLevel() - 1;
			if (lvlDiff >= Config.NPC_SKILL_DMG_PENALTY.size())
			{
				penaltyMod *= Config.NPC_SKILL_DMG_PENALTY.get(Config.NPC_SKILL_DMG_PENALTY.size() - 1);
			}
			else
			{
				penaltyMod *= Config.NPC_SKILL_DMG_PENALTY.get(lvlDiff);
			}
		}
		damage = (baseMod * criticalMod * criticalModPos * criticalVulnMod * proximityBonus * pvpBonus) + criticalAddMod + criticalAddVuln;
		damage *= weaponTraitMod;
		damage *= generalTraitMod;
		damage *= attributeMod;
		damage *= weaponMod;
		damage *= penaltyMod;
		
		if (attacker.isDebug())
		{
			final StatsSet set = new StatsSet();
			set.set("skillPower", skill.getPower(isPvP, isPvE));
			set.set("ssboost", ssboost);
			set.set("proximityBonus", proximityBonus);
			set.set("pvpBonus", pvpBonus);
			set.set("baseMod", baseMod);
			set.set("criticalMod", criticalMod);
			set.set("criticalModPos", criticalModPos);
			set.set("criticalVulnMod", criticalVulnMod);
			set.set("criticalAddMod", criticalAddMod);
			set.set("criticalAddVuln", criticalAddVuln);
			set.set("weaponTraitMod", weaponTraitMod);
			set.set("generalTraitMod", generalTraitMod);
			set.set("attributeMod", attributeMod);
			set.set("weaponMod", weaponMod);
			set.set("penaltyMod", penaltyMod);
			set.set("damage", (int) damage);
			Debug.sendSkillDebug(attacker, target, skill, set);
		}
		
		return Math.max(damage, 1);
	} 

 

 

У меня нет такого. 

Вот мой файл  Formulas.java . Где в нем найти формулу попадания blow скилов?

public class Formulas

{
public static double calcHpRegen(Creature cha)
{
double init;
if(cha.isPlayer())
init = (cha.getLevel() <= 10 ? 1.5 + cha.getLevel() / 20. : 1.4 + cha.getLevel() / 10.) * cha.getLevelMod();
else
init = cha.getTemplate().baseHpReg;
 
if(cha.isPlayable())
{
init *= BaseStats.CON.calcBonus(cha);
if(cha.isSummon())
init *= 2;
}
 
return cha.calcStat(Stats.REGENERATE_HP_RATE, init, null, null);
}
 
public static double calcMpRegen(Creature cha)
{
double init;
if(cha.isPlayer())
init = (.87 + cha.getLevel() * .03) * cha.getLevelMod();
else
init = cha.getTemplate().baseMpReg;
 
if(cha.isPlayable())
{
init *= BaseStats.MEN.calcBonus(cha);
if(cha.isSummon())
init *= 2;
}
 
return cha.calcStat(Stats.REGENERATE_MP_RATE, init, null, null);
}
 
public static double calcCpRegen(Creature cha)
{
double init = (1.5 + cha.getLevel() / 10) * cha.getLevelMod() * BaseStats.CON.calcBonus(cha);
return cha.calcStat(Stats.REGENERATE_CP_RATE, init, null, null);
}
 
public static class AttackInfo
{
public double damage = 0;
public double defence = 0;
public double crit_static = 0;
public double death_rcpt = 0;
public double lethal1 = 0;
public double lethal2 = 0;
public double lethal_dmg = 0;
public boolean crit = false;
public boolean shld = false;
public boolean lethal = false;
public boolean miss = false;
}
 
/**
* Для простых ударов
* patk = patk
* При крите простым ударом:
* patk = patk * (1 + crit_damage_rcpt) * crit_damage_mod + crit_damage_static
* Для blow скиллов
* TODO
* Для скилловых критов, повреждения просто удваиваются, бафы не влияют (кроме blow, для них выше)
* patk = (1 + crit_damage_rcpt) * (patk + skill_power)
* Для обычных атак
* damage = patk * ss_bonus * 70 / pdef
*/
public static AttackInfo calcPhysDam(Creature attacker, Creature target, Skill skill, boolean dual, boolean blow, boolean ss, boolean onCrit)
{
AttackInfo info = new AttackInfo();
 
info.damage = attacker.getPAtk(target);
info.defence = target.getPDef(attacker);
info.crit_static = attacker.calcStat(Stats.CRITICAL_DAMAGE_STATIC, target, skill);
info.death_rcpt = 0.01 * target.calcStat(Stats.DEATH_VULNERABILITY, attacker, skill);
info.lethal1 = skill == null ? 0 : skill.getLethal1() * info.death_rcpt;
info.lethal2 = skill == null ? 0 : skill.getLethal2() * info.death_rcpt;
info.crit = Rnd.chance(calcCrit(attacker, target, skill, blow));
info.shld = (skill == null || !skill.getShieldIgnore()) && Formulas.calcShldUse(attacker, target);
info.lethal = false;
info.miss = false;
boolean isPvP = attacker.isPlayable() && target.isPlayable();
 
if(info.shld)
info.defence += target.getShldDef();
 
info.defence = Math.max(info.defence, 1);
 
if(skill != null)
{
if(!blow && !target.isLethalImmune()) // считаем леталы для не blow скиллов
if(Rnd.chance(info.lethal1))
{
if(target.isPlayer())
{
info.lethal = true;
info.lethal_dmg = target.getCurrentCp();
target.sendPacket(SystemMsg.YOUR_CP_WAS_DRAINED_BECAUSE_YOU_WERE_HIT_WITH_A_CP_SIPHON_SKILL);
}
else
info.lethal_dmg = target.getCurrentHp() / 2;
attacker.sendPacket(SystemMsg.CP_SIPHON);
}
else if(Rnd.chance(info.lethal2))
{
if(target.isPlayer())
{
info.lethal = true;
info.lethal_dmg = target.getCurrentHp() + target.getCurrentCp() - 1.1; // Oly\Duel хак установки не точно 1 ХП, а чуть больше для предотвращения псевдосмерти
target.sendPacket(SystemMsg.LETHAL_STRIKE);
}
else
info.lethal_dmg = target.getCurrentHp() - 1;
attacker.sendPacket(SystemMsg.YOUR_LETHAL_STRIKE_WAS_SUCCESSFUL);
}
 
// если скилл не имеет своей силы дальше идти бесполезно, можно сразу вернуть дамаг от летала
if(skill.getPower(target) == 0)
{
info.damage = 0; // обычного дамага в этом случае не наносится
return info;
}
 
if(blow && !skill.isBehind() && ss) // Для обычных blow не влияет на power
info.damage *= 2.04;
 
info.damage += Math.max(0., skill.getPower(target) * attacker.calcStat(Stats.SKILL_POWER, 1, null, null));
 
if(blow && skill.isBehind() && ss) // Для backstab влияет на power, но меньше множитель
info.damage *= 1.5;
 
//Заряжаемые скилы имеют постоянный урон
if(!skill.isChargeBoost())
info.damage *= 1 + (Rnd.get() * attacker.getRandomDamage() * 2 - attacker.getRandomDamage()) / 100;
 
if(blow)
{
info.damage *= 0.01 * attacker.calcStat(Stats.CRITICAL_DAMAGE, target, skill);
info.damage = target.calcStat(Stats.CRIT_DAMAGE_RECEPTIVE, info.damage, attacker, skill);
info.damage += 6.1 * info.crit_static;
}
 
if(skill.isChargeBoost())
info.damage *= 0.8 + 0.2 * attacker.getIncreasedForce();
 
if(skill.getSkillType() == SkillType.CHARGE)
info.damage *= 2;
else if(skill.isSoulBoost())
info.damage *= 1.0 + 0.06 * Math.min(attacker.getConsumedSouls(), 5);
 
// Gracia Physical Skill Damage Bonus
info.damage *= 1.10113;
 
if(info.crit)
{
//Заряжаемые скилы игнорируют снижающие силу крита статы
if (skill.isChargeBoost() || skill.getSkillType() == SkillType.CHARGE)
info.damage *= 2.;
else
info.damage = 2 * target.calcStat(Stats.CRIT_DAMAGE_RECEPTIVE, info.damage, attacker, skill);
}
}
else
{
info.damage *= 1 + (Rnd.get() * attacker.getRandomDamage() * 2 - attacker.getRandomDamage()) / 100;
 
if(dual)
info.damage /= 2.;
 
if(info.crit)
{
info.damage *= 0.01 * attacker.calcStat(Stats.CRITICAL_DAMAGE, target, skill);
info.damage = 2 * target.calcStat(Stats.CRIT_DAMAGE_RECEPTIVE, info.damage, attacker, skill);
info.damage += info.crit_static;
}
}
 
if(info.crit)
{
// шанс абсорбации души (без анимации) при крите, если Soul Mastery 4го уровня или более
int chance = attacker.getSkillLevel(Skill.SKILL_SOUL_MASTERY);
if(chance > 0)
{
if(chance >= 21)
chance = 30;
else if(chance >= 15)
chance = 25;
else if(chance >= 9)
chance = 20;
else if(chance >= 4)
chance = 15;
if(Rnd.chance(chance))
attacker.setConsumedSouls(attacker.getConsumedSouls() + 1, null);
}
}
 
switch(PositionUtils.getDirectionTo(target, attacker))
{
case BEHIND:
info.damage *= 1.2;
break;
case SIDE:
info.damage *= 1.1;
break;
}
 
if(ss)
info.damage *= blow ? 1.0 : 2.0;
 
info.damage *= 70. / info.defence;
info.damage = attacker.calcStat(Stats.PHYSICAL_DAMAGE, info.damage, target, skill);
 
if(info.shld && Rnd.chance(5))
info.damage = 1;
 
if(isPvP)
{
if(skill == null)
{
info.damage *= attacker.calcStat(Stats.PVP_PHYS_DMG_BONUS, 1, null, null);
info.damage /= target.calcStat(Stats.PVP_PHYS_DEFENCE_BONUS, 1, null, null);
}
else
{
info.damage *= attacker.calcStat(Stats.PVP_PHYS_SKILL_DMG_BONUS, 1, null, null);
info.damage /= target.calcStat(Stats.PVP_PHYS_SKILL_DEFENCE_BONUS, 1, null, null);
}
}
 
info.damage *= balancerDamageModifier(attacker, skill, blow);
info.damage *= balancerIncomeDamageModifier(attacker, target);
 
// Тут проверяем только если skill != null, т.к. L2Character.onHitTimer не обсчитывает дамаг.
if(skill != null)
{
if(info.shld)
if(info.damage == 1)
target.sendPacket(SystemMsg.YOUR_EXCELLENT_SHIELD_DEFENSE_WAS_A_SUCCESS);
else
target.sendPacket(SystemMsg.YOUR_SHIELD_DEFENSE_HAS_SUCCEEDED);
 
// Уворот от физ скилов уводит атаку в 0
if(info.damage > 1 && !skill.hasEffects() && Rnd.chance(target.calcStat(Stats.PSKILL_EVASION, 0, attacker, skill)))
{
attacker.sendPacket(new SystemMessage2(SystemMsg.C1S_ATTACK_WENT_ASTRAY).addName(attacker));
target.sendPacket(new SystemMessage2(SystemMsg.C1_HAS_EVADED_C2S_ATTACK).addName(target).addName(attacker));
info.damage = 0;
}
 
if(info.damage > 1 && skill.isDeathlink())
info.damage *= 1.8 * (1.0 - attacker.getCurrentHpRatio());
 
if(onCrit && !calcBlow(attacker, target, skill))
{
info.miss = true;
info.damage = 0;
attacker.sendPacket(new SystemMessage2(SystemMsg.C1S_ATTACK_WENT_ASTRAY).addName(attacker));
}
 
if(blow)
if(Rnd.chance(info.lethal1))
{
if(target.isPlayer())
{
info.lethal = true;
info.lethal_dmg = target.getCurrentCp();
target.sendPacket(SystemMsg.YOUR_CP_WAS_DRAINED_BECAUSE_YOU_WERE_HIT_WITH_A_CP_SIPHON_SKILL);
}
else if(target.isLethalImmune())
info.damage *= 2;
else
info.lethal_dmg = target.getCurrentHp() / 2;
attacker.sendPacket(SystemMsg.CP_SIPHON);
}
else if(Rnd.chance(info.lethal2))
{
if(target.isPlayer())
{
info.lethal = true;
info.lethal_dmg = target.getCurrentHp() + target.getCurrentCp() - 1.1;
target.sendPacket(SystemMsg.LETHAL_STRIKE);
}
else if(target.isLethalImmune())
info.damage *= 3;
else
info.lethal_dmg = target.getCurrentHp() - 1;
attacker.sendPacket(SystemMsg.YOUR_LETHAL_STRIKE_WAS_SUCCESSFUL);
}
 
if(info.damage > 0)
attacker.displayGiveDamageMessage(target, (int) info.damage, info.crit || blow, false, false, false);
 
if(target.isStunned() && calcStunBreak(info.crit))
target.getEffectList().stopEffects(EffectType.Stun);
 
if(calcCastBreak(target, info.crit))
target.abortCast(false, true);
}
 
return info;
}
 
public static double calcMagicDam(Creature attacker, Creature target, Skill skill, int sps)
{
boolean isPvP = attacker.isPlayable() && target.isPlayable();
// Параметр ShieldIgnore для магических скиллов инвертирован
boolean shield = skill.getShieldIgnore() && calcShldUse(attacker, target);
 
int levelDiff = target.getLevel() - attacker.getLevel();
 
double mAtk = attacker.getMAtk(target, skill);
 
if(sps == 2)
mAtk *= 4;
else if(sps == 1)
mAtk *= 2;
 
double mdef = target.getMDef(null, skill);
 
if(shield)
mdef += target.getShldDef();
if(mdef == 0)
mdef = 1;
 
double power = skill.getPower(target);
double lethalDamage = 0;
 
if(Rnd.chance(skill.getLethal1()))
{
if(target.isPlayer())
{
lethalDamage = target.getCurrentCp();
target.sendPacket(SystemMsg.YOUR_CP_WAS_DRAINED_BECAUSE_YOU_WERE_HIT_WITH_A_CP_SIPHON_SKILL);
}
else if(!target.isLethalImmune())
lethalDamage = target.getCurrentHp() / 2;
else
power *= 2;
attacker.sendPacket(SystemMsg.CP_SIPHON);
}
else if(Rnd.chance(skill.getLethal2()))
{
if(levelDiff <= 9)
{
if(target.isPlayer())
{
lethalDamage = target.getCurrentHp() + target.getCurrentCp() - 1.1;
target.sendPacket(SystemMsg.LETHAL_STRIKE);
}
else if(!target.isLethalImmune())
lethalDamage = target.getCurrentHp() - 1;
else
power *= 3;
attacker.sendPacket(SystemMsg.YOUR_LETHAL_STRIKE_WAS_SUCCESSFUL);
}
else
{
lethalDamage = 0;
power = 0;
}
}
 
if(power == 0)
{
if(lethalDamage > 0)
attacker.displayGiveDamageMessage(target, (int) lethalDamage, false, false, false, false);
return lethalDamage;
}
 
if(skill.isSoulBoost())
power *= 1.0 + 0.06 * Math.min(attacker.getConsumedSouls(), 5);
 
double damage = 91 * power * Math.sqrt(mAtk) / mdef;
 
damage *= 1 + (Rnd.get() * attacker.getRandomDamage() * 2 - attacker.getRandomDamage()) / 100;
 
boolean crit = calcMCrit(attacker.getMagicCriticalRate(target, skill));
 
if(crit)
damage *= attacker.calcStat(Stats.MCRITICAL_DAMAGE, attacker.isPlayable() && target.isPlayable() ? 2.5 : 3., target, skill);
 
damage = attacker.calcStat(Stats.MAGIC_DAMAGE, damage, target, skill);
 
if(shield)
{
if(Rnd.chance(5))
{
damage = 0;
target.sendPacket(SystemMsg.YOUR_EXCELLENT_SHIELD_DEFENSE_WAS_A_SUCCESS);
attacker.sendPacket(new SystemMessage2(SystemMsg.C1_RESISTED_C2S_MAGIC).addName(target).addName(attacker));
}
else
{
target.sendPacket(SystemMsg.YOUR_SHIELD_DEFENSE_HAS_SUCCEEDED);
attacker.sendPacket(new SystemMessage2(SystemMsg.YOUR_OPPONENT_HAS_RESISTANCE_TO_MAGIC_THE_DAMAGE_WAS_DECREASED));
}
}
 
if(damage > 1 && skill.isDeathlink())
damage *= 1.8 * (1.0 - attacker.getCurrentHpRatio());
 
if(damage > 1 && skill.isBasedOnTargetDebuff())
damage *= 1 + 0.05 * target.getEffectList().getAllEffects().size();
 
damage += lethalDamage;
 
if(skill.getSkillType() == SkillType.MANADAM)
damage = Math.max(1, damage / 4.);
 
if(isPvP && damage > 1)
{
damage *= attacker.calcStat(Stats.PVP_MAGIC_SKILL_DMG_BONUS, 1, null, null);
damage /= target.calcStat(Stats.PVP_MAGIC_SKILL_DEFENCE_BONUS, 1, null, null);
}
double magic_rcpt = target.calcStat(Stats.MAGIC_RESIST, attacker, skill) - attacker.calcStat(Stats.MAGIC_POWER, target, skill);
double failChance = 4. * Math.max(1., levelDiff) * (1. + magic_rcpt / 100.);
if(Rnd.chance(failChance))
{
if(levelDiff > 9)
{
damage = 0;
SystemMessage msg = new SystemMessage(SystemMessage.C1_RESISTED_C2S_MAGIC).addName(target).addName(attacker);
attacker.sendPacket(msg);
target.sendPacket(msg);
}
else
{
damage /= 2;
SystemMessage msg = new SystemMessage(SystemMessage.DAMAGE_IS_DECREASED_BECAUSE_C1_RESISTED_AGAINST_C2S_MAGIC).addName(target).addName(attacker);
attacker.sendPacket(msg);
target.sendPacket(msg);
}
}
 
damage *= balancerMagicDamageModifier(attacker);
damage *= balancerIncomeDamageModifier(attacker, target);
 
if(damage > 0)
attacker.displayGiveDamageMessage(target, (int) damage, crit, false, false, true);
 
if(calcCastBreak(target, crit))
target.abortCast(false, true);
 
return damage;
}
 
public static boolean calcStunBreak(boolean crit)
{
return Rnd.chance(crit ? 75 : 10);
}
 
/** Returns true in case of fatal blow success */
public static boolean calcBlow(Creature activeChar, Creature target, Skill skill)
{
WeaponTemplate weapon = activeChar.getActiveWeaponItem();
 
double base_weapon_crit = weapon == null ? 4. : weapon.getCritical();
double crit_height_bonus = 0.008 * Math.min(25, Math.max(-25, target.getZ() - activeChar.getZ())) + 1.1;
double buffs_mult = activeChar.calcStat(Stats.FATALBLOW_RATE, target, skill);
double skill_mod = skill.isBehind() ? 5 : 4; // CT 2.3 blowrate increase
 
double chance = base_weapon_crit * buffs_mult * crit_height_bonus * skill_mod;
 
if(!target.isInCombat())
chance *= 1.1;
 
switch(PositionUtils.getDirectionTo(target, activeChar))
{
case BEHIND:
chance *= 1.3;
break;
case SIDE:
chance *= 1.1;
break;
case FRONT:
if(skill.isBehind())
chance = 3.0;
break;
}
chance = Math.min(skill.isBehind() ? 100 : 80, chance);
if ((Config.SKILLS_CHANCE_SHOW) && (activeChar.isPlayer()) && (((Player)activeChar).getVarB("SkillsHideChance"))) 
{
activeChar.sendMessage(new CustomMessage("core.gameserver.skills.Formulas.Chance", (Player)activeChar, new Object[0]).addString(skill.getName()).addNumber((long) chance));
}
return Rnd.chance(chance);
}
 
/** Возвращает шанс крита в процентах */
public static double calcCrit(Creature attacker, Creature target, Skill skill, boolean blow)
{
if(attacker.isPlayer() && attacker.getActiveWeaponItem() == null)
return 0;
if(skill != null)
return skill.getCriticalRate() * (blow ? BaseStats.DEX.calcBonus(attacker) : BaseStats.STR.calcBonus(attacker)) * 0.01 * attacker.calcStat(Stats.SKILL_CRIT_CHANCE_MOD, target, skill);
 
double rate = attacker.getCriticalHit(target, null) * 0.01 * target.calcStat(Stats.CRIT_CHANCE_RECEPTIVE, attacker, skill);
 
//Баланс модуль.
boolean olympiad = attacker.getOlympiadGame() != null;
if(attacker.getPlayer() != null)
rate += Balancer.criticalRateCalculate(attacker.getPlayer().getClassId().getId(), olympiad);
 
switch(PositionUtils.getDirectionTo(target, attacker))
{
case BEHIND:
rate *= 1.4;
break;
case SIDE:
rate *= 1.2;
break;
}
 
return rate / 10;
}
 
public static boolean calcMCrit(double mRate)
{
// floating point random gives more accuracy calculation, because argument also floating point
return Rnd.get() * 100 <= Math.min(Config.LIM_MCRIT, mRate);
}
 
public static boolean calcCastBreak(Creature target, boolean crit)
{
if(target == null || target.isInvul() || target.isRaid() || !target.isCastingNow())
return false;
Skill skill = target.getCastingSkill();
if(skill != null && (skill.getSkillType() == SkillType.TAKECASTLE || skill.getSkillType() == SkillType.TAKEFORTRESS || skill.getSkillType() == SkillType.TAKEFLAG))
return false;
return Rnd.chance(target.calcStat(Stats.CAST_INTERRUPT, crit ? 75 : 10, null, skill));
}
 
/** Calculate delay (in milliseconds) before next ATTACK */
public static int calcPAtkSpd(double rate)
{
return (int) (500000.0 / rate); // в миллисекундах поэтому 500*1000
}
 
/** Calculate delay (in milliseconds) for skills cast */
public static int calcMAtkSpd(Creature attacker, Skill skill, double skillTime)
{
if(skill.isMagic())
return (int) (skillTime * 333 / Math.max(attacker.getMAtkSpd(), 1));
return (int) (skillTime * 333 / Math.max(attacker.getPAtkSpd(), 1));
}
 
/** Calculate reuse delay (in milliseconds) for skills */
public static long calcSkillReuseDelay(Creature actor, Skill skill)
{
long reuseDelay;
if(skill.isUseMacro() && actor.isPlayer() && actor.getPlayer().isUseMacro() && skill.getReuseDelay() < 9000)
reuseDelay = skill.getReuseDelay() - 3000;
else
reuseDelay = skill.getReuseDelay();
if(actor.isMonster())
reuseDelay = skill.getReuseForMonsters();
if(skill.isReuseDelayPermanent() || skill.isHandler() || skill.isItemSkill())
return reuseDelay;
if(actor.getSkillMastery(skill.getId()) == 1)
{
actor.removeSkillMastery(skill.getId());
return 0;
}
if(skill.isMagic())
return (long) actor.calcStat(Stats.MAGIC_REUSE_RATE, reuseDelay, null, skill);
return (long) actor.calcStat(Stats.PHYSIC_REUSE_RATE, reuseDelay, null, skill);
}
 
/** Returns true if hit missed (target evaded) */
public static boolean calcHitMiss(Creature attacker, Creature target)
{
boolean olympiad_caster = attacker.getOlympiadGame() != null;
boolean olympiad_target = target.getOlympiadGame() != null;
 
int accuracy = attacker.getAccuracy();
int evasion = target.getEvasionRate(attacker);
 
if(attacker.isPlayer() && target.isPlayer())
{
accuracy += Balancer.accuracyCalculate(attacker.getPlayer().getClassId().getId(), olympiad_caster);
evasion += Balancer.evasionCalculate(attacker.getPlayer().getClassId().getId(), olympiad_target);
}
 
int chanceToHit = 88 + 2 * (accuracy - evasion);
 
chanceToHit = Math.max(chanceToHit, 28);
chanceToHit = Math.min(chanceToHit, 98);
 
PositionUtils.TargetDirection direction = PositionUtils.getDirectionTo(attacker, target);
switch(direction)
{
case BEHIND:
chanceToHit *= 1.2;
break;
case SIDE:
chanceToHit *= 1.1;
break;
}
return !Rnd.chance(chanceToHit);
}
 
/** Returns true if shield defence successfull */
public static boolean calcShldUse(Creature attacker, Creature target)
{
WeaponTemplate template = target.getSecondaryWeaponItem();
if(template == null || template.getItemType() != WeaponTemplate.WeaponType.NONE)
return false;
int angle = (int) target.calcStat(Stats.SHIELD_ANGLE, attacker, null);
if(!PositionUtils.isFacing(target, attacker, angle))
return false;
return Rnd.chance((int)target.calcStat(Stats.SHIELD_RATE, attacker, null));
}
 
public static boolean calcSkillSuccess(Env env, EffectTemplate et, int spiritshot)
{
if(env.value == -1)
return true;
 
env.value = Math.max(Math.min(env.value, 100), 1); // На всякий случай
final double base = env.value; // Запоминаем базовый шанс (нужен позже)
 
final Skill skill = env.skill;
if(!skill.isOffensive())
return Rnd.chance(env.value);
 
final Creature caster = env.character;
final Creature target = env.target;
 
boolean debugCaster = false;
boolean debugTarget = false;
boolean debugGlobal = false;
if (Config.ALT_DEBUG_ENABLED)
{
// Включена ли отладка на кастере
debugCaster = caster.getPlayer() != null && caster.getPlayer().isDebug();
// Включена ли отладка на таргете
debugTarget = target.getPlayer() != null && target.getPlayer().isDebug();
// Разрешена ли отладка в PvP
final boolean debugPvP = Config.ALT_DEBUG_PVP_ENABLED && (debugCaster && debugTarget) && (!Config.ALT_DEBUG_PVP_DUEL_ONLY || (caster.getPlayer().isInDuel() && target.getPlayer().isInDuel()));
// Включаем отладку в PvP и для PvE если разрешено
debugGlobal = debugPvP || (Config.ALT_DEBUG_PVE_ENABLED && ((debugCaster && target.isMonster()) || (debugTarget && caster.isMonster())));
}
 
double statMod = 1.;
if(skill.getSaveVs() != null)
{
statMod = skill.getSaveVs().calcChanceMod(target);
env.value *= statMod; // Бонус от MEN/CON/etc
}
 
env.value = Math.max(env.value, 1);
 
double mAtkMod = 1.;
int ssMod = 0;
if(skill.isMagic()) // Этот блок только для магических скиллов
{
int mdef = Math.max(1, target.getMDef(target, skill)); // Вычисляем mDef цели
double matk = caster.getMAtk(target, skill);
 
if(skill.isSSPossible())
{
switch (spiritshot)
{
case ItemInstance.CHARGED_BLESSED_SPIRITSHOT:
ssMod = 4;
break;
case ItemInstance.CHARGED_SPIRITSHOT:
ssMod = 2;
break;
default:
ssMod = 1;
}
matk *= ssMod;
}
 
mAtkMod = Config.SKILLS_CHANCE_MOD * Math.pow(matk, Config.SKILLS_CHANCE_POW) / mdef;
 
/*
if (mAtkMod < 0.7)
mAtkMod = 0.7;
else if (mAtkMod > 1.4)
mAtkMod = 1.4;
*/
if(caster.isMonster())
env.value *= Config.SKILLS_MOB_CHANCE;
else
env.value *= mAtkMod;
env.value = Math.max(env.value, 1);
}
 
double lvlDependMod = skill.getLevelModifier();
int mLevel = skill.getMagicLevel() == 0 ? caster.getLevel() : skill.getMagicLevel(); // Разница в уровнях
if(mLevel > 0)
{
int tlevel = target.getLevel(); //35
int delta = mLevel - tlevel;  // 35 - 85 = -50
int deltamod = (delta / 5) * 5; // - 50
 
if(delta != deltamod)
if(delta < 0)
deltamod -= 5;
else if(delta > 0)
deltamod += 5;
 
env.value += deltamod;  // -50 от общего шанса.
}
 
double vulnMod = 0;
double profMod = 0;
double resMod = 1.;
double debuffMod = 1.;
if(!skill.isIgnoreResists())
{
debuffMod = 1. - target.calcStat(Stats.DEBUFF_RESIST, caster, skill) / 120.;
 
if(debuffMod != 1) // Внимание, знак был изменен на противоположный !
{
if (debuffMod == Double.NEGATIVE_INFINITY)
{
if (debugGlobal)
{
if (debugCaster)
caster.getPlayer().sendMessage("Full debuff immunity");
if (debugTarget)
target.getPlayer().sendMessage("Full debuff immunity");
}
return false;
}
if (debuffMod == Double.POSITIVE_INFINITY)
{
if (debugGlobal)
{
if (debugCaster)
caster.getPlayer().sendMessage("Full debuff vulnerability");
if (debugTarget)
target.getPlayer().sendMessage("Full debuff vulnerability");
}
return true;
}
 
debuffMod = Math.max(debuffMod, 0);
if(caster.isMonster())
env.value *= debuffMod * Config.SKILLS_DEBUFF_MOB_CHANCE;
else
env.value *= debuffMod;
}
 
SkillTrait trait = skill.getTraitType();
if (trait != null)
{
vulnMod = trait.calcVuln(env);
profMod = trait.calcProf(env);
 
final double maxResist = 90 + profMod * 0.85;
resMod = (maxResist - vulnMod) / 60.;
}
 
if(resMod != 1) // Внимание, знак был изменен на противоположный !
{
if (resMod == Double.NEGATIVE_INFINITY)
{
if (debugGlobal)
{
if (debugCaster)
caster.getPlayer().sendMessage("Full immunity");
if (debugTarget)
target.getPlayer().sendMessage("Full immunity");
}
return false;
}
if (resMod == Double.POSITIVE_INFINITY)
{
if (debugGlobal)
{
if (debugCaster)
caster.getPlayer().sendMessage("Full vulnerability");
if (debugTarget)
target.getPlayer().sendMessage("Full vulnerability");
}
return true;
}
 
resMod = Math.max(resMod, 0);
env.value *= resMod;
}
}
 
double elementMod = 0;
final Element element = skill.getElement();
if (element != Element.NONE)
{
elementMod = skill.getElementPower();
Element attackElement = getAttackElement(caster, target);
if (attackElement == element)
elementMod += caster.calcStat(element.getAttack(), 0);
 
elementMod -= target.calcStat(element.getDefence(), 0);
/*if (elementMod < 0)
elementMod = 0;
else
elementMod = Math.round(elementMod / 10);*/
elementMod = Math.round(elementMod / 10);
 
env.value += elementMod;
}
 
//if(skill.isSoulBoost()) // Бонус от душ камаелей
// env.value *= 0.85 + 0.06 * Math.min(character.getConsumedSouls(), 5);
 
env.value = Math.max(env.value, Math.min(base, Config.SKILLS_CHANCE_MIN)); // Если базовый шанс более Config.SKILLS_CHANCE_MIN, то при небольшой разнице в уровнях, делаем кап снизу.
env.value = Math.max(Math.min(env.value, Config.SKILLS_CHANCE_CAP), 1); // Применяем кап
if(caster.isPlayer() && (Config.SKILLS_CHANCE_SHOW || caster.getPlayer().isGM()))
{
Player player = caster.getPlayer();
if ((player != null) && (player.getVarB("SkillsHideChance")))
{
player.sendMessage(new CustomMessage("core.gameserver.skills.Formulas.Chance", player, new Object[0]).addString(skill.getName()).addNumber(Math.round(env.value)));
}
}
if(caster.isMonster())
env.value *= Config.SKILLS_MOB_CHANCE;
 
//Баланс модуль
env.value *= debuffBalanceModifier(caster, skill);
env.value *= balancerIncomeDebuffModifier(caster, target);
 
showDebuffChance(caster, target, skill, (int) env.value);
 
if(skill.getId() == 1169 && env.value <= 10)
env.value = 5;
 
final boolean result = Rnd.chance((int)env.value);
 
if (debugGlobal)
{
StringBuilder stat = new StringBuilder(100);
if (et == null)
stat.append(skill.getName());
else
stat.append(et._effectType.name());
stat.append(" AR:");
stat.append((int)base);
stat.append(" ");
if (skill.getSaveVs() != null)
{
stat.append(skill.getSaveVs().name());
stat.append(":");
stat.append(String.format("%1.1f", statMod));
}
if (skill.isMagic())
{
stat.append(" ");
stat.append(" mAtk:");
stat.append(String.format("%1.1f", mAtkMod));
}
if (skill.getTraitType() != null)
{
stat.append(" ");
stat.append(skill.getTraitType().name());
}
stat.append(" ");
stat.append(String.format("%1.1f", resMod));
stat.append("(");
stat.append(String.format("%1.1f", profMod));
stat.append("/");
stat.append(String.format("%1.1f", vulnMod));
if (debuffMod != 0)
{
stat.append("+");
stat.append(String.format("%1.1f", debuffMod));
}
stat.append(") lvl:");
stat.append(String.format("%1.1f", lvlDependMod));
stat.append(" elem:");
stat.append((int)elementMod);
stat.append(" Chance:");
stat.append(String.format("%1.1f", env.value));
if (!result)
stat.append(" failed");
 
// отсылаем отладочные сообщения
if (debugCaster)
caster.getPlayer().sendMessage(stat.toString());
if (debugTarget)
target.getPlayer().sendMessage(stat.toString());
}
return result;
}
 
public static boolean calcSkillSuccess(Creature player, Creature target, Skill skill, int activateRate)
{
Env env = new Env();
env.character = player;
env.target = target;
env.skill = skill;
env.value = activateRate;
return calcSkillSuccess(env, null, player.getChargedSpiritShot());
}
 
public static void calcSkillMastery(Skill skill, Creature activeChar)
{
if(skill.isHandler())
return;
 
//Skill id 330 for fighters, 331 for mages
//Actually only GM can have 2 skill masteries, so let's make them more lucky ^^
if(activeChar.getSkillLevel(331) > 0 && activeChar.calcStat(Stats.SKILL_MASTERY, activeChar.getINT(), null, skill) >= Rnd.get(1000) || activeChar.getSkillLevel(330) > 0 && activeChar.calcStat(Stats.SKILL_MASTERY, activeChar.getSTR(), null, skill) >= Rnd.get(1000))
{
//byte mastery level, 0 = no skill mastery, 1 = no reuseTime, 2 = buff duration*2, 3 = power*3
int masteryLevel;
Skill.SkillType type = skill.getSkillType();
if(skill.isMusic() || type == Skill.SkillType.BUFF || type == Skill.SkillType.HOT || type == Skill.SkillType.HEAL_PERCENT) //Hope i didn't forget skills to multiply their time
masteryLevel = 2;
else if(type == Skill.SkillType.HEAL)
masteryLevel = 3;
else
masteryLevel = 1;
if(masteryLevel > 0)
activeChar.setSkillMastery(skill.getId(), masteryLevel);
}
}
 
public static double calcDamageResists(Skill skill, Creature attacker, Creature defender, double value)
{
if(attacker == defender) // это дамаг от местности вроде ожога в лаве, наносится от своего имени
return value; // TODO: по хорошему надо учитывать защиту, но поскольку эти скиллы немагические то надо делать отдельный механизм
 
if(attacker.isBoss())
value *= Config.RATE_EPIC_ATTACK;
else if(attacker.isRaid() || attacker instanceof ReflectionBossInstance)
value *= Config.RATE_RAID_ATTACK;
 
if(defender.isBoss())
value /= Config.RATE_EPIC_DEFENSE;
else if(defender.isRaid() || defender instanceof ReflectionBossInstance)
value /= Config.RATE_RAID_DEFENSE;
 
Player pAttacker = attacker.getPlayer();
 
// если уровень игрока ниже чем на 2 и более уровней моба 78+, то его урон по мобу снижается
int diff = defender.getLevel() - (pAttacker != null ? pAttacker.getLevel() : attacker.getLevel());
if(attacker.isPlayable() && defender.isMonster() && defender.getLevel() >= 78 && diff > 2)
value *= .7 / Math.pow(diff - 2, .25);
 
Element element = Element.NONE;
double power = 0.;
 
// использует элемент умения
if(skill != null)
{
element = skill.getElement();
power = skill.getElementPower();
}
// используем максимально эффективный элемент
else
element = getAttackElement(attacker, defender);
 
if(element == Element.NONE)
return value;
 
if(pAttacker != null && pAttacker.isGM() && Config.DEBUG)
{
pAttacker.sendMessage("Element: " + element.name());
pAttacker.sendMessage("Attack: " + attacker.calcStat(element.getAttack(), power));
pAttacker.sendMessage("Defence: " + defender.calcStat(element.getDefence(), 0.));
pAttacker.sendMessage("Modifier: " + getElementMod(defender.calcStat(element.getDefence(), 0.), attacker.calcStat(element.getAttack(), power)));
}
 
return value * getElementMod(defender.calcStat(element.getDefence(), 0.), attacker.calcStat(element.getAttack(), power));
}
 
/**
* Возвращает множитель для атаки из значений атакующего и защитного элемента.
* <br /><br />
* Диапазон от 1.0 до 1.7 (Freya)
* <br /><br />
* @param defense значение защиты
* @param attack значение атаки
* @return множитель
*/
private static double getElementMod(double defense, double attack)
{
double diff = attack - defense;
if(diff <= 0)
return 1.0;
else if(diff < 50)
return 1.0 + diff * 0.003948;
else if(diff < 150)
return 1.2;
else if(diff < 300)
return 1.4;
else
return 1.7;
}
 
/**
* Возвращает максимально эффективный атрибут, при атаке цели
* @param attacker
* @param target
* @return
*/
public static Element getAttackElement(Creature attacker, Creature target)
{
double val, max = Double.MIN_VALUE;
Element result = Element.NONE;
for(Element e : Element.VALUES)
{
val = attacker.calcStat(e.getAttack(), 0., null, null);
if(val <= 0.)
continue;
 
if(target != null)
val -= target.calcStat(e.getDefence(), 0., null, null);
 
if(val > max)
{
result = e;
max = val;
}
}
 
return result;
}
 
private static void showDebuffChance(Creature caster, Creature target, Skill skill, double rate)
{
if(caster != null && caster.getPlayer() != null && caster.getPlayer().getVarB("show_chance") && (Config.SKILLS_CHANCE_SHOW || caster.getPlayer().isGM()))
caster.getPlayer().sendMessage(skill.getName() + " chance: " + (int)rate + "%");
 
if(target != null && target.getPlayer() != null && caster != target && target.getPlayer().getVarB("show_chance") && (Config.SKILLS_CHANCE_SHOW || target.getPlayer().isGM()))
target.getPlayer().sendMessage("Enemy " + skill.getName() + " chance: " + (int)rate + "%");
}
 
private static double calculateForOrdinaryAttack(Creature attacker)
{
double result = 1.;
int casterClassId = attacker.getPlayer().getClassId().getId();
 
boolean olympiad = attacker.getPlayer().getOlympiadGame() != null;
 
if(attacker.isSummon())
result *= Balancer.ordinarySummonPhysicalDamageCalculate(casterClassId, olympiad);
else
result *= Balancer.ordinaryPhysicalDamageCalculate(casterClassId, olympiad);
 
WeaponTemplate weapon = attacker.getActiveWeaponItem();
if(weapon == null) // если нет оружия, то сразу возвращаем результат
return result;
 
if(weapon.getItemType() == WeaponTemplate.WeaponType.ANCIENTSWORD)
result *= Balancer.ancientSwordMod(casterClassId, olympiad);
 
if(weapon.getItemType() == WeaponTemplate.WeaponType.CROSSBOW)
result *= Balancer.CrossbowMod(casterClassId, olympiad);
 
if(weapon.getItemType() == WeaponTemplate.WeaponType.DAGGER)
result *= Balancer.DaggerMod(casterClassId, olympiad);
 
if(weapon.getItemType() == WeaponTemplate.WeaponType.DUAL)
result *= Balancer.DualMod(casterClassId, olympiad);
 
if(weapon.getItemType() == WeaponTemplate.WeaponType.DUALDAGGER)
result *= Balancer.DualDaggerMod(casterClassId, olympiad);
 
if(weapon.getItemType() == WeaponTemplate.WeaponType.DUALFIST)
result *= Balancer.DualFistMod(casterClassId, olympiad);
 
if(weapon.getItemType() == WeaponTemplate.WeaponType.BIGBLUNT)
result *= Balancer.BigBluntMod(casterClassId, olympiad);
 
if(weapon.getItemType() == WeaponTemplate.WeaponType.BIGSWORD)
result *= Balancer.BigSwordMod(casterClassId, olympiad);
 
if(weapon.getItemType() == WeaponTemplate.WeaponType.BLUNT)
result *= Balancer.BluntMod(casterClassId, olympiad);
 
if(weapon.getItemType() == WeaponTemplate.WeaponType.BOW)
result *= Balancer.BowMod(casterClassId, olympiad);
 
if(weapon.getItemType() == WeaponTemplate.WeaponType.SWORD)
result *= Balancer.SwordMod(casterClassId, olympiad);
 
if(weapon.getItemType() == WeaponTemplate.WeaponType.ROD)
result *= Balancer.RodMod(casterClassId, olympiad);
 
if(weapon.getItemType() == WeaponTemplate.WeaponType.RAPIER)
result *= Balancer.RapierMod(casterClassId, olympiad);
 
if(weapon.getItemType() == WeaponTemplate.WeaponType.POLE)
result *= Balancer.PoleMod(casterClassId, olympiad);
 
if(weapon.getItemType() == WeaponTemplate.WeaponType.FIST)
result *= Balancer.FistMod(casterClassId, olympiad);
 
return result;
}
 
private static double calculateForSkills(Creature attacker, Skill skill, boolean blow)
{
double result = 1.;
int casterClassId = attacker.getPlayer().getClassId().getId();
 
boolean olympiad = attacker.getPlayer().getOlympiadGame() != null;
 
if(attacker.isSummon())
result *= Balancer.skillSummonPhysicalDamageCalculate(casterClassId, olympiad);
else
{
if(blow)
result *= Balancer.blowPhysicalDamageCalculate(casterClassId, olympiad);
else if(skill.isChargeBoost())
result *= Balancer.chargePhysicalDamageCalculate(casterClassId, olympiad);
else if(skill.getSkillType() == Skill.SkillType.PDAM || skill.getSkillType() == Skill.SkillType.LETHAL_SHOT)
result *= Balancer.skillPhysicalDamageCalculate(casterClassId, olympiad);
}
 
return result;
}
 
private static double balancerDamageModifier(Creature attacker, Skill skill, boolean blow)
{
double result = 1.;
if(attacker.getPlayer() == null)
return result;
 
if(skill != null)
result *= calculateForSkills(attacker, skill, blow);
else
result *= calculateForOrdinaryAttack(attacker);
return result;
}
 
private static double balancerIncomeDamageModifier(Creature attacker, Creature target)
{
double result = 1.;
if(attacker.getPlayer() == null || target.getPlayer() == null)
return result;
 
int attacker_class_id = attacker.getPlayer().getClassId().getId();
int target_class_id = target.getPlayer().getClassId().getId();
boolean olympiad = target.getOlympiadGame() != null;
 
result *= Balancer.incomeDamageCalculate(attacker_class_id, target_class_id, olympiad);
result *= Balancer.incomeCommonDamageCalculate(target_class_id, olympiad);
 
return result;
}
 
private static double balancerMagicDamageModifier(Creature attacker)
{
double result = 1.;
if(attacker.getPlayer() == null)
return result;
 
int casterClassId = attacker.getPlayer().getClassId().getId();
 
boolean olympiad = attacker.getPlayer().getOlympiadGame() != null;
if(attacker.isSummon())
result *= Balancer.skillSummonMagicalDamageCalculate(casterClassId, olympiad);
else
result *= Balancer.skillMagicalDamageCalculate(casterClassId, olympiad);
 
return result;
}
 
private static double balancerIncomeDebuffModifier(Creature attacker, Creature target)
{
double result = 1.;
if(attacker.getPlayer() == null || target.getPlayer() == null)
return result;
 
int attacker_class_id = attacker.getPlayer().getClassId().getId();
int target_class_id = target.getPlayer().getClassId().getId();
boolean olympiad = target.getOlympiadGame() != null;
 
result *= Balancer.incomeDebuffCalculate(attacker_class_id, target_class_id, olympiad);
result *= Balancer.incomeCommonDebuffCalculate(target_class_id, olympiad);
 
return result;
}
 
private static double debuffBalanceModifier(Creature caster, Skill skill)
{
if(caster == null || caster.getPlayer() == null)
return 1.;
 
int classId = caster.getPlayer().getClassId().getId();
boolean isMagic = skill.isMagic();
boolean hasTrait = skill.getTraitType() != null;
 
boolean olympiad = caster.getOlympiadGame() != null;
 
if(isMagic && !hasTrait)
return Balancer.debuffMagicalModifierCalculate(classId, olympiad);
else if(isMagic && hasTrait)
return Balancer.debuffTraitMagicalModifierCalculate(classId, olympiad);
else if(!isMagic && hasTrait)
return Balancer.debuffTraitPhysicalModifierCalculate(classId, olympiad);
else
return Balancer.debuffPhysicalModifierCalculate(classId, olympiad);
}
}

Изменено пользователем nemo

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Все. Всем спасибо разобрался сам.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти
Авторизация  

  • Последние посетители   0 пользователей онлайн

    Ни одного зарегистрированного пользователя не просматривает данную страницу

×
×
  • Создать...