L2Character attack rework.
Adapted from: L2jUnity free files.
This commit is contained in:
parent
52e54b75ce
commit
86b76fd312
@ -44,6 +44,7 @@ public final class EffectMasterHandler
|
||||
EffectHandler.getInstance().registerHandler("AttackAttribute", AttackAttribute::new);
|
||||
EffectHandler.getInstance().registerHandler("AttackAttributeAdd", AttackAttributeAdd::new);
|
||||
EffectHandler.getInstance().registerHandler("AttackBehind", AttackBehind::new);
|
||||
EffectHandler.getInstance().registerHandler("AttackDamagePosition", AttackDamagePosition::new);
|
||||
EffectHandler.getInstance().registerHandler("AttackTrait", AttackTrait::new);
|
||||
EffectHandler.getInstance().registerHandler("Backstab", Backstab::new);
|
||||
EffectHandler.getInstance().registerHandler("Betray", Betray::new);
|
||||
@ -236,6 +237,7 @@ public final class EffectMasterHandler
|
||||
EffectHandler.getInstance().registerHandler("PhysicalSoulAttack", PhysicalSoulAttack::new);
|
||||
EffectHandler.getInstance().registerHandler("PkCount", PkCount::new);
|
||||
EffectHandler.getInstance().registerHandler("Plunder", Plunder::new);
|
||||
EffectHandler.getInstance().registerHandler("PolearmSingleTarget", PolearmSingleTarget::new);
|
||||
EffectHandler.getInstance().registerHandler("ProtectionBlessing", ProtectionBlessing::new);
|
||||
EffectHandler.getInstance().registerHandler("ProtectDeathPenalty", ProtectDeathPenalty::new);
|
||||
EffectHandler.getInstance().registerHandler("PullBack", PullBack::new);
|
||||
|
53
L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/effecthandlers/AttackDamagePosition.java
vendored
Normal file
53
L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/effecthandlers/AttackDamagePosition.java
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package handlers.effecthandlers;
|
||||
|
||||
import com.l2jmobius.commons.util.MathUtil;
|
||||
import com.l2jmobius.gameserver.enums.Position;
|
||||
import com.l2jmobius.gameserver.model.StatsSet;
|
||||
import com.l2jmobius.gameserver.model.actor.L2Character;
|
||||
import com.l2jmobius.gameserver.model.effects.AbstractEffect;
|
||||
import com.l2jmobius.gameserver.model.skills.BuffInfo;
|
||||
import com.l2jmobius.gameserver.model.skills.Skill;
|
||||
import com.l2jmobius.gameserver.model.stats.Stats;
|
||||
|
||||
/**
|
||||
* @author Nik
|
||||
*/
|
||||
public class AttackDamagePosition extends AbstractEffect
|
||||
{
|
||||
protected final double _amount;
|
||||
protected final Position _position;
|
||||
|
||||
public AttackDamagePosition(StatsSet params)
|
||||
{
|
||||
_amount = params.getDouble("amount");
|
||||
_position = params.getEnum("position", Position.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pump(L2Character effected, Skill skill)
|
||||
{
|
||||
effected.getStat().mergePositionTypeValue(Stats.ATTACK_DAMAGE, _position, (_amount / 100) + 1, MathUtil::mul);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExit(BuffInfo info)
|
||||
{
|
||||
info.getEffected().getStat().mergePositionTypeValue(Stats.ATTACK_DAMAGE, _position, (_amount / 100) + 1, MathUtil::div);
|
||||
}
|
||||
}
|
@ -88,7 +88,7 @@ public final class Backstab extends AbstractEffect
|
||||
}
|
||||
|
||||
// Check if damage should be reflected
|
||||
Formulas.calcDamageReflected(effector, effected, skill, true);
|
||||
Formulas.calcCounterAttack(effector, effected, skill, true);
|
||||
|
||||
final double damageCap = effected.getStat().getValue(Stats.DAMAGE_LIMIT);
|
||||
if (damageCap > 0)
|
||||
|
@ -163,7 +163,7 @@ public final class EnergyAttack extends AbstractEffect
|
||||
damage = Math.max(0, damage);
|
||||
|
||||
// Check if damage should be reflected
|
||||
Formulas.calcDamageReflected(attacker, effected, skill, critical);
|
||||
Formulas.calcCounterAttack(attacker, effected, skill, critical);
|
||||
|
||||
final double damageCap = effected.getStat().getValue(Stats.DAMAGE_LIMIT);
|
||||
if (damageCap > 0)
|
||||
|
@ -119,7 +119,7 @@ public final class FatalBlow extends AbstractEffect
|
||||
}
|
||||
|
||||
// Check if damage should be reflected
|
||||
Formulas.calcDamageReflected(effector, effected, skill, true);
|
||||
Formulas.calcCounterAttack(effector, effected, skill, true);
|
||||
|
||||
final double damageCap = effected.getStat().getValue(Stats.DAMAGE_LIMIT);
|
||||
if (damageCap > 0)
|
||||
|
@ -115,6 +115,6 @@ public final class Lethal extends AbstractEffect
|
||||
}
|
||||
|
||||
// No matter if lethal succeeded or not, its reflected.
|
||||
Formulas.calcDamageReflected(effector, effected, skill, false);
|
||||
Formulas.calcCounterAttack(effector, effected, skill, false);
|
||||
}
|
||||
}
|
||||
|
@ -173,7 +173,7 @@ public final class PhysicalAttack extends AbstractEffect
|
||||
}
|
||||
|
||||
// Check if damage should be reflected
|
||||
Formulas.calcDamageReflected(effector, effected, skill, critical);
|
||||
Formulas.calcCounterAttack(effector, effected, skill, critical);
|
||||
final double damageCap = effected.getStat().getValue(Stats.DAMAGE_LIMIT);
|
||||
if (damageCap > 0)
|
||||
{
|
||||
|
@ -135,7 +135,7 @@ public final class PhysicalAttackHpLink extends AbstractEffect
|
||||
}
|
||||
|
||||
// Check if damage should be reflected.
|
||||
Formulas.calcDamageReflected(effector, effected, skill, critical);
|
||||
Formulas.calcCounterAttack(effector, effected, skill, critical);
|
||||
|
||||
final double damageCap = effected.getStat().getValue(Stats.DAMAGE_LIMIT);
|
||||
if (damageCap > 0)
|
||||
|
@ -145,7 +145,7 @@ public final class PhysicalAttackSaveHp extends AbstractEffect
|
||||
}
|
||||
|
||||
// Check if damage should be reflected
|
||||
Formulas.calcDamageReflected(effector, effected, skill, critical);
|
||||
Formulas.calcCounterAttack(effector, effected, skill, critical);
|
||||
|
||||
final double damageCap = effected.getStat().getValue(Stats.DAMAGE_LIMIT);
|
||||
if (damageCap > 0)
|
||||
|
@ -166,7 +166,7 @@ public final class PhysicalAttackWeaponBonus extends AbstractEffect
|
||||
}
|
||||
|
||||
// Check if damage should be reflected
|
||||
Formulas.calcDamageReflected(effector, effected, skill, critical);
|
||||
Formulas.calcCounterAttack(effector, effected, skill, critical);
|
||||
|
||||
final double damageCap = effected.getStat().getValue(Stats.DAMAGE_LIMIT);
|
||||
if (damageCap > 0)
|
||||
|
@ -160,7 +160,7 @@ public final class PhysicalSoulAttack extends AbstractEffect
|
||||
}
|
||||
|
||||
// Check if damage should be reflected
|
||||
Formulas.calcDamageReflected(effector, effected, skill, critical);
|
||||
Formulas.calcCounterAttack(effector, effected, skill, critical);
|
||||
|
||||
final double damageCap = effected.getStat().getValue(Stats.DAMAGE_LIMIT);
|
||||
if (damageCap > 0)
|
||||
|
52
L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/effecthandlers/PolearmSingleTarget.java
vendored
Normal file
52
L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/effecthandlers/PolearmSingleTarget.java
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package handlers.effecthandlers;
|
||||
|
||||
import com.l2jmobius.gameserver.model.StatsSet;
|
||||
import com.l2jmobius.gameserver.model.actor.L2Character;
|
||||
import com.l2jmobius.gameserver.model.effects.AbstractEffect;
|
||||
import com.l2jmobius.gameserver.model.skills.BuffInfo;
|
||||
import com.l2jmobius.gameserver.model.skills.Skill;
|
||||
import com.l2jmobius.gameserver.model.stats.Stats;
|
||||
|
||||
/**
|
||||
* @author Sdw
|
||||
*/
|
||||
public class PolearmSingleTarget extends AbstractEffect
|
||||
{
|
||||
public PolearmSingleTarget(StatsSet params)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart(L2Character effector, L2Character effected, Skill skill)
|
||||
{
|
||||
if (effected.isPlayer())
|
||||
{
|
||||
effected.getStat().addFixedValue(Stats.PHYSICAL_POLEARM_TARGET_SINGLE, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExit(BuffInfo info)
|
||||
{
|
||||
if (info.getEffected().isPlayer())
|
||||
{
|
||||
info.getEffected().getStat().removeFixedValue(Stats.PHYSICAL_POLEARM_TARGET_SINGLE);
|
||||
}
|
||||
}
|
||||
}
|
@ -93,7 +93,7 @@ public final class SoulBlow extends AbstractEffect
|
||||
}
|
||||
|
||||
// Check if damage should be reflected
|
||||
Formulas.calcDamageReflected(effector, effected, skill, true);
|
||||
Formulas.calcCounterAttack(effector, effected, skill, true);
|
||||
|
||||
final double damageCap = effected.getStat().getValue(Stats.DAMAGE_LIMIT);
|
||||
if (damageCap > 0)
|
||||
|
@ -98,7 +98,7 @@ public class SummonHallucination extends AbstractEffect
|
||||
clone.setSummoner(player);
|
||||
clone.spawnMe(x, y, z);
|
||||
clone.scheduleDespawn(_despawnDelay);
|
||||
clone.doAttack(effected);
|
||||
clone.doAutoAttack(effected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ public class BeastSoulShot implements IItemHandler
|
||||
if (!pet.isChargedShot(ShotType.SOULSHOTS))
|
||||
{
|
||||
activeOwner.sendMessage("Your pet uses soulshot."); // activeOwner.sendPacket(SystemMessageId.YOUR_PET_USES_SPIRITSHOT);
|
||||
pet.setChargedShot(ShotType.SOULSHOTS, true);
|
||||
pet.chargeShot(ShotType.SOULSHOTS);
|
||||
// Visual effect change if player has equipped Ruby lvl 3 or higher
|
||||
if (activeOwner.getActiveRubyJewel() != null)
|
||||
{
|
||||
@ -138,7 +138,7 @@ public class BeastSoulShot implements IItemHandler
|
||||
if (!s.isChargedShot(ShotType.SOULSHOTS))
|
||||
{
|
||||
activeOwner.sendMessage("Your servitor uses soulshot."); // activeOwner.sendPacket(SystemMessageId.YOUR_PET_USES_SPIRITSHOT);
|
||||
s.setChargedShot(ShotType.SOULSHOTS, true);
|
||||
s.chargeShot(ShotType.SOULSHOTS);
|
||||
// Visual effect change if player has equipped Ruby lvl 3 or higher
|
||||
if (activeOwner.getActiveRubyJewel() != null)
|
||||
{
|
||||
|
@ -122,7 +122,7 @@ public class BeastSpiritShot implements IItemHandler
|
||||
if (!pet.isChargedShot(shotType))
|
||||
{
|
||||
activeOwner.sendMessage(isBlessed ? "Your pet uses blessed spiritshot." : "Your pet uses spiritshot."); // activeOwner.sendPacket(SystemMessageId.YOUR_PET_USES_SPIRITSHOT);
|
||||
pet.setChargedShot(shotType, true);
|
||||
pet.chargeShot(shotType);
|
||||
// Visual effect change if player has equipped Sapphire lvl 3 or higher
|
||||
if (activeOwner.getActiveShappireJewel() != null)
|
||||
{
|
||||
@ -140,7 +140,7 @@ public class BeastSpiritShot implements IItemHandler
|
||||
if (!s.isChargedShot(shotType))
|
||||
{
|
||||
activeOwner.sendMessage(isBlessed ? "Your servitor uses blessed spiritshot." : "Your servitor uses spiritshot."); // activeOwner.sendPacket(SystemMessageId.YOUR_PET_USES_SPIRITSHOT);
|
||||
s.setChargedShot(shotType, true);
|
||||
s.chargeShot(shotType);
|
||||
// Visual effect change if player has equipped Sapphire lvl 3 or higher
|
||||
if (activeOwner.getActiveShappireJewel() != null)
|
||||
{
|
||||
|
@ -104,7 +104,7 @@ public class BlessedSoulShots implements IItemHandler
|
||||
return false;
|
||||
}
|
||||
// Charge soul shot
|
||||
weaponInst.setChargedShot(ShotType.BLESSED_SOULSHOTS, true);
|
||||
activeChar.chargeShot(ShotType.BLESSED_SOULSHOTS);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -94,7 +94,7 @@ public class BlessedSpiritShot implements IItemHandler
|
||||
}
|
||||
|
||||
// Charge Spirit shot
|
||||
activeChar.setChargedShot(ShotType.SPIRITSHOTS, true);
|
||||
activeChar.chargeShot(ShotType.SPIRITSHOTS);
|
||||
|
||||
// Send message to client
|
||||
if (!activeChar.getAutoSoulShot().contains(item.getId()))
|
||||
|
@ -75,7 +75,7 @@ public class FishShots implements IItemHandler
|
||||
return false;
|
||||
}
|
||||
|
||||
activeChar.setChargedShot(ShotType.FISH_SOULSHOTS, true);
|
||||
activeChar.chargeShot(ShotType.FISH_SOULSHOTS);
|
||||
activeChar.destroyItemWithoutTrace("Consume", item.getObjectId(), 1, null, false);
|
||||
final L2Object oldTarget = activeChar.getTarget();
|
||||
activeChar.setTarget(activeChar);
|
||||
|
@ -101,7 +101,7 @@ public class SoulShots implements IItemHandler
|
||||
return false;
|
||||
}
|
||||
// Charge soul shot
|
||||
weaponInst.setChargedShot(ShotType.SOULSHOTS, true);
|
||||
activeChar.chargeShot(ShotType.SOULSHOTS);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -94,7 +94,7 @@ public class SpiritShot implements IItemHandler
|
||||
}
|
||||
|
||||
// Charge Spirit shot
|
||||
activeChar.setChargedShot(ShotType.SPIRITSHOTS, true);
|
||||
activeChar.chargeShot(ShotType.SPIRITSHOTS);
|
||||
|
||||
// Send message to client
|
||||
if (!activeChar.getAutoSoulShot().contains(item.getId()))
|
||||
|
@ -865,14 +865,14 @@ public final class MemoryOfDisaster extends AbstractInstance
|
||||
{
|
||||
npc.broadcastSay(ChatType.NPC_GENERAL, NpcStringId.NO_WAY2);
|
||||
npc.doDie(null);
|
||||
attacker.doAttack(world.getNpc(SILVERA));
|
||||
attacker.doAutoAttack(world.getNpc(SILVERA));
|
||||
break;
|
||||
}
|
||||
case SILVERA:
|
||||
{
|
||||
npc.broadcastSay(ChatType.NPC_GENERAL, NpcStringId.MY_GOD);
|
||||
npc.doDie(null);
|
||||
world.getNpc(SIEGE_GOLEM).doAttack(attacker);
|
||||
world.getNpc(SIEGE_GOLEM).doAutoAttack(attacker);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -821,13 +821,7 @@
|
||||
<hitTime>2000</hitTime>
|
||||
<targetType>NONE</targetType>
|
||||
<effects>
|
||||
<effect name="HitNumber">
|
||||
<amount>1</amount>
|
||||
<mode>DIFF</mode>
|
||||
<weaponType>
|
||||
<item>POLE</item>
|
||||
</weaponType>
|
||||
</effect>
|
||||
<effect name="PolearmSingleTarget" />
|
||||
<effect name="Accuracy">
|
||||
<amount>
|
||||
<value level="1">2</value>
|
||||
|
@ -902,7 +902,15 @@
|
||||
<!-- Rear Damage + 3%. -->
|
||||
<operateType>P</operateType>
|
||||
<icon>icon.skill0030</icon>
|
||||
<!-- TODO: Handle rear damage stat -->
|
||||
<effects>
|
||||
<effect name="AttackDamagePosition">
|
||||
<amount>
|
||||
<value level="1">3</value>
|
||||
<value level="2">6</value>
|
||||
</amount>
|
||||
<position>BACK</position>
|
||||
</effect>
|
||||
</effects>
|
||||
</skill>
|
||||
<skill id="19145" toLevel="2" name="Noble Death Whisper">
|
||||
<!-- Physical Critical Damage + 3%. -->
|
||||
|
@ -13,6 +13,7 @@ AreaDamage: Topography (Danger Zone) resistance stat.
|
||||
AttackAttribute: Stat that increases specific attack attribute.
|
||||
AttackAttributeAdd: Stat that increases all attack attribute.
|
||||
AttackBehind: Enables all attacks regardless of position to land towards the back.
|
||||
AttackDamagePosition: Bonus damage depending on player position towards the target.
|
||||
AttackTrait: Stat that manages all attack traits.
|
||||
Backstab: Inflicts physical damage according to the backstab formula.
|
||||
Betray: Causes the target summon to attack its owner.
|
||||
@ -205,6 +206,7 @@ PhysicalSkillPower: Physical Skill Power stat.
|
||||
PhysicalSoulAttack: Physical attack depending on souls.
|
||||
PkCount: Increases PK kills.
|
||||
Plunder: Takes bonus item from monster. Sweep effect.
|
||||
PolearmSingleTarget: Effect used by Focus Attack (317) skill.
|
||||
ProtectDeathPenalty: Unable to acquire death penalty.
|
||||
ProtectionBlessing: Keeps you safe from a PK if he is 10 levels or higher.
|
||||
PullBack: Pulls the target towards you.
|
||||
|
@ -78,7 +78,7 @@ public class DoppelgangerAI extends L2CharacterAI
|
||||
return;
|
||||
}
|
||||
clientStopMoving(null);
|
||||
_actor.doAttack(attackTarget);
|
||||
_actor.doAutoAttack(attackTarget);
|
||||
}
|
||||
|
||||
private void thinkCast()
|
||||
|
@ -218,7 +218,7 @@ public class FriendlyNpcAI extends L2AttackableAI
|
||||
return;
|
||||
}
|
||||
|
||||
_actor.doAttack(originalAttackTarget);
|
||||
_actor.doAutoAttack(originalAttackTarget);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -994,7 +994,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
}
|
||||
|
||||
// Attacks target
|
||||
_actor.doAttack(target);
|
||||
_actor.doAutoAttack(target);
|
||||
}
|
||||
|
||||
private boolean checkSkillTarget(Skill skill, L2Object target)
|
||||
|
@ -223,7 +223,7 @@ public final class L2ControllableMobAI extends L2AttackableAI
|
||||
|
||||
return;
|
||||
}
|
||||
_actor.doAttack(target);
|
||||
_actor.doAutoAttack(target);
|
||||
}
|
||||
|
||||
protected void thinkForceAttack()
|
||||
@ -264,7 +264,7 @@ public final class L2ControllableMobAI extends L2AttackableAI
|
||||
return;
|
||||
}
|
||||
|
||||
_actor.doAttack(getForcedTarget());
|
||||
_actor.doAutoAttack(getForcedTarget());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -364,7 +364,7 @@ public final class L2ControllableMobAI extends L2AttackableAI
|
||||
}
|
||||
}
|
||||
|
||||
_actor.doAttack(target);
|
||||
_actor.doAutoAttack(target);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -262,7 +262,7 @@ public class L2PlayerAI extends L2PlayableAI
|
||||
return;
|
||||
}
|
||||
|
||||
_actor.doAttack((L2Character) target);
|
||||
_actor.doAutoAttack((L2Character) target);
|
||||
}
|
||||
|
||||
private void thinkCast()
|
||||
|
@ -107,7 +107,7 @@ public class L2SummonAI extends L2PlayableAI implements Runnable
|
||||
return;
|
||||
}
|
||||
clientStopMoving(null);
|
||||
_actor.doAttack(attackTarget);
|
||||
_actor.doAutoAttack(attackTarget);
|
||||
}
|
||||
|
||||
private void thinkCast()
|
||||
@ -276,7 +276,7 @@ public class L2SummonAI extends L2PlayableAI implements Runnable
|
||||
final L2Summon summon = getActor();
|
||||
if ((summon.getOwner() != null) && (summon.getOwner() != attacker) && !summon.isMoving() && summon.canAttack(attacker, false) && summon.getOwner().isInsideRadius(_actor, 2 * AVOID_RADIUS, true, false))
|
||||
{
|
||||
summon.doAttack(attacker);
|
||||
summon.doAutoAttack(attacker);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -245,18 +245,13 @@ public class Fishing
|
||||
}
|
||||
|
||||
double chance = baitData.getChance();
|
||||
final boolean isCharged = _player.isChargedShot(ShotType.FISH_SOULSHOTS);
|
||||
if (isCharged)
|
||||
if (_player.isChargedShot(ShotType.FISH_SOULSHOTS))
|
||||
{
|
||||
chance *= 1.50; // +50 % chance to win
|
||||
chance *= 1.5; // +50 % chance to win
|
||||
}
|
||||
|
||||
if (Rnd.get(0, 100) <= chance)
|
||||
{
|
||||
if (isCharged)
|
||||
{
|
||||
_player.setChargedShot(ShotType.FISH_SOULSHOTS, false);
|
||||
}
|
||||
reelIn(FishingEndReason.WIN, true);
|
||||
}
|
||||
else
|
||||
|
@ -16,6 +16,8 @@
|
||||
*/
|
||||
package com.l2jmobius.gameserver.model;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import com.l2jmobius.gameserver.enums.AttackType;
|
||||
import com.l2jmobius.gameserver.model.actor.L2Character;
|
||||
|
||||
@ -24,6 +26,7 @@ import com.l2jmobius.gameserver.model.actor.L2Character;
|
||||
*/
|
||||
public class Hit
|
||||
{
|
||||
private final WeakReference<L2Object> _target;
|
||||
private final int _targetId;
|
||||
private final int _damage;
|
||||
private final int _ssGrade;
|
||||
@ -31,6 +34,7 @@ public class Hit
|
||||
|
||||
public Hit(L2Object target, int damage, boolean miss, boolean crit, byte shld, boolean soulshot, int ssGrade)
|
||||
{
|
||||
_target = new WeakReference<>(target);
|
||||
_targetId = target.getObjectId();
|
||||
_damage = damage;
|
||||
_ssGrade = ssGrade;
|
||||
@ -62,6 +66,11 @@ public class Hit
|
||||
_flags |= type.getMask();
|
||||
}
|
||||
|
||||
public L2Object getTarget()
|
||||
{
|
||||
return _target.get();
|
||||
}
|
||||
|
||||
public int getTargetId()
|
||||
{
|
||||
return _targetId;
|
||||
@ -81,4 +90,24 @@ public class Hit
|
||||
{
|
||||
return _ssGrade;
|
||||
}
|
||||
|
||||
public boolean isMiss()
|
||||
{
|
||||
return (AttackType.MISSED.getMask() & _flags) != 0;
|
||||
}
|
||||
|
||||
public boolean isCritical()
|
||||
{
|
||||
return (AttackType.CRITICAL.getMask() & _flags) != 0;
|
||||
}
|
||||
|
||||
public boolean isShotUsed()
|
||||
{
|
||||
return (AttackType.SHOT_USED.getMask() & _flags) != 0;
|
||||
}
|
||||
|
||||
public boolean isBlocked()
|
||||
{
|
||||
return (AttackType.BLOCKED.getMask() & _flags) != 0;
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.l2jmobius.gameserver.enums.InstanceType;
|
||||
import com.l2jmobius.gameserver.enums.ShotType;
|
||||
import com.l2jmobius.gameserver.handler.ActionHandler;
|
||||
import com.l2jmobius.gameserver.handler.ActionShiftHandler;
|
||||
import com.l2jmobius.gameserver.handler.IActionHandler;
|
||||
@ -463,35 +462,6 @@ public abstract class L2Object extends ListenersContainer implements IIdentifiab
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if current object has charged shot.
|
||||
* @param type of the shot to be checked.
|
||||
* @return {@code true} if the object has charged shot
|
||||
*/
|
||||
public boolean isChargedShot(ShotType type)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Charging shot into the current object.
|
||||
* @param type of the shot to be charged.
|
||||
* @param charged
|
||||
*/
|
||||
public void setChargedShot(ShotType type, boolean charged)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to recharge a shot.
|
||||
* @param physical skill are using Soul shots.
|
||||
* @param magical skill are using Spirit shots.
|
||||
* @param fish
|
||||
*/
|
||||
public void rechargeShots(boolean physical, boolean magical, boolean fish)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param <T>
|
||||
* @param script
|
||||
|
@ -128,7 +128,7 @@ public class ShortCuts implements IRestorable
|
||||
{
|
||||
if (_owner.removeAutoSoulShot(item.getId()))
|
||||
{
|
||||
_owner.sendPacket(new ExAutoSoulShot(item.getId(), 0));
|
||||
_owner.sendPacket(new ExAutoSoulShot(item.getId(), false, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -137,7 +137,7 @@ public class ShortCuts implements IRestorable
|
||||
|
||||
for (int shotId : _owner.getAutoSoulShot())
|
||||
{
|
||||
_owner.sendPacket(new ExAutoSoulShot(shotId, 1));
|
||||
_owner.sendPacket(new ExAutoSoulShot(shotId, true, 0));
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -144,7 +144,6 @@ public class L2Npc extends L2Character
|
||||
private int _spiritshotamount = 0;
|
||||
private int _displayEffect = 0;
|
||||
|
||||
private int _shotsMask = 0;
|
||||
private int _killingBlowWeaponId;
|
||||
|
||||
private int _cloneObjId; // Used in NpcInfo packet to clone the specified player.
|
||||
@ -1410,47 +1409,43 @@ public class L2Npc extends L2Character
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChargedShot(ShotType type)
|
||||
public void rechargeShots(boolean physical, boolean magic, boolean fish)
|
||||
{
|
||||
return (_shotsMask & type.getMask()) == type.getMask();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChargedShot(ShotType type, boolean charged)
|
||||
{
|
||||
if (charged)
|
||||
if (isFakePlayer() && Config.FAKE_PLAYER_USE_SHOTS)
|
||||
{
|
||||
_shotsMask |= type.getMask();
|
||||
if (physical)
|
||||
{
|
||||
Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 9193, 1, 0, 0), 600);
|
||||
chargeShot(ShotType.SOULSHOTS);
|
||||
}
|
||||
if (magic)
|
||||
{
|
||||
Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 9195, 1, 0, 0), 600);
|
||||
chargeShot(ShotType.SPIRITSHOTS);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_shotsMask &= ~type.getMask();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rechargeShots(boolean physical, boolean magic, boolean fish)
|
||||
{
|
||||
if (physical && (_soulshotamount > 0))
|
||||
{
|
||||
if (Rnd.get(100) > getTemplate().getSoulShotChance())
|
||||
if (physical && (_soulshotamount > 0))
|
||||
{
|
||||
return;
|
||||
if (Rnd.get(100) > getTemplate().getSoulShotChance())
|
||||
{
|
||||
return;
|
||||
}
|
||||
_soulshotamount--;
|
||||
Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2154, 1, 0, 0), 600);
|
||||
chargeShot(ShotType.SOULSHOTS);
|
||||
}
|
||||
_soulshotamount--;
|
||||
Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2154, 1, 0, 0), 600);
|
||||
setChargedShot(ShotType.SOULSHOTS, true);
|
||||
}
|
||||
|
||||
if (magic && (_spiritshotamount > 0))
|
||||
{
|
||||
if (Rnd.get(100) > getTemplate().getSpiritShotChance())
|
||||
if (magic && (_spiritshotamount > 0))
|
||||
{
|
||||
return;
|
||||
if (Rnd.get(100) > getTemplate().getSpiritShotChance())
|
||||
{
|
||||
return;
|
||||
}
|
||||
_spiritshotamount--;
|
||||
Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2061, 1, 0, 0), 600);
|
||||
chargeShot(ShotType.SPIRITSHOTS);
|
||||
}
|
||||
_spiritshotamount--;
|
||||
Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2061, 1, 0, 0), 600);
|
||||
setChargedShot(ShotType.SPIRITSHOTS, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,6 @@ import com.l2jmobius.gameserver.data.xml.impl.ExperienceData;
|
||||
import com.l2jmobius.gameserver.datatables.ItemTable;
|
||||
import com.l2jmobius.gameserver.enums.InstanceType;
|
||||
import com.l2jmobius.gameserver.enums.Race;
|
||||
import com.l2jmobius.gameserver.enums.ShotType;
|
||||
import com.l2jmobius.gameserver.enums.Team;
|
||||
import com.l2jmobius.gameserver.handler.IItemHandler;
|
||||
import com.l2jmobius.gameserver.handler.ItemHandler;
|
||||
@ -77,7 +76,6 @@ public abstract class L2Summon extends L2Playable
|
||||
private boolean _follow = true;
|
||||
private boolean _previousFollowStatus = true;
|
||||
protected boolean _restoreSummon = true;
|
||||
private int _shotsMask = 0;
|
||||
private int _summonPoints = 0;
|
||||
|
||||
// @formatter:off
|
||||
@ -1030,25 +1028,6 @@ public abstract class L2Summon extends L2Playable
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChargedShot(ShotType type)
|
||||
{
|
||||
return (_shotsMask & type.getMask()) == type.getMask();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChargedShot(ShotType type, boolean charged)
|
||||
{
|
||||
if (charged)
|
||||
{
|
||||
_shotsMask |= type.getMask();
|
||||
}
|
||||
else
|
||||
{
|
||||
_shotsMask &= ~type.getMask();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rechargeShots(boolean physical, boolean magic, boolean fish)
|
||||
{
|
||||
|
@ -91,7 +91,7 @@ public final class L2DoorInstance extends L2Character
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAttack(L2Character target)
|
||||
public void doAutoAttack(L2Character target)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -92,7 +92,6 @@ import com.l2jmobius.gameserver.enums.PrivateStoreType;
|
||||
import com.l2jmobius.gameserver.enums.Race;
|
||||
import com.l2jmobius.gameserver.enums.Sex;
|
||||
import com.l2jmobius.gameserver.enums.ShortcutType;
|
||||
import com.l2jmobius.gameserver.enums.ShotType;
|
||||
import com.l2jmobius.gameserver.enums.StatusUpdateType;
|
||||
import com.l2jmobius.gameserver.enums.SubclassInfoType;
|
||||
import com.l2jmobius.gameserver.enums.Team;
|
||||
@ -4643,9 +4642,9 @@ public final class L2PcInstance extends L2Playable
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAttack(L2Character target)
|
||||
public void doAutoAttack(L2Character target)
|
||||
{
|
||||
super.doAttack(target);
|
||||
super.doAutoAttack(target);
|
||||
setRecentFakeDeath(false);
|
||||
if (target.isFakePlayer())
|
||||
{
|
||||
@ -8788,7 +8787,8 @@ public final class L2PcInstance extends L2Playable
|
||||
if (_activeSoulShots.contains(itemId))
|
||||
{
|
||||
removeAutoSoulShot(itemId);
|
||||
sendPacket(new ExAutoSoulShot(itemId, 0));
|
||||
sendPacket(new ExAutoSoulShot(itemId, false, 0));
|
||||
|
||||
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.THE_AUTOMATIC_USE_OF_S1_HAS_BEEN_DEACTIVATED);
|
||||
sm.addItemName(itemId);
|
||||
sendPacket(sm);
|
||||
@ -8804,7 +8804,7 @@ public final class L2PcInstance extends L2Playable
|
||||
{
|
||||
for (int itemId : _activeSoulShots)
|
||||
{
|
||||
sendPacket(new ExAutoSoulShot(itemId, 0));
|
||||
sendPacket(new ExAutoSoulShot(itemId, false, 0));
|
||||
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.THE_AUTOMATIC_USE_OF_S1_HAS_BEEN_DEACTIVATED);
|
||||
sm.addItemName(itemId);
|
||||
sendPacket(sm);
|
||||
@ -13065,23 +13065,6 @@ public final class L2PcInstance extends L2Playable
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChargedShot(ShotType type)
|
||||
{
|
||||
final L2ItemInstance weapon = getActiveWeaponInstance();
|
||||
return (weapon != null) && weapon.isChargedShot(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChargedShot(ShotType type, boolean charged)
|
||||
{
|
||||
final L2ItemInstance weapon = getActiveWeaponInstance();
|
||||
if (weapon != null)
|
||||
{
|
||||
weapon.setChargedShot(type, charged);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param skillId the display skill Id
|
||||
* @return the custom skill
|
||||
|
@ -195,7 +195,7 @@ public final class L2StaticObjectInstance extends L2Character
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAttack(L2Character target)
|
||||
public void doAutoAttack(L2Character target)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1,61 +0,0 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jmobius.gameserver.model.actor.tasks.character;
|
||||
|
||||
import com.l2jmobius.gameserver.model.actor.L2Character;
|
||||
|
||||
/**
|
||||
* Task launching the function onHitTimer().<br>
|
||||
* <B><U>Actions</U>:</B>
|
||||
* <ul>
|
||||
* <li>If the attacker/target is dead or use fake death, notify the AI with EVT_CANCEL and send a Server->Client packet ActionFailed (if attacker is a L2PcInstance)</li>
|
||||
* <li>If attack isn't aborted, send a message system (critical hit, missed...) to attacker/target if they are L2PcInstance</li>
|
||||
* <li>If attack isn't aborted and hit isn't missed, reduce HP of the target and calculate reflection damage to reduce HP of attacker if necessary</li>
|
||||
* <li>if attack isn't aborted and hit isn't missed, manage attack or cast break of the target (calculating rate, sending message...)</li>
|
||||
* </ul>
|
||||
* @author xban1x
|
||||
*/
|
||||
public final class HitTask implements Runnable
|
||||
{
|
||||
private final L2Character _character;
|
||||
private final L2Character _hitTarget;
|
||||
private final int _damage;
|
||||
private final boolean _crit;
|
||||
private final boolean _miss;
|
||||
private final byte _shld;
|
||||
private final boolean _soulshot;
|
||||
|
||||
public HitTask(L2Character character, L2Character target, int damage, boolean crit, boolean miss, boolean soulshot, byte shld)
|
||||
{
|
||||
_character = character;
|
||||
_hitTarget = target;
|
||||
_damage = damage;
|
||||
_crit = crit;
|
||||
_shld = shld;
|
||||
_miss = miss;
|
||||
_soulshot = soulshot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
if (_character != null)
|
||||
{
|
||||
_character.onHitTimer(_hitTarget, _damage, _crit, _miss, _soulshot, _shld);
|
||||
}
|
||||
}
|
||||
}
|
@ -19,6 +19,7 @@ package com.l2jmobius.gameserver.model.events.impl.character;
|
||||
import com.l2jmobius.gameserver.model.actor.L2Character;
|
||||
import com.l2jmobius.gameserver.model.events.EventType;
|
||||
import com.l2jmobius.gameserver.model.events.impl.IBaseEvent;
|
||||
import com.l2jmobius.gameserver.model.skills.Skill;
|
||||
|
||||
/**
|
||||
* An instantly executed event when L2Character is attacked by L2Character.
|
||||
@ -28,11 +29,13 @@ public class OnCreatureAttack implements IBaseEvent
|
||||
{
|
||||
private final L2Character _attacker;
|
||||
private final L2Character _target;
|
||||
private final Skill _skill;
|
||||
|
||||
public OnCreatureAttack(L2Character attacker, L2Character target)
|
||||
public OnCreatureAttack(L2Character attacker, L2Character target, Skill skill)
|
||||
{
|
||||
_attacker = attacker;
|
||||
_target = target;
|
||||
_skill = skill;
|
||||
}
|
||||
|
||||
public final L2Character getAttacker()
|
||||
@ -45,6 +48,11 @@ public class OnCreatureAttack implements IBaseEvent
|
||||
return _target;
|
||||
}
|
||||
|
||||
public final Skill getSkill()
|
||||
{
|
||||
return _skill;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventType getType()
|
||||
{
|
||||
|
@ -45,7 +45,6 @@ import com.l2jmobius.gameserver.enums.AttributeType;
|
||||
import com.l2jmobius.gameserver.enums.InstanceType;
|
||||
import com.l2jmobius.gameserver.enums.ItemLocation;
|
||||
import com.l2jmobius.gameserver.enums.ItemSkillType;
|
||||
import com.l2jmobius.gameserver.enums.ShotType;
|
||||
import com.l2jmobius.gameserver.enums.UserInfoType;
|
||||
import com.l2jmobius.gameserver.geoengine.GeoEngine;
|
||||
import com.l2jmobius.gameserver.idfactory.IdFactory;
|
||||
@ -173,8 +172,6 @@ public final class L2ItemInstance extends L2Object
|
||||
|
||||
private final DropProtection _dropProtection = new DropProtection();
|
||||
|
||||
private int _shotsMask = 0;
|
||||
|
||||
private final List<Options> _enchantOptions = new ArrayList<>();
|
||||
|
||||
/**
|
||||
@ -1399,7 +1396,6 @@ public final class L2ItemInstance extends L2Object
|
||||
final InventoryUpdate iu = new InventoryUpdate();
|
||||
for (L2ItemInstance item : unequiped)
|
||||
{
|
||||
item.unChargeAllShots();
|
||||
iu.addModifiedItem(item);
|
||||
}
|
||||
player.sendInventoryUpdate(iu);
|
||||
@ -1827,7 +1823,6 @@ public final class L2ItemInstance extends L2Object
|
||||
final InventoryUpdate iu = new InventoryUpdate();
|
||||
for (L2ItemInstance item : unequiped)
|
||||
{
|
||||
item.unChargeAllShots();
|
||||
iu.addModifiedItem(item);
|
||||
}
|
||||
player.sendInventoryUpdate(iu);
|
||||
@ -2077,30 +2072,6 @@ public final class L2ItemInstance extends L2Object
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChargedShot(ShotType type)
|
||||
{
|
||||
return (_shotsMask & type.getMask()) == type.getMask();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChargedShot(ShotType type, boolean charged)
|
||||
{
|
||||
if (charged)
|
||||
{
|
||||
_shotsMask |= type.getMask();
|
||||
}
|
||||
else
|
||||
{
|
||||
_shotsMask &= ~type.getMask();
|
||||
}
|
||||
}
|
||||
|
||||
public void unChargeAllShots()
|
||||
{
|
||||
_shotsMask = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns enchant effect object for this item
|
||||
* @return enchanteffect
|
||||
|
@ -271,11 +271,7 @@ public abstract class AbstractOlympiadGame
|
||||
player.disableAutoShotsAll();
|
||||
|
||||
// Discharge any active shots
|
||||
final L2ItemInstance item = player.getActiveWeaponInstance();
|
||||
if (item != null)
|
||||
{
|
||||
item.unChargeAllShots();
|
||||
}
|
||||
player.unchargeAllShots();
|
||||
|
||||
// enable skills with cool time <= 15 minutes
|
||||
for (Skill skill : player.getAllSkills())
|
||||
|
@ -1514,11 +1514,11 @@ public final class Skill implements IIdentifiable
|
||||
{
|
||||
if (useSpiritShot())
|
||||
{
|
||||
caster.setChargedShot(caster.isChargedShot(ShotType.BLESSED_SPIRITSHOTS) ? ShotType.BLESSED_SPIRITSHOTS : ShotType.SPIRITSHOTS, false);
|
||||
caster.unchargeShot(caster.isChargedShot(ShotType.BLESSED_SPIRITSHOTS) ? ShotType.BLESSED_SPIRITSHOTS : ShotType.SPIRITSHOTS);
|
||||
}
|
||||
else if (useSoulShot())
|
||||
{
|
||||
caster.setChargedShot(caster.isChargedShot(ShotType.BLESSED_SOULSHOTS) ? ShotType.BLESSED_SOULSHOTS : ShotType.SOULSHOTS, false);
|
||||
caster.unchargeShot(caster.isChargedShot(ShotType.BLESSED_SOULSHOTS) ? ShotType.BLESSED_SOULSHOTS : ShotType.SOULSHOTS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -217,11 +217,11 @@ public class SkillChannelizer implements Runnable
|
||||
// Reduce shots.
|
||||
if (skill.useSpiritShot())
|
||||
{
|
||||
_channelizer.setChargedShot(_channelizer.isChargedShot(ShotType.BLESSED_SPIRITSHOTS) ? ShotType.BLESSED_SPIRITSHOTS : ShotType.SPIRITSHOTS, false);
|
||||
_channelizer.unchargeShot(_channelizer.isChargedShot(ShotType.BLESSED_SPIRITSHOTS) ? ShotType.BLESSED_SPIRITSHOTS : ShotType.SPIRITSHOTS);
|
||||
}
|
||||
else
|
||||
{
|
||||
_channelizer.setChargedShot(_channelizer.isChargedShot(ShotType.BLESSED_SOULSHOTS) ? ShotType.BLESSED_SOULSHOTS : ShotType.SOULSHOTS, false);
|
||||
_channelizer.unchargeShot(_channelizer.isChargedShot(ShotType.BLESSED_SOULSHOTS) ? ShotType.BLESSED_SOULSHOTS : ShotType.SOULSHOTS);
|
||||
}
|
||||
|
||||
// Shots are re-charged every cast.
|
||||
|
@ -37,6 +37,7 @@ import com.l2jmobius.gameserver.model.actor.instance.L2StaticObjectInstance;
|
||||
import com.l2jmobius.gameserver.model.cubic.CubicInstance;
|
||||
import com.l2jmobius.gameserver.model.effects.EffectFlag;
|
||||
import com.l2jmobius.gameserver.model.effects.L2EffectType;
|
||||
import com.l2jmobius.gameserver.model.interfaces.ILocational;
|
||||
import com.l2jmobius.gameserver.model.items.L2Armor;
|
||||
import com.l2jmobius.gameserver.model.items.L2Item;
|
||||
import com.l2jmobius.gameserver.model.items.L2Weapon;
|
||||
@ -271,8 +272,12 @@ public final class Formulas
|
||||
}
|
||||
|
||||
// Autoattack critical rate.
|
||||
// It is capped to 500, but unbound by positional critical rate and level diff bonus.
|
||||
rate *= activeChar.getStat().getPositionTypeValue(Stats.CRITICAL_RATE, Position.getPosition(activeChar, target));
|
||||
// Even though, visible critical rate is capped to 500, you can reach higher than 50% chance with position and level modifiers.
|
||||
// TODO: Find retail-like calculation for criticalRateMod.
|
||||
final double criticalRateMod = (target.getStat().getValue(Stats.DEFENCE_CRITICAL_RATE, rate) + target.getStat().getValue(Stats.DEFENCE_CRITICAL_RATE_ADD, 0)) / 10;
|
||||
final double criticalLocBonus = calcCriticalPositionBonus(activeChar, target);
|
||||
final double criticalHeightBonus = calcCriticalHeightBonus(activeChar, target);
|
||||
rate = criticalLocBonus * criticalRateMod * criticalHeightBonus;
|
||||
|
||||
// In retail, it appears that when you are higher level attacking lower level mobs, your critical rate is much higher.
|
||||
// Level 91 attacking level 1 appear that nearly all hits are critical. Unconfirmed for skills and pvp.
|
||||
@ -286,6 +291,37 @@ public final class Formulas
|
||||
return finalRate > Rnd.get(1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default (10% for side, 30% for back) positional critical rate bonus and multiplies it by any buffs that give positional critical rate bonus.
|
||||
* @param activeChar the attacker.
|
||||
* @param target the target.
|
||||
* @return a multiplier representing the positional critical rate bonus. Autoattacks for example get this bonus on top of the already capped critical rate of 500.
|
||||
*/
|
||||
public static double calcCriticalPositionBonus(L2Character activeChar, L2Character target)
|
||||
{
|
||||
final Position position = target.isAffected(EffectFlag.ATTACK_BEHIND) ? Position.BACK : Position.getPosition(activeChar, target);
|
||||
switch (position)
|
||||
{
|
||||
case SIDE: // 10% Critical Chance bonus when attacking from side.
|
||||
{
|
||||
return 1.1 * activeChar.getStat().getPositionTypeValue(Stats.CRITICAL_RATE, Position.SIDE);
|
||||
}
|
||||
case BACK: // 30% Critical Chance bonus when attacking from back.
|
||||
{
|
||||
return 1.3 * activeChar.getStat().getPositionTypeValue(Stats.CRITICAL_RATE, Position.BACK);
|
||||
}
|
||||
default: // No Critical Chance bonus when attacking from front.
|
||||
{
|
||||
return activeChar.getStat().getPositionTypeValue(Stats.CRITICAL_RATE, Position.FRONT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static double calcCriticalHeightBonus(ILocational from, ILocational target)
|
||||
{
|
||||
return ((((CommonUtil.constrain(from.getZ() - target.getZ(), -25, 25) * 4) / 5) + 10) / 100) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param attacker
|
||||
* @param target
|
||||
@ -403,16 +439,6 @@ public final class Formulas
|
||||
return Rnd.get(100) < rate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param attackSpeed the attack speed of the Creature.
|
||||
* @return {@code 500000 / attackSpeed}.
|
||||
*/
|
||||
public static int calculateTimeBetweenAttacks(int attackSpeed)
|
||||
{
|
||||
// Measured Nov 2015 by Nik. Formula: atk.spd/500 = hits per second.
|
||||
return Math.max(50, (500000 / attackSpeed));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate delay (in milliseconds) for skills cast
|
||||
* @param attacker
|
||||
@ -1023,7 +1049,7 @@ public final class Formulas
|
||||
return 1;
|
||||
}
|
||||
|
||||
public static void calcDamageReflected(L2Character attacker, L2Character target, Skill skill, boolean crit)
|
||||
public static void calcCounterAttack(L2Character attacker, L2Character target, Skill skill, boolean crit)
|
||||
{
|
||||
// Only melee skills can be reflected
|
||||
if (skill.isMagic() || (skill.getCastRange() > MELEE_ATTACK_RANGE))
|
||||
@ -1049,7 +1075,7 @@ public final class Formulas
|
||||
|
||||
double counterdmg = ((target.getPAtk() * 873) / attacker.getPDef()); // Old: (((target.getPAtk(attacker) * 10.0) * 70.0) / attacker.getPDef(target));
|
||||
counterdmg *= calcWeaponTraitBonus(attacker, target);
|
||||
counterdmg *= calcGeneralTraitBonus(attacker, target, skill.getTraitType(), false);
|
||||
counterdmg *= calcGeneralTraitBonus(attacker, target, skill.getTraitType(), true);
|
||||
counterdmg *= calcAttributeBonus(attacker, target, skill);
|
||||
|
||||
attacker.reduceCurrentHp(counterdmg, target, skill);
|
||||
@ -1086,35 +1112,37 @@ public final class Formulas
|
||||
return cha.getStat().getValue(Stats.FALL, (fallHeight * cha.getMaxHp()) / 1000.0);
|
||||
}
|
||||
|
||||
public static boolean calcBlowSuccess(L2Character activeChar, L2Character target, Skill skill, double blowChance)
|
||||
/**
|
||||
* Basic chance formula:<br>
|
||||
* <ul>
|
||||
* <li>chance = weapon_critical * dex_bonus * crit_height_bonus * crit_pos_bonus * effect_bonus * fatal_blow_rate</li>
|
||||
* <li>weapon_critical = (12 for daggers)</li>
|
||||
* <li>dex_bonus = dex modifier bonus for current dex (Seems unused in GOD, so its not used in formula).</li>
|
||||
* <li>crit_height_bonus = (z_diff * 4 / 5 + 10) / 100 + 1 or alternatively (z_diff * 0.008) + 1.1. Be aware of z_diff constraint of -25 to 25.</li>
|
||||
* <li>crit_pos_bonus = crit_pos(front = 1, side = 1.1, back = 1.3) * p_critical_rate_position_bonus</li>
|
||||
* <li>effect_bonus = (p2 + 100) / 100, p2 - 2nd param of effect. Blow chance of effect.</li>
|
||||
* </ul>
|
||||
* Chance cannot be higher than 80%.
|
||||
* @param activeChar
|
||||
* @param target
|
||||
* @param skill
|
||||
* @param chanceBoost
|
||||
* @return
|
||||
*/
|
||||
public static boolean calcBlowSuccess(L2Character activeChar, L2Character target, Skill skill, double chanceBoost)
|
||||
{
|
||||
final double weaponCritical = 12; // Dagger weapon critical mod is 12... TODO: Make it work for other weapons.
|
||||
final L2Weapon weapon = activeChar.getActiveWeaponItem();
|
||||
final double weaponCritical = weapon != null ? weapon.getStats(Stats.CRITICAL_RATE, activeChar.getTemplate().getBaseCritRate()) : activeChar.getTemplate().getBaseCritRate();
|
||||
// double dexBonus = BaseStats.DEX.calcBonus(activeChar); Not used in GOD
|
||||
final double critHeightBonus = ((((CommonUtil.constrain(activeChar.getZ() - target.getZ(), -25, 25) * 4) / 5) + 10) / 100) + 1;
|
||||
final Position position = Position.getPosition(activeChar, target);
|
||||
final double criticalPosition = position == Position.BACK ? 1.3 : position == Position.SIDE ? 1.1 : 1; // 30% chance from back, 10% chance from side.
|
||||
final double criticalPositionMod = criticalPosition * activeChar.getStat().getPositionTypeValue(Stats.CRITICAL_RATE, position);
|
||||
final double critHeightBonus = calcCriticalHeightBonus(activeChar, target);
|
||||
final double criticalPosition = calcCriticalPositionBonus(activeChar, target); // 30% chance from back, 10% chance from side. Include buffs that give positional crit rate.
|
||||
final double chanceBoostMod = (100 + chanceBoost) / 100;
|
||||
final double blowRateMod = activeChar.getStat().getValue(Stats.BLOW_RATE, 1);
|
||||
blowChance = (weaponCritical + blowChance) * 10;
|
||||
|
||||
final double rate = blowChance * critHeightBonus * criticalPositionMod * blowRateMod;
|
||||
|
||||
// Debug
|
||||
if (activeChar.isDebug())
|
||||
{
|
||||
final StatsSet set = new StatsSet();
|
||||
set.set("weaponCritical", weaponCritical);
|
||||
set.set("critHeightBonus", critHeightBonus);
|
||||
set.set("criticalPosition", criticalPosition);
|
||||
set.set("criticalPositionMod", criticalPositionMod);
|
||||
set.set("blowRate", blowRateMod);
|
||||
set.set("blowChance", blowChance);
|
||||
set.set("rate(max 800 of 1000)", rate);
|
||||
Debug.sendSkillDebug(activeChar, target, skill, set);
|
||||
}
|
||||
final double rate = criticalPosition * critHeightBonus * weaponCritical * chanceBoostMod * blowRateMod;
|
||||
|
||||
// Blow rate is capped at 80%
|
||||
return Rnd.get(1000) < Math.min(rate, 800);
|
||||
return Rnd.get(100) < Math.min(rate, 80);
|
||||
}
|
||||
|
||||
public static List<BuffInfo> calcCancelStealEffects(L2Character activeChar, L2Character target, Skill skill, DispelSlotType slot, int rate, int max)
|
||||
@ -1224,6 +1252,12 @@ public final class Formulas
|
||||
*/
|
||||
public static boolean calcProbability(double baseChance, L2Character attacker, L2Character target, Skill skill)
|
||||
{
|
||||
// Skills without set probability should only test against trait invulnerability.
|
||||
if (Double.isNaN(baseChance))
|
||||
{
|
||||
return calcGeneralTraitBonus(attacker, target, skill.getTraitType(), true) > 0;
|
||||
}
|
||||
|
||||
// Outdated formula: return Rnd.get(100) < ((((((skill.getMagicLevel() + baseChance) - target.getLevel()) + 30) - target.getINT()) * calcAttributeBonus(attacker, target, skill)) * calcGeneralTraitBonus(attacker, target, skill.getTraitType(), false));
|
||||
// TODO: Find more retail-like formula
|
||||
return Rnd.get(100) < (((((skill.getMagicLevel() + baseChance) - target.getLevel()) - getAbnormalResist(skill.getBasicProperty(), target)) * calcAttributeBonus(attacker, target, skill)) * calcGeneralTraitBonus(attacker, target, skill.getTraitType(), false));
|
||||
@ -1486,7 +1520,7 @@ public final class Formulas
|
||||
*/
|
||||
public static boolean calcStunBreak(L2Character activeChar)
|
||||
{
|
||||
// Check if target is stunned and 10% chance.
|
||||
// Check if target is stunned and 10% chance (retail is 14% and 35% on crit?)
|
||||
if (activeChar.hasBlockActions() && (Rnd.get(10) == 0))
|
||||
{
|
||||
// Any stun that has double duration due to skill mastery, doesn't get removed until its time reaches the usual abnormal time.
|
||||
@ -1497,8 +1531,18 @@ public final class Formulas
|
||||
|
||||
public static boolean calcRealTargetBreak()
|
||||
{
|
||||
// Real Target breaks at 5% probability.
|
||||
return Rnd.get(20) == 0;
|
||||
// Real Target breaks at 3% (Rnd > 3.0 doesn't break) probability.
|
||||
return Rnd.get(100) <= 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param attackSpeed the attack speed of the Creature.
|
||||
* @return {@code 500000 / attackSpeed}.
|
||||
*/
|
||||
public static int calculateTimeBetweenAttacks(int attackSpeed)
|
||||
{
|
||||
// Measured Nov 2015 by Nik. Formula: atk.spd/500 = hits per second.
|
||||
return Math.max(50, (500000 / attackSpeed));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -143,6 +143,7 @@ public enum Stats
|
||||
PHYSICAL_ATTACK_RANGE("pAtkRange", new PRangeFinalizer()),
|
||||
MAGIC_ATTACK_RANGE("mAtkRange"),
|
||||
ATTACK_COUNT_MAX("atkCountMax"),
|
||||
PHYSICAL_POLEARM_TARGET_SINGLE("polearmSingleTarget"),
|
||||
// Run speed, walk & escape speed are calculated proportionally, magic speed is a buff
|
||||
MOVE_SPEED("moveSpeed"),
|
||||
RUN_SPEED("runSpd", new SpeedFinalizer()),
|
||||
@ -266,7 +267,8 @@ public enum Stats
|
||||
// Which base stat ordinal should alter skill critical formula.
|
||||
STAT_BONUS_SKILL_CRITICAL("statSkillCritical"),
|
||||
STAT_BONUS_SPEED("statSpeed"),
|
||||
SHOTS_BONUS("shotBonus", new ShotsBonusFinalizer());
|
||||
SHOTS_BONUS("shotBonus", new ShotsBonusFinalizer()),
|
||||
ATTACK_DAMAGE("attackDamage");
|
||||
|
||||
static final Logger LOGGER = Logger.getLogger(Stats.class.getName());
|
||||
public static final int NUM_STATS = values().length;
|
||||
|
@ -18,6 +18,7 @@ package com.l2jmobius.gameserver.network.clientpackets;
|
||||
|
||||
import com.l2jmobius.commons.network.PacketReader;
|
||||
import com.l2jmobius.gameserver.enums.PrivateStoreType;
|
||||
import com.l2jmobius.gameserver.enums.ShotType;
|
||||
import com.l2jmobius.gameserver.model.actor.L2Summon;
|
||||
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
|
||||
import com.l2jmobius.gameserver.model.items.L2Item;
|
||||
@ -34,6 +35,7 @@ import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
|
||||
public final class RequestAutoSoulShot implements IClientIncomingPacket
|
||||
{
|
||||
private int _itemId;
|
||||
private boolean _enable;
|
||||
private int _type;
|
||||
|
||||
@Override
|
||||
@ -41,6 +43,7 @@ public final class RequestAutoSoulShot implements IClientIncomingPacket
|
||||
{
|
||||
_itemId = packet.readD();
|
||||
_type = packet.readD();
|
||||
_enable = _type == 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -61,7 +64,7 @@ public final class RequestAutoSoulShot implements IClientIncomingPacket
|
||||
return;
|
||||
}
|
||||
|
||||
if (_type == 1)
|
||||
if (_enable)
|
||||
{
|
||||
if (!activeChar.getInventory().canManipulateWithItemId(item.getId()))
|
||||
{
|
||||
@ -114,23 +117,34 @@ public final class RequestAutoSoulShot implements IClientIncomingPacket
|
||||
|
||||
// Activate shots
|
||||
activeChar.addAutoSoulShot(_itemId);
|
||||
client.sendPacket(new ExAutoSoulShot(_itemId, _type));
|
||||
|
||||
// Send message
|
||||
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.THE_AUTOMATIC_USE_OF_S1_HAS_BEEN_ACTIVATED);
|
||||
sm.addItemName(item);
|
||||
client.sendPacket(sm);
|
||||
client.sendPacket(new ExAutoSoulShot(_itemId, _enable, _type));
|
||||
|
||||
// Recharge summon's shots
|
||||
final L2Summon pet = activeChar.getPet();
|
||||
if (pet != null)
|
||||
{
|
||||
// Send message
|
||||
if (!pet.isChargedShot(item.getItem().getDefaultAction() == ActionType.SUMMON_SOULSHOT ? ShotType.SOULSHOTS : ((item.getId() == 6647) || (item.getId() == 20334)) ? ShotType.BLESSED_SPIRITSHOTS : ShotType.SPIRITSHOTS))
|
||||
{
|
||||
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.THE_AUTOMATIC_USE_OF_S1_HAS_BEEN_ACTIVATED);
|
||||
sm.addItemName(item);
|
||||
client.sendPacket(sm);
|
||||
}
|
||||
// Charge
|
||||
pet.rechargeShots(isSoulshot, isSpiritshot, false);
|
||||
}
|
||||
activeChar.getServitors().values().forEach(s ->
|
||||
for (L2Summon summon : activeChar.getServitors().values())
|
||||
{
|
||||
s.rechargeShots(isSoulshot, isSpiritshot, false);
|
||||
});
|
||||
// Send message
|
||||
if (!summon.isChargedShot(item.getItem().getDefaultAction() == ActionType.SUMMON_SOULSHOT ? ShotType.SOULSHOTS : ((item.getId() == 6647) || (item.getId() == 20334)) ? ShotType.BLESSED_SPIRITSHOTS : ShotType.SPIRITSHOTS))
|
||||
{
|
||||
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.THE_AUTOMATIC_USE_OF_S1_HAS_BEEN_ACTIVATED);
|
||||
sm.addItemName(item);
|
||||
client.sendPacket(sm);
|
||||
}
|
||||
// Charge
|
||||
summon.rechargeShots(isSoulshot, isSpiritshot, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -150,7 +164,7 @@ public final class RequestAutoSoulShot implements IClientIncomingPacket
|
||||
|
||||
// Activate shots
|
||||
activeChar.addAutoSoulShot(_itemId);
|
||||
client.sendPacket(new ExAutoSoulShot(_itemId, _type));
|
||||
client.sendPacket(new ExAutoSoulShot(_itemId, _enable, _type));
|
||||
|
||||
// Send message
|
||||
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.THE_AUTOMATIC_USE_OF_S1_HAS_BEEN_ACTIVATED);
|
||||
@ -165,7 +179,7 @@ public final class RequestAutoSoulShot implements IClientIncomingPacket
|
||||
{
|
||||
// Cancel auto shots
|
||||
activeChar.removeAutoSoulShot(_itemId);
|
||||
client.sendPacket(new ExAutoSoulShot(_itemId, _type));
|
||||
client.sendPacket(new ExAutoSoulShot(_itemId, _enable, _type));
|
||||
|
||||
// Send message
|
||||
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.THE_AUTOMATIC_USE_OF_S1_HAS_BEEN_DEACTIVATED);
|
||||
|
@ -180,11 +180,7 @@ public final class RequestDropItem implements IClientIncomingPacket
|
||||
|
||||
if (item.isEquipped())
|
||||
{
|
||||
final L2ItemInstance[] unequiped = activeChar.getInventory().unEquipItemInSlotAndRecord(item.getLocationSlot());
|
||||
for (L2ItemInstance itm : unequiped)
|
||||
{
|
||||
itm.unChargeAllShots();
|
||||
}
|
||||
activeChar.getInventory().unEquipItemInSlot(item.getLocationSlot());
|
||||
activeChar.broadcastUserInfo();
|
||||
activeChar.sendItemList(true);
|
||||
}
|
||||
|
@ -29,8 +29,6 @@ import com.l2jmobius.gameserver.network.OutgoingPackets;
|
||||
public class Attack implements IClientOutgoingPacket
|
||||
{
|
||||
private final int _attackerObjId;
|
||||
private final boolean _soulshot;
|
||||
private final int _ssGrade;
|
||||
private final Location _attackerLoc;
|
||||
private final Location _targetLoc;
|
||||
private final List<Hit> _hits = new ArrayList<>();
|
||||
@ -38,29 +36,26 @@ public class Attack implements IClientOutgoingPacket
|
||||
/**
|
||||
* @param attacker
|
||||
* @param target
|
||||
* @param useShots
|
||||
* @param ssGrade
|
||||
*/
|
||||
public Attack(L2Character attacker, L2Character target, boolean useShots, int ssGrade)
|
||||
public Attack(L2Character attacker, L2Character target)
|
||||
{
|
||||
_attackerObjId = attacker.getObjectId();
|
||||
_soulshot = useShots;
|
||||
_ssGrade = Math.min(ssGrade, 6);
|
||||
_attackerLoc = new Location(attacker);
|
||||
_targetLoc = new Location(target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds hit to the attack (Attacks such as dual dagger/sword/fist has two hits)
|
||||
* @param target
|
||||
* @param damage
|
||||
* @param miss
|
||||
* @param crit
|
||||
* @param shld
|
||||
* @param hit
|
||||
*/
|
||||
public void addHit(L2Character target, int damage, boolean miss, boolean crit, byte shld)
|
||||
public void addHit(Hit hit)
|
||||
{
|
||||
_hits.add(new Hit(target, damage, miss, crit, shld, _soulshot, _ssGrade));
|
||||
_hits.add(hit);
|
||||
}
|
||||
|
||||
public List<Hit> getHits()
|
||||
{
|
||||
return _hits;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -71,14 +66,6 @@ public class Attack implements IClientOutgoingPacket
|
||||
return !_hits.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if attack has soul shot charged.
|
||||
*/
|
||||
public boolean hasSoulshot()
|
||||
{
|
||||
return _soulshot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes current hit
|
||||
* @param packet
|
||||
|
@ -22,11 +22,19 @@ import com.l2jmobius.gameserver.network.OutgoingPackets;
|
||||
public class ExAutoSoulShot implements IClientOutgoingPacket
|
||||
{
|
||||
private final int _itemId;
|
||||
@SuppressWarnings("unused")
|
||||
private final boolean _enable;
|
||||
private final int _type;
|
||||
|
||||
public ExAutoSoulShot(int itemId, int type)
|
||||
/**
|
||||
* @param itemId
|
||||
* @param enable
|
||||
* @param type
|
||||
*/
|
||||
public ExAutoSoulShot(int itemId, boolean enable, int type)
|
||||
{
|
||||
_itemId = itemId;
|
||||
_enable = enable;
|
||||
_type = type;
|
||||
}
|
||||
|
||||
@ -36,6 +44,7 @@ public class ExAutoSoulShot implements IClientOutgoingPacket
|
||||
OutgoingPackets.EX_AUTO_SOUL_SHOT.writeId(packet);
|
||||
|
||||
packet.writeD(_itemId);
|
||||
// packet.writeD(_enable ? 0x01 : 0x00);
|
||||
packet.writeD(_type);
|
||||
return true;
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ public final class EffectMasterHandler
|
||||
EffectHandler.getInstance().registerHandler("AttackAttribute", AttackAttribute::new);
|
||||
EffectHandler.getInstance().registerHandler("AttackAttributeAdd", AttackAttributeAdd::new);
|
||||
EffectHandler.getInstance().registerHandler("AttackBehind", AttackBehind::new);
|
||||
EffectHandler.getInstance().registerHandler("AttackDamagePosition", AttackDamagePosition::new);
|
||||
EffectHandler.getInstance().registerHandler("AttackTrait", AttackTrait::new);
|
||||
EffectHandler.getInstance().registerHandler("Backstab", Backstab::new);
|
||||
EffectHandler.getInstance().registerHandler("Betray", Betray::new);
|
||||
@ -236,6 +237,7 @@ public final class EffectMasterHandler
|
||||
EffectHandler.getInstance().registerHandler("PhysicalSoulAttack", PhysicalSoulAttack::new);
|
||||
EffectHandler.getInstance().registerHandler("PkCount", PkCount::new);
|
||||
EffectHandler.getInstance().registerHandler("Plunder", Plunder::new);
|
||||
EffectHandler.getInstance().registerHandler("PolearmSingleTarget", PolearmSingleTarget::new);
|
||||
EffectHandler.getInstance().registerHandler("ProtectionBlessing", ProtectionBlessing::new);
|
||||
EffectHandler.getInstance().registerHandler("ProtectDeathPenalty", ProtectDeathPenalty::new);
|
||||
EffectHandler.getInstance().registerHandler("PullBack", PullBack::new);
|
||||
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package handlers.effecthandlers;
|
||||
|
||||
import com.l2jmobius.commons.util.MathUtil;
|
||||
import com.l2jmobius.gameserver.enums.Position;
|
||||
import com.l2jmobius.gameserver.model.StatsSet;
|
||||
import com.l2jmobius.gameserver.model.actor.L2Character;
|
||||
import com.l2jmobius.gameserver.model.effects.AbstractEffect;
|
||||
import com.l2jmobius.gameserver.model.skills.BuffInfo;
|
||||
import com.l2jmobius.gameserver.model.skills.Skill;
|
||||
import com.l2jmobius.gameserver.model.stats.Stats;
|
||||
|
||||
/**
|
||||
* @author Nik
|
||||
*/
|
||||
public class AttackDamagePosition extends AbstractEffect
|
||||
{
|
||||
protected final double _amount;
|
||||
protected final Position _position;
|
||||
|
||||
public AttackDamagePosition(StatsSet params)
|
||||
{
|
||||
_amount = params.getDouble("amount");
|
||||
_position = params.getEnum("position", Position.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pump(L2Character effected, Skill skill)
|
||||
{
|
||||
effected.getStat().mergePositionTypeValue(Stats.ATTACK_DAMAGE, _position, (_amount / 100) + 1, MathUtil::mul);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExit(BuffInfo info)
|
||||
{
|
||||
info.getEffected().getStat().mergePositionTypeValue(Stats.ATTACK_DAMAGE, _position, (_amount / 100) + 1, MathUtil::div);
|
||||
}
|
||||
}
|
@ -88,7 +88,7 @@ public final class Backstab extends AbstractEffect
|
||||
}
|
||||
|
||||
// Check if damage should be reflected
|
||||
Formulas.calcDamageReflected(effector, effected, skill, true);
|
||||
Formulas.calcCounterAttack(effector, effected, skill, true);
|
||||
|
||||
final double damageCap = effected.getStat().getValue(Stats.DAMAGE_LIMIT);
|
||||
if (damageCap > 0)
|
||||
|
@ -163,7 +163,7 @@ public final class EnergyAttack extends AbstractEffect
|
||||
damage = Math.max(0, damage);
|
||||
|
||||
// Check if damage should be reflected
|
||||
Formulas.calcDamageReflected(attacker, effected, skill, critical);
|
||||
Formulas.calcCounterAttack(attacker, effected, skill, critical);
|
||||
|
||||
final double damageCap = effected.getStat().getValue(Stats.DAMAGE_LIMIT);
|
||||
if (damageCap > 0)
|
||||
|
@ -119,7 +119,7 @@ public final class FatalBlow extends AbstractEffect
|
||||
}
|
||||
|
||||
// Check if damage should be reflected
|
||||
Formulas.calcDamageReflected(effector, effected, skill, true);
|
||||
Formulas.calcCounterAttack(effector, effected, skill, true);
|
||||
|
||||
final double damageCap = effected.getStat().getValue(Stats.DAMAGE_LIMIT);
|
||||
if (damageCap > 0)
|
||||
|
@ -115,6 +115,6 @@ public final class Lethal extends AbstractEffect
|
||||
}
|
||||
|
||||
// No matter if lethal succeeded or not, its reflected.
|
||||
Formulas.calcDamageReflected(effector, effected, skill, false);
|
||||
Formulas.calcCounterAttack(effector, effected, skill, false);
|
||||
}
|
||||
}
|
||||
|
@ -173,7 +173,7 @@ public final class PhysicalAttack extends AbstractEffect
|
||||
}
|
||||
|
||||
// Check if damage should be reflected
|
||||
Formulas.calcDamageReflected(effector, effected, skill, critical);
|
||||
Formulas.calcCounterAttack(effector, effected, skill, critical);
|
||||
final double damageCap = effected.getStat().getValue(Stats.DAMAGE_LIMIT);
|
||||
if (damageCap > 0)
|
||||
{
|
||||
|
@ -135,7 +135,7 @@ public final class PhysicalAttackHpLink extends AbstractEffect
|
||||
}
|
||||
|
||||
// Check if damage should be reflected.
|
||||
Formulas.calcDamageReflected(effector, effected, skill, critical);
|
||||
Formulas.calcCounterAttack(effector, effected, skill, critical);
|
||||
|
||||
final double damageCap = effected.getStat().getValue(Stats.DAMAGE_LIMIT);
|
||||
if (damageCap > 0)
|
||||
|
@ -145,7 +145,7 @@ public final class PhysicalAttackSaveHp extends AbstractEffect
|
||||
}
|
||||
|
||||
// Check if damage should be reflected
|
||||
Formulas.calcDamageReflected(effector, effected, skill, critical);
|
||||
Formulas.calcCounterAttack(effector, effected, skill, critical);
|
||||
|
||||
final double damageCap = effected.getStat().getValue(Stats.DAMAGE_LIMIT);
|
||||
if (damageCap > 0)
|
||||
|
@ -166,7 +166,7 @@ public final class PhysicalAttackWeaponBonus extends AbstractEffect
|
||||
}
|
||||
|
||||
// Check if damage should be reflected
|
||||
Formulas.calcDamageReflected(effector, effected, skill, critical);
|
||||
Formulas.calcCounterAttack(effector, effected, skill, critical);
|
||||
|
||||
final double damageCap = effected.getStat().getValue(Stats.DAMAGE_LIMIT);
|
||||
if (damageCap > 0)
|
||||
|
@ -160,7 +160,7 @@ public final class PhysicalSoulAttack extends AbstractEffect
|
||||
}
|
||||
|
||||
// Check if damage should be reflected
|
||||
Formulas.calcDamageReflected(effector, effected, skill, critical);
|
||||
Formulas.calcCounterAttack(effector, effected, skill, critical);
|
||||
|
||||
final double damageCap = effected.getStat().getValue(Stats.DAMAGE_LIMIT);
|
||||
if (damageCap > 0)
|
||||
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package handlers.effecthandlers;
|
||||
|
||||
import com.l2jmobius.gameserver.model.StatsSet;
|
||||
import com.l2jmobius.gameserver.model.actor.L2Character;
|
||||
import com.l2jmobius.gameserver.model.effects.AbstractEffect;
|
||||
import com.l2jmobius.gameserver.model.skills.BuffInfo;
|
||||
import com.l2jmobius.gameserver.model.skills.Skill;
|
||||
import com.l2jmobius.gameserver.model.stats.Stats;
|
||||
|
||||
/**
|
||||
* @author Sdw
|
||||
*/
|
||||
public class PolearmSingleTarget extends AbstractEffect
|
||||
{
|
||||
public PolearmSingleTarget(StatsSet params)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart(L2Character effector, L2Character effected, Skill skill)
|
||||
{
|
||||
if (effected.isPlayer())
|
||||
{
|
||||
effected.getStat().addFixedValue(Stats.PHYSICAL_POLEARM_TARGET_SINGLE, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExit(BuffInfo info)
|
||||
{
|
||||
if (info.getEffected().isPlayer())
|
||||
{
|
||||
info.getEffected().getStat().removeFixedValue(Stats.PHYSICAL_POLEARM_TARGET_SINGLE);
|
||||
}
|
||||
}
|
||||
}
|
@ -93,7 +93,7 @@ public final class SoulBlow extends AbstractEffect
|
||||
}
|
||||
|
||||
// Check if damage should be reflected
|
||||
Formulas.calcDamageReflected(effector, effected, skill, true);
|
||||
Formulas.calcCounterAttack(effector, effected, skill, true);
|
||||
|
||||
final double damageCap = effected.getStat().getValue(Stats.DAMAGE_LIMIT);
|
||||
if (damageCap > 0)
|
||||
|
@ -98,7 +98,7 @@ public class SummonHallucination extends AbstractEffect
|
||||
clone.setSummoner(player);
|
||||
clone.spawnMe(x, y, z);
|
||||
clone.scheduleDespawn(_despawnDelay);
|
||||
clone.doAttack(effected);
|
||||
clone.doAutoAttack(effected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -865,14 +865,14 @@ public final class MemoryOfDisaster extends AbstractInstance
|
||||
{
|
||||
npc.broadcastSay(ChatType.NPC_GENERAL, NpcStringId.NO_WAY2);
|
||||
npc.doDie(null);
|
||||
attacker.doAttack(world.getNpc(SILVERA));
|
||||
attacker.doAutoAttack(world.getNpc(SILVERA));
|
||||
break;
|
||||
}
|
||||
case SILVERA:
|
||||
{
|
||||
npc.broadcastSay(ChatType.NPC_GENERAL, NpcStringId.MY_GOD);
|
||||
npc.doDie(null);
|
||||
world.getNpc(SIEGE_GOLEM).doAttack(attacker);
|
||||
world.getNpc(SIEGE_GOLEM).doAutoAttack(attacker);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -821,13 +821,7 @@
|
||||
<hitTime>2000</hitTime>
|
||||
<targetType>NONE</targetType>
|
||||
<effects>
|
||||
<effect name="HitNumber">
|
||||
<amount>1</amount>
|
||||
<mode>DIFF</mode>
|
||||
<weaponType>
|
||||
<item>POLE</item>
|
||||
</weaponType>
|
||||
</effect>
|
||||
<effect name="PolearmSingleTarget" />
|
||||
<effect name="Accuracy">
|
||||
<amount>
|
||||
<value level="1">2</value>
|
||||
|
@ -902,7 +902,15 @@
|
||||
<!-- Rear Damage + 3%. -->
|
||||
<operateType>P</operateType>
|
||||
<icon>icon.skill0030</icon>
|
||||
<!-- TODO: Handle rear damage stat -->
|
||||
<effects>
|
||||
<effect name="AttackDamagePosition">
|
||||
<amount>
|
||||
<value level="1">3</value>
|
||||
<value level="2">6</value>
|
||||
</amount>
|
||||
<position>BACK</position>
|
||||
</effect>
|
||||
</effects>
|
||||
</skill>
|
||||
<skill id="19145" toLevel="2" name="Noble Death Whisper">
|
||||
<!-- Physical Critical Damage + 3%. -->
|
||||
|
@ -13,6 +13,7 @@ AreaDamage: Topography (Danger Zone) resistance stat.
|
||||
AttackAttribute: Stat that increases specific attack attribute.
|
||||
AttackAttributeAdd: Stat that increases all attack attribute.
|
||||
AttackBehind: Enables all attacks regardless of position to land towards the back.
|
||||
AttackDamagePosition: Bonus damage depending on player position towards the target.
|
||||
AttackTrait: Stat that manages all attack traits.
|
||||
Backstab: Inflicts physical damage according to the backstab formula.
|
||||
Betray: Causes the target summon to attack its owner.
|
||||
@ -205,6 +206,7 @@ PhysicalSkillPower: Physical Skill Power stat.
|
||||
PhysicalSoulAttack: Physical attack depending on souls.
|
||||
PkCount: Increases PK kills.
|
||||
Plunder: Takes bonus item from monster. Sweep effect.
|
||||
PolearmSingleTarget: Effect used by Focus Attack (317) skill.
|
||||
ProtectDeathPenalty: Unable to acquire death penalty.
|
||||
ProtectionBlessing: Keeps you safe from a PK if he is 10 levels or higher.
|
||||
PullBack: Pulls the target towards you.
|
||||
|
@ -78,7 +78,7 @@ public class DoppelgangerAI extends L2CharacterAI
|
||||
return;
|
||||
}
|
||||
clientStopMoving(null);
|
||||
_actor.doAttack(attackTarget);
|
||||
_actor.doAutoAttack(attackTarget);
|
||||
}
|
||||
|
||||
private void thinkCast()
|
||||
|
@ -218,7 +218,7 @@ public class FriendlyNpcAI extends L2AttackableAI
|
||||
return;
|
||||
}
|
||||
|
||||
_actor.doAttack(originalAttackTarget);
|
||||
_actor.doAutoAttack(originalAttackTarget);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -994,7 +994,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
}
|
||||
|
||||
// Attacks target
|
||||
_actor.doAttack(target);
|
||||
_actor.doAutoAttack(target);
|
||||
}
|
||||
|
||||
private boolean checkSkillTarget(Skill skill, L2Object target)
|
||||
|
@ -223,7 +223,7 @@ public final class L2ControllableMobAI extends L2AttackableAI
|
||||
|
||||
return;
|
||||
}
|
||||
_actor.doAttack(target);
|
||||
_actor.doAutoAttack(target);
|
||||
}
|
||||
|
||||
protected void thinkForceAttack()
|
||||
@ -264,7 +264,7 @@ public final class L2ControllableMobAI extends L2AttackableAI
|
||||
return;
|
||||
}
|
||||
|
||||
_actor.doAttack(getForcedTarget());
|
||||
_actor.doAutoAttack(getForcedTarget());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -364,7 +364,7 @@ public final class L2ControllableMobAI extends L2AttackableAI
|
||||
}
|
||||
}
|
||||
|
||||
_actor.doAttack(target);
|
||||
_actor.doAutoAttack(target);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -262,7 +262,7 @@ public class L2PlayerAI extends L2PlayableAI
|
||||
return;
|
||||
}
|
||||
|
||||
_actor.doAttack((L2Character) target);
|
||||
_actor.doAutoAttack((L2Character) target);
|
||||
}
|
||||
|
||||
private void thinkCast()
|
||||
|
@ -107,7 +107,7 @@ public class L2SummonAI extends L2PlayableAI implements Runnable
|
||||
return;
|
||||
}
|
||||
clientStopMoving(null);
|
||||
_actor.doAttack(attackTarget);
|
||||
_actor.doAutoAttack(attackTarget);
|
||||
}
|
||||
|
||||
private void thinkCast()
|
||||
@ -276,7 +276,7 @@ public class L2SummonAI extends L2PlayableAI implements Runnable
|
||||
final L2Summon summon = getActor();
|
||||
if ((summon.getOwner() != null) && (summon.getOwner() != attacker) && !summon.isMoving() && summon.canAttack(attacker, false) && summon.getOwner().isInsideRadius(_actor, 2 * AVOID_RADIUS, true, false))
|
||||
{
|
||||
summon.doAttack(attacker);
|
||||
summon.doAutoAttack(attacker);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,8 @@
|
||||
*/
|
||||
package com.l2jmobius.gameserver.model;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import com.l2jmobius.gameserver.enums.AttackType;
|
||||
import com.l2jmobius.gameserver.model.actor.L2Character;
|
||||
|
||||
@ -24,6 +26,7 @@ import com.l2jmobius.gameserver.model.actor.L2Character;
|
||||
*/
|
||||
public class Hit
|
||||
{
|
||||
private final WeakReference<L2Object> _target;
|
||||
private final int _targetId;
|
||||
private final int _damage;
|
||||
private final int _ssGrade;
|
||||
@ -31,6 +34,7 @@ public class Hit
|
||||
|
||||
public Hit(L2Object target, int damage, boolean miss, boolean crit, byte shld, boolean soulshot, int ssGrade)
|
||||
{
|
||||
_target = new WeakReference<>(target);
|
||||
_targetId = target.getObjectId();
|
||||
_damage = damage;
|
||||
_ssGrade = ssGrade;
|
||||
@ -62,6 +66,11 @@ public class Hit
|
||||
_flags |= type.getMask();
|
||||
}
|
||||
|
||||
public L2Object getTarget()
|
||||
{
|
||||
return _target.get();
|
||||
}
|
||||
|
||||
public int getTargetId()
|
||||
{
|
||||
return _targetId;
|
||||
@ -81,4 +90,24 @@ public class Hit
|
||||
{
|
||||
return _ssGrade;
|
||||
}
|
||||
|
||||
public boolean isMiss()
|
||||
{
|
||||
return (AttackType.MISSED.getMask() & _flags) != 0;
|
||||
}
|
||||
|
||||
public boolean isCritical()
|
||||
{
|
||||
return (AttackType.CRITICAL.getMask() & _flags) != 0;
|
||||
}
|
||||
|
||||
public boolean isShotUsed()
|
||||
{
|
||||
return (AttackType.SHOT_USED.getMask() & _flags) != 0;
|
||||
}
|
||||
|
||||
public boolean isBlocked()
|
||||
{
|
||||
return (AttackType.BLOCKED.getMask() & _flags) != 0;
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -91,7 +91,7 @@ public final class L2DoorInstance extends L2Character
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAttack(L2Character target)
|
||||
public void doAutoAttack(L2Character target)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -4642,9 +4642,9 @@ public final class L2PcInstance extends L2Playable
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAttack(L2Character target)
|
||||
public void doAutoAttack(L2Character target)
|
||||
{
|
||||
super.doAttack(target);
|
||||
super.doAutoAttack(target);
|
||||
setRecentFakeDeath(false);
|
||||
if (target.isFakePlayer())
|
||||
{
|
||||
|
@ -195,7 +195,7 @@ public final class L2StaticObjectInstance extends L2Character
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAttack(L2Character target)
|
||||
public void doAutoAttack(L2Character target)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1,61 +0,0 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jmobius.gameserver.model.actor.tasks.character;
|
||||
|
||||
import com.l2jmobius.gameserver.model.actor.L2Character;
|
||||
|
||||
/**
|
||||
* Task launching the function onHitTimer().<br>
|
||||
* <B><U>Actions</U>:</B>
|
||||
* <ul>
|
||||
* <li>If the attacker/target is dead or use fake death, notify the AI with EVT_CANCEL and send a Server->Client packet ActionFailed (if attacker is a L2PcInstance)</li>
|
||||
* <li>If attack isn't aborted, send a message system (critical hit, missed...) to attacker/target if they are L2PcInstance</li>
|
||||
* <li>If attack isn't aborted and hit isn't missed, reduce HP of the target and calculate reflection damage to reduce HP of attacker if necessary</li>
|
||||
* <li>if attack isn't aborted and hit isn't missed, manage attack or cast break of the target (calculating rate, sending message...)</li>
|
||||
* </ul>
|
||||
* @author xban1x
|
||||
*/
|
||||
public final class HitTask implements Runnable
|
||||
{
|
||||
private final L2Character _character;
|
||||
private final L2Character _hitTarget;
|
||||
private final int _damage;
|
||||
private final boolean _crit;
|
||||
private final boolean _miss;
|
||||
private final byte _shld;
|
||||
private final boolean _soulshot;
|
||||
|
||||
public HitTask(L2Character character, L2Character target, int damage, boolean crit, boolean miss, boolean soulshot, byte shld)
|
||||
{
|
||||
_character = character;
|
||||
_hitTarget = target;
|
||||
_damage = damage;
|
||||
_crit = crit;
|
||||
_shld = shld;
|
||||
_miss = miss;
|
||||
_soulshot = soulshot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
if (_character != null)
|
||||
{
|
||||
_character.onHitTimer(_hitTarget, _damage, _crit, _miss, _soulshot, _shld);
|
||||
}
|
||||
}
|
||||
}
|
@ -19,6 +19,7 @@ package com.l2jmobius.gameserver.model.events.impl.character;
|
||||
import com.l2jmobius.gameserver.model.actor.L2Character;
|
||||
import com.l2jmobius.gameserver.model.events.EventType;
|
||||
import com.l2jmobius.gameserver.model.events.impl.IBaseEvent;
|
||||
import com.l2jmobius.gameserver.model.skills.Skill;
|
||||
|
||||
/**
|
||||
* An instantly executed event when L2Character is attacked by L2Character.
|
||||
@ -28,11 +29,13 @@ public class OnCreatureAttack implements IBaseEvent
|
||||
{
|
||||
private final L2Character _attacker;
|
||||
private final L2Character _target;
|
||||
private final Skill _skill;
|
||||
|
||||
public OnCreatureAttack(L2Character attacker, L2Character target)
|
||||
public OnCreatureAttack(L2Character attacker, L2Character target, Skill skill)
|
||||
{
|
||||
_attacker = attacker;
|
||||
_target = target;
|
||||
_skill = skill;
|
||||
}
|
||||
|
||||
public final L2Character getAttacker()
|
||||
@ -45,6 +48,11 @@ public class OnCreatureAttack implements IBaseEvent
|
||||
return _target;
|
||||
}
|
||||
|
||||
public final Skill getSkill()
|
||||
{
|
||||
return _skill;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventType getType()
|
||||
{
|
||||
|
@ -37,6 +37,7 @@ import com.l2jmobius.gameserver.model.actor.instance.L2StaticObjectInstance;
|
||||
import com.l2jmobius.gameserver.model.cubic.CubicInstance;
|
||||
import com.l2jmobius.gameserver.model.effects.EffectFlag;
|
||||
import com.l2jmobius.gameserver.model.effects.L2EffectType;
|
||||
import com.l2jmobius.gameserver.model.interfaces.ILocational;
|
||||
import com.l2jmobius.gameserver.model.items.L2Armor;
|
||||
import com.l2jmobius.gameserver.model.items.L2Item;
|
||||
import com.l2jmobius.gameserver.model.items.L2Weapon;
|
||||
@ -271,8 +272,12 @@ public final class Formulas
|
||||
}
|
||||
|
||||
// Autoattack critical rate.
|
||||
// It is capped to 500, but unbound by positional critical rate and level diff bonus.
|
||||
rate *= activeChar.getStat().getPositionTypeValue(Stats.CRITICAL_RATE, Position.getPosition(activeChar, target));
|
||||
// Even though, visible critical rate is capped to 500, you can reach higher than 50% chance with position and level modifiers.
|
||||
// TODO: Find retail-like calculation for criticalRateMod.
|
||||
final double criticalRateMod = (target.getStat().getValue(Stats.DEFENCE_CRITICAL_RATE, rate) + target.getStat().getValue(Stats.DEFENCE_CRITICAL_RATE_ADD, 0)) / 10;
|
||||
final double criticalLocBonus = calcCriticalPositionBonus(activeChar, target);
|
||||
final double criticalHeightBonus = calcCriticalHeightBonus(activeChar, target);
|
||||
rate = criticalLocBonus * criticalRateMod * criticalHeightBonus;
|
||||
|
||||
// In retail, it appears that when you are higher level attacking lower level mobs, your critical rate is much higher.
|
||||
// Level 91 attacking level 1 appear that nearly all hits are critical. Unconfirmed for skills and pvp.
|
||||
@ -286,6 +291,37 @@ public final class Formulas
|
||||
return finalRate > Rnd.get(1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default (10% for side, 30% for back) positional critical rate bonus and multiplies it by any buffs that give positional critical rate bonus.
|
||||
* @param activeChar the attacker.
|
||||
* @param target the target.
|
||||
* @return a multiplier representing the positional critical rate bonus. Autoattacks for example get this bonus on top of the already capped critical rate of 500.
|
||||
*/
|
||||
public static double calcCriticalPositionBonus(L2Character activeChar, L2Character target)
|
||||
{
|
||||
final Position position = target.isAffected(EffectFlag.ATTACK_BEHIND) ? Position.BACK : Position.getPosition(activeChar, target);
|
||||
switch (position)
|
||||
{
|
||||
case SIDE: // 10% Critical Chance bonus when attacking from side.
|
||||
{
|
||||
return 1.1 * activeChar.getStat().getPositionTypeValue(Stats.CRITICAL_RATE, Position.SIDE);
|
||||
}
|
||||
case BACK: // 30% Critical Chance bonus when attacking from back.
|
||||
{
|
||||
return 1.3 * activeChar.getStat().getPositionTypeValue(Stats.CRITICAL_RATE, Position.BACK);
|
||||
}
|
||||
default: // No Critical Chance bonus when attacking from front.
|
||||
{
|
||||
return activeChar.getStat().getPositionTypeValue(Stats.CRITICAL_RATE, Position.FRONT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static double calcCriticalHeightBonus(ILocational from, ILocational target)
|
||||
{
|
||||
return ((((CommonUtil.constrain(from.getZ() - target.getZ(), -25, 25) * 4) / 5) + 10) / 100) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param attacker
|
||||
* @param target
|
||||
@ -403,16 +439,6 @@ public final class Formulas
|
||||
return Rnd.get(100) < rate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param attackSpeed the attack speed of the Creature.
|
||||
* @return {@code 500000 / attackSpeed}.
|
||||
*/
|
||||
public static int calculateTimeBetweenAttacks(int attackSpeed)
|
||||
{
|
||||
// Measured Nov 2015 by Nik. Formula: atk.spd/500 = hits per second.
|
||||
return Math.max(50, (500000 / attackSpeed));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate delay (in milliseconds) for skills cast
|
||||
* @param attacker
|
||||
@ -1023,7 +1049,7 @@ public final class Formulas
|
||||
return 1;
|
||||
}
|
||||
|
||||
public static void calcDamageReflected(L2Character attacker, L2Character target, Skill skill, boolean crit)
|
||||
public static void calcCounterAttack(L2Character attacker, L2Character target, Skill skill, boolean crit)
|
||||
{
|
||||
// Only melee skills can be reflected
|
||||
if (skill.isMagic() || (skill.getCastRange() > MELEE_ATTACK_RANGE))
|
||||
@ -1049,7 +1075,7 @@ public final class Formulas
|
||||
|
||||
double counterdmg = ((target.getPAtk() * 873) / attacker.getPDef()); // Old: (((target.getPAtk(attacker) * 10.0) * 70.0) / attacker.getPDef(target));
|
||||
counterdmg *= calcWeaponTraitBonus(attacker, target);
|
||||
counterdmg *= calcGeneralTraitBonus(attacker, target, skill.getTraitType(), false);
|
||||
counterdmg *= calcGeneralTraitBonus(attacker, target, skill.getTraitType(), true);
|
||||
counterdmg *= calcAttributeBonus(attacker, target, skill);
|
||||
|
||||
attacker.reduceCurrentHp(counterdmg, target, skill);
|
||||
@ -1086,35 +1112,37 @@ public final class Formulas
|
||||
return cha.getStat().getValue(Stats.FALL, (fallHeight * cha.getMaxHp()) / 1000.0);
|
||||
}
|
||||
|
||||
public static boolean calcBlowSuccess(L2Character activeChar, L2Character target, Skill skill, double blowChance)
|
||||
/**
|
||||
* Basic chance formula:<br>
|
||||
* <ul>
|
||||
* <li>chance = weapon_critical * dex_bonus * crit_height_bonus * crit_pos_bonus * effect_bonus * fatal_blow_rate</li>
|
||||
* <li>weapon_critical = (12 for daggers)</li>
|
||||
* <li>dex_bonus = dex modifier bonus for current dex (Seems unused in GOD, so its not used in formula).</li>
|
||||
* <li>crit_height_bonus = (z_diff * 4 / 5 + 10) / 100 + 1 or alternatively (z_diff * 0.008) + 1.1. Be aware of z_diff constraint of -25 to 25.</li>
|
||||
* <li>crit_pos_bonus = crit_pos(front = 1, side = 1.1, back = 1.3) * p_critical_rate_position_bonus</li>
|
||||
* <li>effect_bonus = (p2 + 100) / 100, p2 - 2nd param of effect. Blow chance of effect.</li>
|
||||
* </ul>
|
||||
* Chance cannot be higher than 80%.
|
||||
* @param activeChar
|
||||
* @param target
|
||||
* @param skill
|
||||
* @param chanceBoost
|
||||
* @return
|
||||
*/
|
||||
public static boolean calcBlowSuccess(L2Character activeChar, L2Character target, Skill skill, double chanceBoost)
|
||||
{
|
||||
final double weaponCritical = 12; // Dagger weapon critical mod is 12... TODO: Make it work for other weapons.
|
||||
final L2Weapon weapon = activeChar.getActiveWeaponItem();
|
||||
final double weaponCritical = weapon != null ? weapon.getStats(Stats.CRITICAL_RATE, activeChar.getTemplate().getBaseCritRate()) : activeChar.getTemplate().getBaseCritRate();
|
||||
// double dexBonus = BaseStats.DEX.calcBonus(activeChar); Not used in GOD
|
||||
final double critHeightBonus = ((((CommonUtil.constrain(activeChar.getZ() - target.getZ(), -25, 25) * 4) / 5) + 10) / 100) + 1;
|
||||
final Position position = Position.getPosition(activeChar, target);
|
||||
final double criticalPosition = position == Position.BACK ? 1.3 : position == Position.SIDE ? 1.1 : 1; // 30% chance from back, 10% chance from side.
|
||||
final double criticalPositionMod = criticalPosition * activeChar.getStat().getPositionTypeValue(Stats.CRITICAL_RATE, position);
|
||||
final double critHeightBonus = calcCriticalHeightBonus(activeChar, target);
|
||||
final double criticalPosition = calcCriticalPositionBonus(activeChar, target); // 30% chance from back, 10% chance from side. Include buffs that give positional crit rate.
|
||||
final double chanceBoostMod = (100 + chanceBoost) / 100;
|
||||
final double blowRateMod = activeChar.getStat().getValue(Stats.BLOW_RATE, 1);
|
||||
blowChance = (weaponCritical + blowChance) * 10;
|
||||
|
||||
final double rate = blowChance * critHeightBonus * criticalPositionMod * blowRateMod;
|
||||
|
||||
// Debug
|
||||
if (activeChar.isDebug())
|
||||
{
|
||||
final StatsSet set = new StatsSet();
|
||||
set.set("weaponCritical", weaponCritical);
|
||||
set.set("critHeightBonus", critHeightBonus);
|
||||
set.set("criticalPosition", criticalPosition);
|
||||
set.set("criticalPositionMod", criticalPositionMod);
|
||||
set.set("blowRate", blowRateMod);
|
||||
set.set("blowChance", blowChance);
|
||||
set.set("rate(max 800 of 1000)", rate);
|
||||
Debug.sendSkillDebug(activeChar, target, skill, set);
|
||||
}
|
||||
final double rate = criticalPosition * critHeightBonus * weaponCritical * chanceBoostMod * blowRateMod;
|
||||
|
||||
// Blow rate is capped at 80%
|
||||
return Rnd.get(1000) < Math.min(rate, 800);
|
||||
return Rnd.get(100) < Math.min(rate, 80);
|
||||
}
|
||||
|
||||
public static List<BuffInfo> calcCancelStealEffects(L2Character activeChar, L2Character target, Skill skill, DispelSlotType slot, int rate, int max)
|
||||
@ -1224,6 +1252,12 @@ public final class Formulas
|
||||
*/
|
||||
public static boolean calcProbability(double baseChance, L2Character attacker, L2Character target, Skill skill)
|
||||
{
|
||||
// Skills without set probability should only test against trait invulnerability.
|
||||
if (Double.isNaN(baseChance))
|
||||
{
|
||||
return calcGeneralTraitBonus(attacker, target, skill.getTraitType(), true) > 0;
|
||||
}
|
||||
|
||||
// Outdated formula: return Rnd.get(100) < ((((((skill.getMagicLevel() + baseChance) - target.getLevel()) + 30) - target.getINT()) * calcAttributeBonus(attacker, target, skill)) * calcGeneralTraitBonus(attacker, target, skill.getTraitType(), false));
|
||||
// TODO: Find more retail-like formula
|
||||
return Rnd.get(100) < (((((skill.getMagicLevel() + baseChance) - target.getLevel()) - getAbnormalResist(skill.getBasicProperty(), target)) * calcAttributeBonus(attacker, target, skill)) * calcGeneralTraitBonus(attacker, target, skill.getTraitType(), false));
|
||||
@ -1486,7 +1520,7 @@ public final class Formulas
|
||||
*/
|
||||
public static boolean calcStunBreak(L2Character activeChar)
|
||||
{
|
||||
// Check if target is stunned and 10% chance.
|
||||
// Check if target is stunned and 10% chance (retail is 14% and 35% on crit?)
|
||||
if (activeChar.hasBlockActions() && (Rnd.get(10) == 0))
|
||||
{
|
||||
// Any stun that has double duration due to skill mastery, doesn't get removed until its time reaches the usual abnormal time.
|
||||
@ -1497,8 +1531,18 @@ public final class Formulas
|
||||
|
||||
public static boolean calcRealTargetBreak()
|
||||
{
|
||||
// Real Target breaks at 5% probability.
|
||||
return Rnd.get(20) == 0;
|
||||
// Real Target breaks at 3% (Rnd > 3.0 doesn't break) probability.
|
||||
return Rnd.get(100) <= 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param attackSpeed the attack speed of the Creature.
|
||||
* @return {@code 500000 / attackSpeed}.
|
||||
*/
|
||||
public static int calculateTimeBetweenAttacks(int attackSpeed)
|
||||
{
|
||||
// Measured Nov 2015 by Nik. Formula: atk.spd/500 = hits per second.
|
||||
return Math.max(50, (500000 / attackSpeed));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -143,6 +143,7 @@ public enum Stats
|
||||
PHYSICAL_ATTACK_RANGE("pAtkRange", new PRangeFinalizer()),
|
||||
MAGIC_ATTACK_RANGE("mAtkRange"),
|
||||
ATTACK_COUNT_MAX("atkCountMax"),
|
||||
PHYSICAL_POLEARM_TARGET_SINGLE("polearmSingleTarget"),
|
||||
// Run speed, walk & escape speed are calculated proportionally, magic speed is a buff
|
||||
MOVE_SPEED("moveSpeed"),
|
||||
RUN_SPEED("runSpd", new SpeedFinalizer()),
|
||||
@ -266,7 +267,8 @@ public enum Stats
|
||||
// Which base stat ordinal should alter skill critical formula.
|
||||
STAT_BONUS_SKILL_CRITICAL("statSkillCritical"),
|
||||
STAT_BONUS_SPEED("statSpeed"),
|
||||
SHOTS_BONUS("shotBonus", new ShotsBonusFinalizer());
|
||||
SHOTS_BONUS("shotBonus", new ShotsBonusFinalizer()),
|
||||
ATTACK_DAMAGE("attackDamage");
|
||||
|
||||
static final Logger LOGGER = Logger.getLogger(Stats.class.getName());
|
||||
public static final int NUM_STATS = values().length;
|
||||
|
@ -29,8 +29,6 @@ import com.l2jmobius.gameserver.network.OutgoingPackets;
|
||||
public class Attack implements IClientOutgoingPacket
|
||||
{
|
||||
private final int _attackerObjId;
|
||||
private final boolean _soulshot;
|
||||
private final int _ssGrade;
|
||||
private final Location _attackerLoc;
|
||||
private final Location _targetLoc;
|
||||
private final List<Hit> _hits = new ArrayList<>();
|
||||
@ -38,29 +36,26 @@ public class Attack implements IClientOutgoingPacket
|
||||
/**
|
||||
* @param attacker
|
||||
* @param target
|
||||
* @param useShots
|
||||
* @param ssGrade
|
||||
*/
|
||||
public Attack(L2Character attacker, L2Character target, boolean useShots, int ssGrade)
|
||||
public Attack(L2Character attacker, L2Character target)
|
||||
{
|
||||
_attackerObjId = attacker.getObjectId();
|
||||
_soulshot = useShots;
|
||||
_ssGrade = Math.min(ssGrade, 6);
|
||||
_attackerLoc = new Location(attacker);
|
||||
_targetLoc = new Location(target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds hit to the attack (Attacks such as dual dagger/sword/fist has two hits)
|
||||
* @param target
|
||||
* @param damage
|
||||
* @param miss
|
||||
* @param crit
|
||||
* @param shld
|
||||
* @param hit
|
||||
*/
|
||||
public void addHit(L2Character target, int damage, boolean miss, boolean crit, byte shld)
|
||||
public void addHit(Hit hit)
|
||||
{
|
||||
_hits.add(new Hit(target, damage, miss, crit, shld, _soulshot, _ssGrade));
|
||||
_hits.add(hit);
|
||||
}
|
||||
|
||||
public List<Hit> getHits()
|
||||
{
|
||||
return _hits;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -71,14 +66,6 @@ public class Attack implements IClientOutgoingPacket
|
||||
return !_hits.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if attack has soul shot charged.
|
||||
*/
|
||||
public boolean hasSoulshot()
|
||||
{
|
||||
return _soulshot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes current hit
|
||||
* @param packet
|
||||
|
@ -43,7 +43,7 @@ public class ExAutoSoulShot implements IClientOutgoingPacket
|
||||
OutgoingPackets.EX_AUTO_SOUL_SHOT.writeId(packet);
|
||||
|
||||
packet.writeD(_itemId);
|
||||
packet.writeD(_enable ? 0x01 : 0x00);
|
||||
packet.writeD(_enable ? 0x01 : 0x00); // Underground
|
||||
packet.writeD(_type);
|
||||
return true;
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ public final class EffectMasterHandler
|
||||
EffectHandler.getInstance().registerHandler("AttackAttribute", AttackAttribute::new);
|
||||
EffectHandler.getInstance().registerHandler("AttackAttributeAdd", AttackAttributeAdd::new);
|
||||
EffectHandler.getInstance().registerHandler("AttackBehind", AttackBehind::new);
|
||||
EffectHandler.getInstance().registerHandler("AttackDamagePosition", AttackDamagePosition::new);
|
||||
EffectHandler.getInstance().registerHandler("AttackTrait", AttackTrait::new);
|
||||
EffectHandler.getInstance().registerHandler("Backstab", Backstab::new);
|
||||
EffectHandler.getInstance().registerHandler("Betray", Betray::new);
|
||||
@ -236,6 +237,7 @@ public final class EffectMasterHandler
|
||||
EffectHandler.getInstance().registerHandler("PhysicalSoulAttack", PhysicalSoulAttack::new);
|
||||
EffectHandler.getInstance().registerHandler("PkCount", PkCount::new);
|
||||
EffectHandler.getInstance().registerHandler("Plunder", Plunder::new);
|
||||
EffectHandler.getInstance().registerHandler("PolearmSingleTarget", PolearmSingleTarget::new);
|
||||
EffectHandler.getInstance().registerHandler("ProtectionBlessing", ProtectionBlessing::new);
|
||||
EffectHandler.getInstance().registerHandler("ProtectDeathPenalty", ProtectDeathPenalty::new);
|
||||
EffectHandler.getInstance().registerHandler("PullBack", PullBack::new);
|
||||
|
53
L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/effecthandlers/AttackDamagePosition.java
vendored
Normal file
53
L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/effecthandlers/AttackDamagePosition.java
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package handlers.effecthandlers;
|
||||
|
||||
import com.l2jmobius.commons.util.MathUtil;
|
||||
import com.l2jmobius.gameserver.enums.Position;
|
||||
import com.l2jmobius.gameserver.model.StatsSet;
|
||||
import com.l2jmobius.gameserver.model.actor.L2Character;
|
||||
import com.l2jmobius.gameserver.model.effects.AbstractEffect;
|
||||
import com.l2jmobius.gameserver.model.skills.BuffInfo;
|
||||
import com.l2jmobius.gameserver.model.skills.Skill;
|
||||
import com.l2jmobius.gameserver.model.stats.Stats;
|
||||
|
||||
/**
|
||||
* @author Nik
|
||||
*/
|
||||
public class AttackDamagePosition extends AbstractEffect
|
||||
{
|
||||
protected final double _amount;
|
||||
protected final Position _position;
|
||||
|
||||
public AttackDamagePosition(StatsSet params)
|
||||
{
|
||||
_amount = params.getDouble("amount");
|
||||
_position = params.getEnum("position", Position.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pump(L2Character effected, Skill skill)
|
||||
{
|
||||
effected.getStat().mergePositionTypeValue(Stats.ATTACK_DAMAGE, _position, (_amount / 100) + 1, MathUtil::mul);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExit(BuffInfo info)
|
||||
{
|
||||
info.getEffected().getStat().mergePositionTypeValue(Stats.ATTACK_DAMAGE, _position, (_amount / 100) + 1, MathUtil::div);
|
||||
}
|
||||
}
|
@ -88,7 +88,7 @@ public final class Backstab extends AbstractEffect
|
||||
}
|
||||
|
||||
// Check if damage should be reflected
|
||||
Formulas.calcDamageReflected(effector, effected, skill, true);
|
||||
Formulas.calcCounterAttack(effector, effected, skill, true);
|
||||
|
||||
final double damageCap = effected.getStat().getValue(Stats.DAMAGE_LIMIT);
|
||||
if (damageCap > 0)
|
||||
|
@ -163,7 +163,7 @@ public final class EnergyAttack extends AbstractEffect
|
||||
damage = Math.max(0, damage);
|
||||
|
||||
// Check if damage should be reflected
|
||||
Formulas.calcDamageReflected(attacker, effected, skill, critical);
|
||||
Formulas.calcCounterAttack(attacker, effected, skill, critical);
|
||||
|
||||
final double damageCap = effected.getStat().getValue(Stats.DAMAGE_LIMIT);
|
||||
if (damageCap > 0)
|
||||
|
@ -119,7 +119,7 @@ public final class FatalBlow extends AbstractEffect
|
||||
}
|
||||
|
||||
// Check if damage should be reflected
|
||||
Formulas.calcDamageReflected(effector, effected, skill, true);
|
||||
Formulas.calcCounterAttack(effector, effected, skill, true);
|
||||
|
||||
final double damageCap = effected.getStat().getValue(Stats.DAMAGE_LIMIT);
|
||||
if (damageCap > 0)
|
||||
|
@ -115,6 +115,6 @@ public final class Lethal extends AbstractEffect
|
||||
}
|
||||
|
||||
// No matter if lethal succeeded or not, its reflected.
|
||||
Formulas.calcDamageReflected(effector, effected, skill, false);
|
||||
Formulas.calcCounterAttack(effector, effected, skill, false);
|
||||
}
|
||||
}
|
||||
|
@ -173,7 +173,7 @@ public final class PhysicalAttack extends AbstractEffect
|
||||
}
|
||||
|
||||
// Check if damage should be reflected
|
||||
Formulas.calcDamageReflected(effector, effected, skill, critical);
|
||||
Formulas.calcCounterAttack(effector, effected, skill, critical);
|
||||
final double damageCap = effected.getStat().getValue(Stats.DAMAGE_LIMIT);
|
||||
if (damageCap > 0)
|
||||
{
|
||||
|
@ -135,7 +135,7 @@ public final class PhysicalAttackHpLink extends AbstractEffect
|
||||
}
|
||||
|
||||
// Check if damage should be reflected.
|
||||
Formulas.calcDamageReflected(effector, effected, skill, critical);
|
||||
Formulas.calcCounterAttack(effector, effected, skill, critical);
|
||||
|
||||
final double damageCap = effected.getStat().getValue(Stats.DAMAGE_LIMIT);
|
||||
if (damageCap > 0)
|
||||
|
@ -145,7 +145,7 @@ public final class PhysicalAttackSaveHp extends AbstractEffect
|
||||
}
|
||||
|
||||
// Check if damage should be reflected
|
||||
Formulas.calcDamageReflected(effector, effected, skill, critical);
|
||||
Formulas.calcCounterAttack(effector, effected, skill, critical);
|
||||
|
||||
final double damageCap = effected.getStat().getValue(Stats.DAMAGE_LIMIT);
|
||||
if (damageCap > 0)
|
||||
|
@ -166,7 +166,7 @@ public final class PhysicalAttackWeaponBonus extends AbstractEffect
|
||||
}
|
||||
|
||||
// Check if damage should be reflected
|
||||
Formulas.calcDamageReflected(effector, effected, skill, critical);
|
||||
Formulas.calcCounterAttack(effector, effected, skill, critical);
|
||||
|
||||
final double damageCap = effected.getStat().getValue(Stats.DAMAGE_LIMIT);
|
||||
if (damageCap > 0)
|
||||
|
@ -160,7 +160,7 @@ public final class PhysicalSoulAttack extends AbstractEffect
|
||||
}
|
||||
|
||||
// Check if damage should be reflected
|
||||
Formulas.calcDamageReflected(effector, effected, skill, critical);
|
||||
Formulas.calcCounterAttack(effector, effected, skill, critical);
|
||||
|
||||
final double damageCap = effected.getStat().getValue(Stats.DAMAGE_LIMIT);
|
||||
if (damageCap > 0)
|
||||
|
52
L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/effecthandlers/PolearmSingleTarget.java
vendored
Normal file
52
L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/effecthandlers/PolearmSingleTarget.java
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package handlers.effecthandlers;
|
||||
|
||||
import com.l2jmobius.gameserver.model.StatsSet;
|
||||
import com.l2jmobius.gameserver.model.actor.L2Character;
|
||||
import com.l2jmobius.gameserver.model.effects.AbstractEffect;
|
||||
import com.l2jmobius.gameserver.model.skills.BuffInfo;
|
||||
import com.l2jmobius.gameserver.model.skills.Skill;
|
||||
import com.l2jmobius.gameserver.model.stats.Stats;
|
||||
|
||||
/**
|
||||
* @author Sdw
|
||||
*/
|
||||
public class PolearmSingleTarget extends AbstractEffect
|
||||
{
|
||||
public PolearmSingleTarget(StatsSet params)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart(L2Character effector, L2Character effected, Skill skill)
|
||||
{
|
||||
if (effected.isPlayer())
|
||||
{
|
||||
effected.getStat().addFixedValue(Stats.PHYSICAL_POLEARM_TARGET_SINGLE, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExit(BuffInfo info)
|
||||
{
|
||||
if (info.getEffected().isPlayer())
|
||||
{
|
||||
info.getEffected().getStat().removeFixedValue(Stats.PHYSICAL_POLEARM_TARGET_SINGLE);
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user