Unified dragonfire protection logic
Fixed KBD's attack range resulting in only certain spots allowing him to melee
This commit is contained in:
+165
-177
@@ -17,205 +17,193 @@ import core.game.world.update.flag.context.Animation;
|
||||
import core.game.world.update.flag.context.Graphics;
|
||||
import core.tools.RandomFunction;
|
||||
|
||||
import static core.api.ContentAPIKt.calculateDragonfireMaxHit;
|
||||
|
||||
/**
|
||||
* Handles dragonfire combat.
|
||||
* @author Emperor
|
||||
*/
|
||||
public class DragonfireSwingHandler extends CombatSwingHandler {
|
||||
|
||||
/**
|
||||
* If the NPC has to be in melee range.
|
||||
*/
|
||||
private boolean meleeRange;
|
||||
/**
|
||||
* If the NPC has to be in melee range.
|
||||
*/
|
||||
private boolean meleeRange;
|
||||
|
||||
/**
|
||||
* The maximum hit.
|
||||
*/
|
||||
private int maximumHit;
|
||||
/**
|
||||
* The maximum hit.
|
||||
*/
|
||||
private int maximumHit;
|
||||
|
||||
/**
|
||||
* The attack data.
|
||||
*/
|
||||
private SwitchAttack attack;
|
||||
/**
|
||||
* The attack data.
|
||||
*/
|
||||
private SwitchAttack attack;
|
||||
|
||||
/**
|
||||
* IF the dragon attack is firey or icey.
|
||||
*/
|
||||
private boolean fire;
|
||||
/**
|
||||
* IF the dragon attack is firey or icey.
|
||||
*/
|
||||
private boolean fire;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code DragonfireSwingHandler} {@code Object}.
|
||||
* @param meleeRange If the NPC has to be in melee range.
|
||||
* @param maximumHit The maximum hit.
|
||||
* @param fire if firey.
|
||||
*/
|
||||
public DragonfireSwingHandler(boolean meleeRange, int maximumHit, SwitchAttack attack, boolean fire) {
|
||||
super(CombatStyle.MAGIC);
|
||||
this.meleeRange = meleeRange;
|
||||
this.maximumHit = maximumHit;
|
||||
this.attack = attack;
|
||||
this.fire = fire;
|
||||
}
|
||||
/**
|
||||
* Constructs a new {@code DragonfireSwingHandler} {@code Object}.
|
||||
* @param meleeRange If the NPC has to be in melee range.
|
||||
* @param maximumHit The maximum hit.
|
||||
* @param fire if firey.
|
||||
*/
|
||||
public DragonfireSwingHandler(boolean meleeRange, int maximumHit, SwitchAttack attack, boolean fire) {
|
||||
super(CombatStyle.MAGIC);
|
||||
this.meleeRange = meleeRange;
|
||||
this.maximumHit = maximumHit;
|
||||
this.attack = attack;
|
||||
this.fire = fire;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the switch attack instance for a dragonfire attack.
|
||||
* @param meleeRange If the attack is melee range.
|
||||
* @param maximumHit The maximum hit.
|
||||
* @param animation The animation.
|
||||
* @param startGraphic The start graphic.
|
||||
* @param endGraphic The end graphic.
|
||||
* @param projectile The projectile.
|
||||
* @return The switch attack instance.
|
||||
*/
|
||||
public static SwitchAttack get(boolean meleeRange, int maximumHit, Animation animation, Graphics startGraphic, Graphics endGraphic, Projectile projectile) {
|
||||
SwitchAttack attack = new SwitchAttack(null, animation, startGraphic, endGraphic, projectile).setUseHandler(true);
|
||||
attack.setHandler(new DragonfireSwingHandler(meleeRange, maximumHit, attack, true));
|
||||
return attack;
|
||||
}
|
||||
/**
|
||||
* Gets the switch attack instance for a dragonfire attack.
|
||||
* @param meleeRange If the attack is melee range.
|
||||
* @param maximumHit The maximum hit.
|
||||
* @param animation The animation.
|
||||
* @param startGraphic The start graphic.
|
||||
* @param endGraphic The end graphic.
|
||||
* @param projectile The projectile.
|
||||
* @return The switch attack instance.
|
||||
*/
|
||||
public static SwitchAttack get(boolean meleeRange, int maximumHit, Animation animation, Graphics startGraphic, Graphics endGraphic, Projectile projectile) {
|
||||
SwitchAttack attack = new SwitchAttack(null, animation, startGraphic, endGraphic, projectile).setUseHandler(true);
|
||||
attack.setHandler(new DragonfireSwingHandler(meleeRange, maximumHit, attack, true));
|
||||
return attack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the switch attack instance for a dragonfire attack.
|
||||
* @param meleeRange If the attack is melee range.
|
||||
* @param maximumHit The maximum hit.
|
||||
* @param animation The animation.
|
||||
* @param startGraphic The start graphic.
|
||||
* @param endGraphic The end graphic.
|
||||
* @param projectile The projectile.
|
||||
* @return The switch attack instance.
|
||||
*/
|
||||
public static SwitchAttack get(boolean meleeRange, int maximumHit, Animation animation, Graphics startGraphic, Graphics endGraphic, Projectile projectile, boolean fire) {
|
||||
SwitchAttack attack = new SwitchAttack(null, animation, startGraphic, endGraphic, projectile).setUseHandler(true);
|
||||
attack.setHandler(new DragonfireSwingHandler(meleeRange, maximumHit, attack, fire));
|
||||
return attack;
|
||||
}
|
||||
/**
|
||||
* Gets the switch attack instance for a dragonfire attack.
|
||||
* @param meleeRange If the attack is melee range.
|
||||
* @param maximumHit The maximum hit.
|
||||
* @param animation The animation.
|
||||
* @param startGraphic The start graphic.
|
||||
* @param endGraphic The end graphic.
|
||||
* @param projectile The projectile.
|
||||
* @return The switch attack instance.
|
||||
*/
|
||||
public static SwitchAttack get(boolean meleeRange, int maximumHit, Animation animation, Graphics startGraphic, Graphics endGraphic, Projectile projectile, boolean fire) {
|
||||
SwitchAttack attack = new SwitchAttack(null, animation, startGraphic, endGraphic, projectile).setUseHandler(true);
|
||||
attack.setHandler(new DragonfireSwingHandler(meleeRange, maximumHit, attack, fire));
|
||||
return attack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionType canSwing(Entity entity, Entity victim) {
|
||||
if (meleeRange) {
|
||||
return CombatStyle.MELEE.getSwingHandler().canSwing(entity, victim);
|
||||
}
|
||||
return CombatStyle.MAGIC.getSwingHandler().canSwing(entity, victim);
|
||||
}
|
||||
@Override
|
||||
public InteractionType canSwing(Entity entity, Entity victim) {
|
||||
if (meleeRange) {
|
||||
return CombatStyle.MELEE.getSwingHandler().canSwing(entity, victim);
|
||||
}
|
||||
return CombatStyle.MAGIC.getSwingHandler().canSwing(entity, victim);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int swing(Entity entity, Entity victim, BattleState state) {
|
||||
int max = calculateHit(entity, victim, 1.0);
|
||||
int hit = RandomFunction.random(max);
|
||||
assert state != null;
|
||||
state.setMaximumHit(max);
|
||||
state.setStyle(CombatStyle.MAGIC);
|
||||
state.setEstimatedHit(hit);
|
||||
if (meleeRange) {
|
||||
return 1;
|
||||
}
|
||||
int ticks = 2 + (int) Math.floor(entity.getLocation().getDistance(victim.getLocation()) * 0.5);
|
||||
entity.setAttribute("fireBreath", GameWorld.getTicks() + (ticks + 2));
|
||||
return ticks;
|
||||
}
|
||||
@Override
|
||||
public int swing(Entity entity, Entity victim, BattleState state) {
|
||||
int max = calculateHit(entity, victim, 1.0);
|
||||
int hit = RandomFunction.random(max + 1);
|
||||
assert state != null;
|
||||
state.setMaximumHit(max);
|
||||
state.setStyle(CombatStyle.MAGIC);
|
||||
state.setEstimatedHit(hit);
|
||||
if (meleeRange) {
|
||||
return 1;
|
||||
}
|
||||
int ticks = 2 + (int) Math.floor(entity.getLocation().getDistance(victim.getLocation()) * 0.5);
|
||||
entity.setAttribute("fireBreath", GameWorld.getTicks() + (ticks + 2));
|
||||
return ticks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visualize(Entity entity, Entity victim, BattleState state) {
|
||||
entity.visualize(attack.getAnimation(), attack.getStartGraphic());
|
||||
if (attack.getProjectile() != null) {
|
||||
attack.getProjectile().copy(entity, victim, 5).send();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void visualize(Entity entity, Entity victim, BattleState state) {
|
||||
entity.visualize(attack.getAnimation(), attack.getStartGraphic());
|
||||
if (attack.getProjectile() != null) {
|
||||
attack.getProjectile().copy(entity, victim, 5).send();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visualizeImpact(Entity entity, Entity victim, BattleState state) {
|
||||
if (entity instanceof NPC && victim instanceof Player) {
|
||||
Player p = (Player) victim;
|
||||
p.getPacketDispatch().sendMessage(getDragonfireMessage(victim.getAttribute("fire_resistance", 0), !fire ? "icy breath" : "fiery breath"));
|
||||
Item shield = p.getEquipment().get(EquipmentContainer.SLOT_SHIELD);
|
||||
if (shield != null && (shield.getId() == 11283 || shield.getId() == 11284)) {
|
||||
if (shield.getId() == 11284) {
|
||||
p.getEquipment().replace(new Item(11283), EquipmentContainer.SLOT_SHIELD);
|
||||
shield = p.getEquipment().get(EquipmentContainer.SLOT_SHIELD);
|
||||
shield.setCharge(0);
|
||||
}
|
||||
if (shield.getCharge() < 1000) {
|
||||
shield.setCharge(shield.getCharge() + 20);
|
||||
EquipmentContainer.updateBonuses(p);
|
||||
p.getPacketDispatch().sendMessage("Your dragonfire shield glows more brightly.");
|
||||
@Override
|
||||
public void visualizeImpact(Entity entity, Entity victim, BattleState state) {
|
||||
if (entity instanceof NPC && victim instanceof Player) {
|
||||
Player p = (Player) victim;
|
||||
Item shield = p.getEquipment().get(EquipmentContainer.SLOT_SHIELD);
|
||||
if (shield != null && (shield.getId() == 11283 || shield.getId() == 11284)) {
|
||||
if (shield.getId() == 11284) {
|
||||
p.getEquipment().replace(new Item(11283), EquipmentContainer.SLOT_SHIELD);
|
||||
shield = p.getEquipment().get(EquipmentContainer.SLOT_SHIELD);
|
||||
shield.setCharge(0);
|
||||
}
|
||||
if (shield.getCharge() < 1000) {
|
||||
shield.setCharge(shield.getCharge() + 20);
|
||||
EquipmentContainer.updateBonuses(p);
|
||||
p.getPacketDispatch().sendMessage("Your dragonfire shield glows more brightly.");
|
||||
|
||||
p.faceLocation(entity.getCenterLocation());
|
||||
victim.visualize(Animation.create(6695), Graphics.create(1163));
|
||||
} else {
|
||||
p.getPacketDispatch().sendMessage("Your dragonfire shield is already fully charged.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!fire && victim.getAttribute("freeze_immunity", -1) < GameWorld.getTicks() && RandomFunction.random(4) == 2) {
|
||||
victim.getStateManager().set(EntityState.FROZEN, 16);
|
||||
victim.graphics(Graphics.create(502));
|
||||
}
|
||||
Graphics graphic = attack != null ? attack.getEndGraphic() : null;
|
||||
victim.visualize(victim.getProperties().getDefenceAnimation(), graphic);
|
||||
}
|
||||
p.faceLocation(entity.getCenterLocation());
|
||||
victim.visualize(Animation.create(6695), Graphics.create(1163));
|
||||
} else {
|
||||
p.getPacketDispatch().sendMessage("Your dragonfire shield is already fully charged.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!fire && victim.getAttribute("freeze_immunity", -1) < GameWorld.getTicks() && RandomFunction.random(4) == 2) {
|
||||
victim.getStateManager().set(EntityState.FROZEN, 16);
|
||||
victim.graphics(Graphics.create(502));
|
||||
}
|
||||
Graphics graphic = attack != null ? attack.getEndGraphic() : null;
|
||||
victim.visualize(victim.getProperties().getDefenceAnimation(), graphic);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void impact(Entity entity, Entity victim, BattleState state) {
|
||||
assert state != null;
|
||||
int hit = state.getEstimatedHit();
|
||||
if (hit > -1) {
|
||||
victim.getImpactHandler().handleImpact(entity, hit, CombatStyle.MAGIC, state);
|
||||
}
|
||||
hit = state.getSecondaryHit();
|
||||
if (hit > -1) {
|
||||
victim.getImpactHandler().handleImpact(entity, hit, CombatStyle.MAGIC, state);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void impact(Entity entity, Entity victim, BattleState state) {
|
||||
assert state != null;
|
||||
int hit = state.getEstimatedHit();
|
||||
if (hit > -1) {
|
||||
victim.getImpactHandler().handleImpact(entity, hit, CombatStyle.MAGIC, state);
|
||||
}
|
||||
hit = state.getSecondaryHit();
|
||||
if (hit > -1) {
|
||||
victim.getImpactHandler().handleImpact(entity, hit, CombatStyle.MAGIC, state);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustBattleState(Entity entity, Entity victim, BattleState state) {
|
||||
if (victim.isPlayer() && !fire) {
|
||||
Item item = victim.asPlayer().getEquipment().get(EquipmentContainer.SLOT_SHIELD);
|
||||
if (item != null && (item.getId() == 2890 || item.getId() == 9731) && state.getEstimatedHit() > 10) {
|
||||
state.setEstimatedHit(RandomFunction.random(10));
|
||||
}
|
||||
}
|
||||
CombatStyle style = state.getStyle();
|
||||
super.adjustBattleState(entity, victim, state);
|
||||
state.setStyle(style);
|
||||
}
|
||||
@Override
|
||||
public void adjustBattleState(Entity entity, Entity victim, BattleState state) {
|
||||
if (victim.isPlayer() && !fire) {
|
||||
Item item = victim.asPlayer().getEquipment().get(EquipmentContainer.SLOT_SHIELD);
|
||||
if (item != null && (item.getId() == 2890 || item.getId() == 9731) && state.getEstimatedHit() > 10) {
|
||||
state.setEstimatedHit(RandomFunction.random(10));
|
||||
}
|
||||
}
|
||||
CombatStyle style = state.getStyle();
|
||||
super.adjustBattleState(entity, victim, state);
|
||||
state.setStyle(style);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getFormattedHit(Entity entity, Entity victim, BattleState state, int hit) {
|
||||
return formatHit(victim, hit);
|
||||
}
|
||||
@Override
|
||||
protected int getFormattedHit(Entity entity, Entity victim, BattleState state, int hit) {
|
||||
return formatHit(victim, hit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int calculateAccuracy(Entity entity) {
|
||||
return 4000;
|
||||
}
|
||||
@Override
|
||||
public int calculateAccuracy(Entity entity) {
|
||||
return 4000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int calculateHit(Entity entity, Entity victim, double modifier) {
|
||||
int damage = maximumHit;
|
||||
if (victim instanceof Player) {
|
||||
int val = victim.getDragonfireProtection(fire);
|
||||
if ((val & 0x2) != 0) {
|
||||
damage *= 0.1;
|
||||
}
|
||||
if ((val & 0x4) != 0) {
|
||||
damage *= 0.1;
|
||||
}
|
||||
if ((val & 0x8) != 0) {
|
||||
damage *= 0.6;
|
||||
}
|
||||
}
|
||||
return damage;
|
||||
}
|
||||
@Override
|
||||
public int calculateHit(Entity entity, Entity victim, double modifier) {
|
||||
return calculateDragonfireMaxHit(victim, maximumHit, !fire, 0, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int calculateDefence(Entity victim, Entity attacker) {
|
||||
return CombatStyle.MAGIC.getSwingHandler().calculateDefence(victim, attacker);
|
||||
}
|
||||
@Override
|
||||
public int calculateDefence(Entity victim, Entity attacker) {
|
||||
return CombatStyle.MAGIC.getSwingHandler().calculateDefence(victim, attacker);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getSetMultiplier(Entity e, int skillId) {
|
||||
return 1.0;
|
||||
}
|
||||
@Override
|
||||
public double getSetMultiplier(Entity e, int skillId) {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,19 +31,6 @@ class SkeletalWyvernBehavior : NPCBehavior(*Tasks.SKELETAL_WYVERN.ids) {
|
||||
|
||||
private val SHIELDS = intArrayOf(Items.DRAGONFIRE_SHIELD_11283, Items.DRAGONFIRE_SHIELD_11285, Items.ELEMENTAL_SHIELD_2890, Items.MIND_SHIELD_9731)
|
||||
|
||||
override fun beforeAttackFinalized(self: NPC, victim: Entity, state: BattleState) {
|
||||
if (victim !is Player) return
|
||||
if (state.style != CombatStyle.MAGIC) return
|
||||
|
||||
val shield = getItemFromEquipment(victim, EquipmentSlot.SHIELD)
|
||||
val hasShieldProtection = shield != null && shield.id in SHIELDS
|
||||
if (!hasShieldProtection) return
|
||||
|
||||
state.estimatedHit = RandomFunction.random(11)
|
||||
if (victim.location.getDistance(self.location) >= 5 && victim.prayer.get(PrayerType.PROTECT_FROM_MAGIC))
|
||||
state.estimatedHit = 0
|
||||
}
|
||||
|
||||
override fun getSwingHandlerOverride(self: NPC, original: CombatSwingHandler): CombatSwingHandler {
|
||||
val victim = self.properties.combatPulse.getVictim() ?: return original
|
||||
if (victim !is Player) return original
|
||||
@@ -53,4 +40,4 @@ class SkeletalWyvernBehavior : NPCBehavior(*Tasks.SKELETAL_WYVERN.ids) {
|
||||
else
|
||||
COMBAT_HANDLER
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+249
-263
@@ -25,6 +25,8 @@ import core.plugin.Initializable;
|
||||
import core.tools.RandomFunction;
|
||||
import content.global.handlers.item.equipment.special.DragonfireSwingHandler;
|
||||
|
||||
import static core.api.ContentAPIKt.calculateDragonfireMaxHit;
|
||||
|
||||
|
||||
/**
|
||||
* Represents the Elvarg npc.
|
||||
@@ -34,311 +36,295 @@ import content.global.handlers.item.equipment.special.DragonfireSwingHandler;
|
||||
@Initializable
|
||||
public final class ElvargNPC extends AbstractNPC {
|
||||
|
||||
/**
|
||||
* The NPC ids of NPCs using this plugin.
|
||||
*/
|
||||
private static final int[] ID = { 742 };
|
||||
/**
|
||||
* The NPC ids of NPCs using this plugin.
|
||||
*/
|
||||
private static final int[] ID = { 742 };
|
||||
|
||||
/**
|
||||
* Represents the animations to use.
|
||||
*/
|
||||
private static final Animation[] ANIMATIONS = new Animation[] { new Animation(6654), new Animation(6655) };
|
||||
/**
|
||||
* Represents the animations to use.
|
||||
*/
|
||||
private static final Animation[] ANIMATIONS = new Animation[] { new Animation(6654), new Animation(6655) };
|
||||
|
||||
/**
|
||||
* Represents the combat swing handler.
|
||||
*/
|
||||
private final CombatSwingHandler combatHandler = new ElvargCombatSwingHandler();
|
||||
/**
|
||||
* Represents the combat swing handler.
|
||||
*/
|
||||
private final CombatSwingHandler combatHandler = new ElvargCombatSwingHandler();
|
||||
|
||||
/**
|
||||
* Constructs a new {@code ElvargNPC} {@code Object}.
|
||||
*/
|
||||
public ElvargNPC() {
|
||||
super(0, null);
|
||||
}
|
||||
/**
|
||||
* Constructs a new {@code ElvargNPC} {@code Object}.
|
||||
*/
|
||||
public ElvargNPC() {
|
||||
super(0, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code ElvargNPC} {@code Object}.
|
||||
* @param id The NPC id.
|
||||
* @param location The location.
|
||||
*/
|
||||
private ElvargNPC(int id, Location location) {
|
||||
super(id, location);
|
||||
}
|
||||
/**
|
||||
* Constructs a new {@code ElvargNPC} {@code Object}.
|
||||
* @param id The NPC id.
|
||||
* @param location The location.
|
||||
*/
|
||||
private ElvargNPC(int id, Location location) {
|
||||
super(id, location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractNPC construct(int id, Location location, Object... objects) {
|
||||
return new ElvargNPC(id, location);
|
||||
}
|
||||
@Override
|
||||
public AbstractNPC construct(int id, Location location, Object... objects) {
|
||||
return new ElvargNPC(id, location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commenceDeath(Entity killer) {
|
||||
final Direction direction = Direction.getLogicalDirection(getLocation(), killer.getLocation());
|
||||
GameWorld.getPulser().submit(new Pulse(1, this) {
|
||||
@Override
|
||||
public boolean pulse() {
|
||||
faceLocation(getCenterLocation().transform(direction.getStepX() * 3, direction.getStepY() * 3, 0));
|
||||
return true;
|
||||
}
|
||||
});
|
||||
setDirection(direction);
|
||||
}
|
||||
@Override
|
||||
public void commenceDeath(Entity killer) {
|
||||
final Direction direction = Direction.getLogicalDirection(getLocation(), killer.getLocation());
|
||||
GameWorld.getPulser().submit(new Pulse(1, this) {
|
||||
@Override
|
||||
public boolean pulse() {
|
||||
faceLocation(getCenterLocation().transform(direction.getStepX() * 3, direction.getStepY() * 3, 0));
|
||||
return true;
|
||||
}
|
||||
});
|
||||
setDirection(direction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finalizeDeath(final Entity killer) {
|
||||
super.finalizeDeath(killer);
|
||||
final Scenery object = new Scenery(25202, getLocation(), getRotation());
|
||||
SceneryBuilder.add(object);
|
||||
killer.faceLocation(object.getCenterLocation());
|
||||
killer.lock();
|
||||
GameWorld.getPulser().submit(new Pulse(1) {
|
||||
int counter = 0;
|
||||
@Override
|
||||
public void finalizeDeath(final Entity killer) {
|
||||
super.finalizeDeath(killer);
|
||||
final Scenery object = new Scenery(25202, getLocation(), getRotation());
|
||||
SceneryBuilder.add(object);
|
||||
killer.faceLocation(object.getCenterLocation());
|
||||
killer.lock();
|
||||
GameWorld.getPulser().submit(new Pulse(1) {
|
||||
int counter = 0;
|
||||
|
||||
@Override
|
||||
public boolean pulse() {
|
||||
counter++;
|
||||
if (counter == 1) {
|
||||
killer.animate(ANIMATIONS[0]);
|
||||
} else if (counter == 4) {
|
||||
final Player player = ((Player) killer);
|
||||
SceneryBuilder.replace(object, object.transform(25203));
|
||||
if (!player.getInventory().add(DragonSlayer.ELVARG_HEAD)) {
|
||||
GroundItemManager.create(DragonSlayer.ELVARG_HEAD, player);
|
||||
}
|
||||
killer.animate(ANIMATIONS[1]);
|
||||
killer.unlock();
|
||||
} else if (counter == 12) {
|
||||
SceneryBuilder.remove(RegionManager.getObject(object.getLocation()));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean pulse() {
|
||||
counter++;
|
||||
if (counter == 1) {
|
||||
killer.animate(ANIMATIONS[0]);
|
||||
} else if (counter == 4) {
|
||||
final Player player = ((Player) killer);
|
||||
SceneryBuilder.replace(object, object.transform(25203));
|
||||
if (!player.getInventory().add(DragonSlayer.ELVARG_HEAD)) {
|
||||
GroundItemManager.create(DragonSlayer.ELVARG_HEAD, player);
|
||||
}
|
||||
killer.animate(ANIMATIONS[1]);
|
||||
killer.unlock();
|
||||
} else if (counter == 12) {
|
||||
SceneryBuilder.remove(RegionManager.getObject(object.getLocation()));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public CombatSwingHandler getSwingHandler(boolean swing) {
|
||||
return combatHandler;
|
||||
}
|
||||
@Override
|
||||
public CombatSwingHandler getSwingHandler(boolean swing) {
|
||||
return combatHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getIds() {
|
||||
return ID;
|
||||
}
|
||||
@Override
|
||||
public int[] getIds() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method used to get the rotation.
|
||||
* @return the rotation.
|
||||
*/
|
||||
public int getRotation() {
|
||||
switch (getDirection()) {
|
||||
case EAST:
|
||||
return 3;
|
||||
case NORTH:
|
||||
return 2;
|
||||
case WEST:
|
||||
return 1;
|
||||
case SOUTH:
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* Method used to get the rotation.
|
||||
* @return the rotation.
|
||||
*/
|
||||
public int getRotation() {
|
||||
switch (getDirection()) {
|
||||
case EAST:
|
||||
return 3;
|
||||
case NORTH:
|
||||
return 2;
|
||||
case WEST:
|
||||
return 1;
|
||||
case SOUTH:
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAttackable(Entity entity, CombatStyle style, boolean message) {
|
||||
if (!(entity instanceof Player)) {
|
||||
return super.isAttackable(entity, style, message);
|
||||
}
|
||||
final Player player = (Player) entity;
|
||||
if (player.getQuestRepository().getQuest("Dragon Slayer").getStage(player) == 40 && (player.getInventory().containsItem(DragonSlayer.ELVARG_HEAD))) {
|
||||
@Override
|
||||
public boolean isAttackable(Entity entity, CombatStyle style, boolean message) {
|
||||
if (!(entity instanceof Player)) {
|
||||
return super.isAttackable(entity, style, message);
|
||||
}
|
||||
final Player player = (Player) entity;
|
||||
if (player.getQuestRepository().getQuest("Dragon Slayer").getStage(player) == 40 && (player.getInventory().containsItem(DragonSlayer.ELVARG_HEAD))) {
|
||||
if(message) {
|
||||
player.getPacketDispatch().sendMessage("You have already slain the dragon. Now you just need to return to Oziach for");
|
||||
player.getPacketDispatch().sendMessage("your reward!");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (player.getQuestRepository().getQuest("Dragon Slayer").getStage(player) > 40) {
|
||||
return false;
|
||||
}
|
||||
if (player.getQuestRepository().getQuest("Dragon Slayer").getStage(player) > 40) {
|
||||
if(message) {
|
||||
player.getPacketDispatch().sendMessage("You have already slain Elvarg.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return super.isAttackable(entity, style, message);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return super.isAttackable(entity, style, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDragonfireProtection(boolean fire) {
|
||||
return 0x2 | 0x4 | 0x8;
|
||||
}
|
||||
@Override
|
||||
public int getDragonfireProtection(boolean fire) {
|
||||
return 0x2 | 0x4 | 0x8;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the Elvarg combat swing handler.
|
||||
* @author Emperor
|
||||
*/
|
||||
static class ElvargCombatSwingHandler extends CombatSwingHandler {
|
||||
/**
|
||||
* Handles the Elvarg combat swing handler.
|
||||
* @author Emperor
|
||||
*/
|
||||
static class ElvargCombatSwingHandler extends CombatSwingHandler {
|
||||
|
||||
/**
|
||||
* The style.
|
||||
*/
|
||||
private CombatStyle style = CombatStyle.RANGE;
|
||||
/**
|
||||
* The style.
|
||||
*/
|
||||
private CombatStyle style = CombatStyle.RANGE;
|
||||
|
||||
/**
|
||||
* The melee attack animation.
|
||||
*/
|
||||
private static final Animation MELEE_ATTACK = new Animation(80, Priority.HIGH);
|
||||
/**
|
||||
* The melee attack animation.
|
||||
*/
|
||||
private static final Animation MELEE_ATTACK = new Animation(80, Priority.HIGH);
|
||||
|
||||
/**
|
||||
* The fire type.
|
||||
*/
|
||||
private final FireType fireType = FireType.FIERY_BREATH;
|
||||
/**
|
||||
* The fire type.
|
||||
*/
|
||||
private final FireType fireType = FireType.FIERY_BREATH;
|
||||
|
||||
/**
|
||||
* The DragonFire Attack */
|
||||
private static final DragonfireSwingHandler DRAGONFIRE = new DragonfireSwingHandler(false, 60, null, true);
|
||||
/**
|
||||
* The DragonFire Attack */
|
||||
private static final DragonfireSwingHandler DRAGONFIRE = new DragonfireSwingHandler(false, 60, null, true);
|
||||
|
||||
/**
|
||||
* Constructs a new {@Code ElvargCombatSwingHandler} {@Code CombatStyle}.
|
||||
* The Combat style.
|
||||
*/
|
||||
public ElvargCombatSwingHandler() {
|
||||
super(CombatStyle.RANGE);
|
||||
}
|
||||
/**
|
||||
* Constructs a new {@Code ElvargCombatSwingHandler} {@Code CombatStyle}.
|
||||
* The Combat style.
|
||||
*/
|
||||
public ElvargCombatSwingHandler() {
|
||||
super(CombatStyle.RANGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustBattleState(Entity entity, Entity victim, BattleState state) {
|
||||
if (style == CombatStyle.RANGE) {
|
||||
fireType.getTask().exec(victim, entity);
|
||||
state.setStyle(null);
|
||||
DRAGONFIRE.adjustBattleState(entity, victim, state);
|
||||
state.setStyle(CombatStyle.RANGE);
|
||||
return;
|
||||
}
|
||||
style.getSwingHandler().adjustBattleState(entity, victim, state);
|
||||
}
|
||||
@Override
|
||||
public void adjustBattleState(Entity entity, Entity victim, BattleState state) {
|
||||
if (style == CombatStyle.RANGE) {
|
||||
fireType.getTask().exec(victim, entity);
|
||||
state.setStyle(null);
|
||||
DRAGONFIRE.adjustBattleState(entity, victim, state);
|
||||
state.setStyle(CombatStyle.RANGE);
|
||||
return;
|
||||
}
|
||||
style.getSwingHandler().adjustBattleState(entity, victim, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int calculateAccuracy(Entity entity) {
|
||||
// If in melee combat, calculate attackers accuracy level.
|
||||
if (style == CombatStyle.MELEE) {
|
||||
return style.getSwingHandler().calculateAccuracy(entity);
|
||||
}
|
||||
// Else calculate attackers accuracy based on their magic level.
|
||||
return CombatStyle.MAGIC.getSwingHandler().calculateAccuracy(entity);
|
||||
}
|
||||
@Override
|
||||
public int calculateAccuracy(Entity entity) {
|
||||
// If in melee combat, calculate attackers accuracy level.
|
||||
if (style == CombatStyle.MELEE) {
|
||||
return style.getSwingHandler().calculateAccuracy(entity);
|
||||
}
|
||||
// Else calculate attackers accuracy based on their magic level.
|
||||
return CombatStyle.MAGIC.getSwingHandler().calculateAccuracy(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int calculateDefence(Entity victim, Entity attacker) {
|
||||
// If in melee combat, calculate players defense level.
|
||||
if (style == CombatStyle.MELEE) {
|
||||
return style.getSwingHandler().calculateDefence(victim, attacker);
|
||||
}
|
||||
// Else calculate players defense against attack based on their magic level.
|
||||
return CombatStyle.MAGIC.getSwingHandler().calculateDefence(victim, attacker);
|
||||
}
|
||||
@Override
|
||||
public int calculateDefence(Entity victim, Entity attacker) {
|
||||
// If in melee combat, calculate players defense level.
|
||||
if (style == CombatStyle.MELEE) {
|
||||
return style.getSwingHandler().calculateDefence(victim, attacker);
|
||||
}
|
||||
// Else calculate players defense against attack based on their magic level.
|
||||
return CombatStyle.MAGIC.getSwingHandler().calculateDefence(victim, attacker);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int calculateHit(Entity entity, Entity victim, double modifier) {
|
||||
if (style == CombatStyle.MELEE) {
|
||||
return style.getSwingHandler().calculateHit(entity, victim, modifier);
|
||||
}
|
||||
int maxDamage = 60; // Max Possible hit without shield protection
|
||||
int finalDamage = maxDamage;
|
||||
@Override
|
||||
public int calculateHit(Entity entity, Entity victim, double modifier) {
|
||||
if (style == CombatStyle.MELEE) {
|
||||
return style.getSwingHandler().calculateHit(entity, victim, modifier);
|
||||
}
|
||||
|
||||
if (victim instanceof Player) {
|
||||
int val = victim.getDragonfireProtection(true); // DragonFireShield Protection
|
||||
return calculateDragonfireMaxHit(victim, 60, false, 3, true);
|
||||
}
|
||||
|
||||
if ((val & 0x2) != 0) { // 0x2 - Anti Fire potion used?
|
||||
finalDamage -= 0.22 * maxDamage; // = 20% protection
|
||||
}
|
||||
if ((val & 0x4) != 0) { // 0x4 - Anti Dragon Fire Shield equipped?
|
||||
finalDamage -= 0.78 * maxDamage; // Should always equal 13 as that is the max hit possible with the shield equipped, 80% protection
|
||||
}
|
||||
if ( (val & 0x2) == 0 && (val & 0x4) == 0 && (val & 0x8) != 0) { // 0x8 - Magic Prayer Protection, should not stack with the others
|
||||
finalDamage -= 0.6 * maxDamage; // = 36
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public InteractionType canSwing(Entity entity, Entity victim) {
|
||||
if (!isProjectileClipped(entity, victim, false)) {
|
||||
return InteractionType.NO_INTERACT;
|
||||
}
|
||||
if (victim.getCenterLocation().withinDistance(entity.getCenterLocation(), getCombatDistance(entity, victim, 9)) && super.canSwing(entity, victim) != InteractionType.NO_INTERACT) {
|
||||
entity.getWalkingQueue().reset();
|
||||
return InteractionType.STILL_INTERACT;
|
||||
}
|
||||
return InteractionType.NO_INTERACT;
|
||||
}
|
||||
|
||||
return finalDamage;
|
||||
}
|
||||
@Override
|
||||
public ArmourSet getArmourSet(Entity e) {
|
||||
return style.getSwingHandler().getArmourSet(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionType canSwing(Entity entity, Entity victim) {
|
||||
if (!isProjectileClipped(entity, victim, false)) {
|
||||
return InteractionType.NO_INTERACT;
|
||||
}
|
||||
if (victim.getCenterLocation().withinDistance(entity.getCenterLocation(), getCombatDistance(entity, victim, 9)) && super.canSwing(entity, victim) != InteractionType.NO_INTERACT) {
|
||||
entity.getWalkingQueue().reset();
|
||||
return InteractionType.STILL_INTERACT;
|
||||
}
|
||||
return InteractionType.NO_INTERACT;
|
||||
}
|
||||
@Override
|
||||
public double getSetMultiplier(Entity e, int skillId) {
|
||||
return style.getSwingHandler().getSetMultiplier(e, skillId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArmourSet getArmourSet(Entity e) {
|
||||
return style.getSwingHandler().getArmourSet(e);
|
||||
}
|
||||
@Override
|
||||
public void impact(Entity entity, Entity victim, BattleState state) {
|
||||
style.getSwingHandler().impact(entity, victim, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getSetMultiplier(Entity e, int skillId) {
|
||||
return style.getSwingHandler().getSetMultiplier(e, skillId);
|
||||
}
|
||||
@Override
|
||||
public int swing(Entity entity, Entity victim, BattleState state) {
|
||||
style = CombatStyle.RANGE;
|
||||
int hit = 0;
|
||||
int ticks = 1;
|
||||
|
||||
@Override
|
||||
public void impact(Entity entity, Entity victim, BattleState state) {
|
||||
style.getSwingHandler().impact(entity, victim, state);
|
||||
}
|
||||
if (victim.getCenterLocation().withinDistance(entity.getCenterLocation(), getCombatDistance(entity, victim, 1)) ) {
|
||||
if ( RandomFunction.random(10) < 7 ){
|
||||
style = CombatStyle.MELEE;
|
||||
}
|
||||
} else {
|
||||
ticks += (int) Math.ceil(entity.getLocation().getDistance(victim.getLocation()) * 0.3);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int swing(Entity entity, Entity victim, BattleState state) {
|
||||
style = CombatStyle.RANGE;
|
||||
int hit = 0;
|
||||
int ticks = 1;
|
||||
state.setStyle(style);
|
||||
|
||||
if (victim.getCenterLocation().withinDistance(entity.getCenterLocation(), getCombatDistance(entity, victim, 1)) ) {
|
||||
if ( RandomFunction.random(10) < 7 ){
|
||||
style = CombatStyle.MELEE;
|
||||
}
|
||||
} else {
|
||||
ticks += (int) Math.ceil(entity.getLocation().getDistance(victim.getLocation()) * 0.3);
|
||||
}
|
||||
if (isAccurateImpact(entity, victim)) {
|
||||
int max = calculateHit(entity, victim, 1.0);
|
||||
state.setMaximumHit(max);
|
||||
hit = RandomFunction.random(max + 1);
|
||||
}
|
||||
state.setEstimatedHit(hit);
|
||||
return ticks;
|
||||
}
|
||||
|
||||
state.setStyle(style);
|
||||
@Override
|
||||
public void visualize(Entity entity, Entity victim, BattleState state) {
|
||||
switch (style) {
|
||||
case MELEE:
|
||||
entity.animate(MELEE_ATTACK);
|
||||
break;
|
||||
case RANGE:
|
||||
Projectile.ranged(entity, victim, 450, 20, 36, 50, 15).send();
|
||||
entity.animate(fireType.getAnimation());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isAccurateImpact(entity, victim)) {
|
||||
int max = calculateHit(entity, victim, 1.0);
|
||||
state.setMaximumHit(max);
|
||||
hit = RandomFunction.random(max);
|
||||
}
|
||||
state.setEstimatedHit(hit);
|
||||
return ticks;
|
||||
}
|
||||
@Override
|
||||
public void visualizeImpact(Entity entity, Entity victim, BattleState state) {
|
||||
if (style != CombatStyle.MELEE) {
|
||||
DRAGONFIRE.visualizeImpact(entity, victim, state);
|
||||
} else {
|
||||
style.getSwingHandler().visualizeImpact(entity, victim, state);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visualize(Entity entity, Entity victim, BattleState state) {
|
||||
switch (style) {
|
||||
case MELEE:
|
||||
entity.animate(MELEE_ATTACK);
|
||||
break;
|
||||
case RANGE:
|
||||
Projectile.ranged(entity, victim, 450, 20, 36, 50, 15).send();
|
||||
entity.animate(fireType.getAnimation());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visualizeImpact(Entity entity, Entity victim, BattleState state) {
|
||||
if (style != CombatStyle.MELEE) {
|
||||
DRAGONFIRE.visualizeImpact(entity, victim, state);
|
||||
} else {
|
||||
style.getSwingHandler().visualizeImpact(entity, victim, state);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ import core.plugin.Initializable;
|
||||
import core.plugin.Plugin;
|
||||
import core.tools.RandomFunction;
|
||||
|
||||
import static core.api.ContentAPIKt.calculateDragonfireMaxHit;
|
||||
|
||||
/**
|
||||
* Represents the King Black Dragon NPC.
|
||||
* @author Emperor
|
||||
@@ -28,236 +30,216 @@ import core.tools.RandomFunction;
|
||||
@Initializable
|
||||
public final class KingBlackDragonNPC extends AbstractNPC {
|
||||
|
||||
/**
|
||||
* The default spawn location.
|
||||
*/
|
||||
private static final Location DEFAULT_SPAWN = Location.create(2273, 4698, 0);
|
||||
/**
|
||||
* The default spawn location.
|
||||
*/
|
||||
private static final Location DEFAULT_SPAWN = Location.create(2273, 4698, 0);
|
||||
|
||||
/**
|
||||
* The combat swing handler.
|
||||
*/
|
||||
private CombatSwingHandler combatHandler = new KBDCombatSwingHandler();
|
||||
/**
|
||||
* The combat swing handler.
|
||||
*/
|
||||
private CombatSwingHandler combatHandler = new KBDCombatSwingHandler();
|
||||
|
||||
|
||||
public KingBlackDragonNPC() {
|
||||
super(-1,null);
|
||||
}
|
||||
|
||||
public KingBlackDragonNPC() {
|
||||
super(-1,null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finalizeDeath(Entity killer) {
|
||||
super.finalizeDeath(killer);
|
||||
BossKillCounter.addtoKillcount((Player) killer, this.getId());
|
||||
}
|
||||
@Override
|
||||
public void finalizeDeath(Entity killer) {
|
||||
super.finalizeDeath(killer);
|
||||
BossKillCounter.addtoKillcount((Player) killer, this.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code KingBlackDragonNPC} {@code Object}.
|
||||
* @param id the id.
|
||||
* @param l the l.
|
||||
*/
|
||||
public KingBlackDragonNPC(int id, Location l) {
|
||||
super(id, l);
|
||||
}
|
||||
/**
|
||||
* Constructs a new {@code KingBlackDragonNPC} {@code Object}.
|
||||
* @param id the id.
|
||||
* @param l the l.
|
||||
*/
|
||||
public KingBlackDragonNPC(int id, Location l) {
|
||||
super(id, l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
super.init();
|
||||
configureBossData();
|
||||
}
|
||||
@Override
|
||||
public void init() {
|
||||
super.init();
|
||||
configureBossData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractNPC construct(int id, Location location, Object... objects) {
|
||||
return new KingBlackDragonNPC(id, location);
|
||||
}
|
||||
@Override
|
||||
public AbstractNPC construct(int id, Location location, Object... objects) {
|
||||
return new KingBlackDragonNPC(id, location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDragonfireProtection(boolean fire) {
|
||||
return 0x2 | 0x4 | 0x8;
|
||||
}
|
||||
@Override
|
||||
public int getDragonfireProtection(boolean fire) {
|
||||
return 0x2 | 0x4 | 0x8;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getIds() {
|
||||
return new int[] { 50 };
|
||||
}
|
||||
@Override
|
||||
public int[] getIds() {
|
||||
return new int[] { 50 };
|
||||
}
|
||||
|
||||
@Override
|
||||
public CombatSwingHandler getSwingHandler(boolean swing) {
|
||||
return combatHandler;
|
||||
}
|
||||
@Override
|
||||
public CombatSwingHandler getSwingHandler(boolean swing) {
|
||||
return combatHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Plugin<Object> newInstance(Object arg) throws Throwable {
|
||||
return super.newInstance(arg);
|
||||
}
|
||||
@Override
|
||||
public Plugin<Object> newInstance(Object arg) throws Throwable {
|
||||
return super.newInstance(arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the King Black Dragon's combat swings.
|
||||
* @author Emperor
|
||||
*/
|
||||
static class KBDCombatSwingHandler extends CombatSwingHandler {
|
||||
/**
|
||||
* Handles the King Black Dragon's combat swings.
|
||||
* @author Emperor
|
||||
*/
|
||||
static class KBDCombatSwingHandler extends CombatSwingHandler {
|
||||
|
||||
/**
|
||||
* The style.
|
||||
*/
|
||||
private CombatStyle style = CombatStyle.RANGE;
|
||||
|
||||
/**
|
||||
* Dragonfire.
|
||||
*/
|
||||
private static final DragonfireSwingHandler DRAGONFIRE = new DragonfireSwingHandler(false, 56, null, true);
|
||||
|
||||
/**
|
||||
* The melee attack animation.
|
||||
*/
|
||||
private static final Animation MELEE_ATTACK = new Animation(80, Priority.HIGH);
|
||||
|
||||
/**
|
||||
* The fire type.
|
||||
*/
|
||||
private FireType fireType = FireType.FIERY_BREATH;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code KBDCombatSwingHandler} {@Code Object}.
|
||||
/**
|
||||
* The style.
|
||||
*/
|
||||
public KBDCombatSwingHandler() {
|
||||
super(CombatStyle.RANGE);
|
||||
}
|
||||
private CombatStyle style = CombatStyle.RANGE;
|
||||
|
||||
@Override
|
||||
public void adjustBattleState(Entity entity, Entity victim, BattleState state) {
|
||||
if (style == CombatStyle.RANGE) {
|
||||
fireType.getTask().exec(victim, entity);
|
||||
state.setStyle(null);
|
||||
DRAGONFIRE.adjustBattleState(entity, victim, state);
|
||||
state.setStyle(CombatStyle.RANGE);
|
||||
return;
|
||||
}
|
||||
style.getSwingHandler().adjustBattleState(entity, victim, state);
|
||||
}
|
||||
/**
|
||||
* Dragonfire.
|
||||
*/
|
||||
private static final DragonfireSwingHandler DRAGONFIRE = new DragonfireSwingHandler(false, 56, null, true);
|
||||
|
||||
@Override
|
||||
public int calculateAccuracy(Entity entity) {
|
||||
if (style == CombatStyle.MELEE) {
|
||||
return style.getSwingHandler().calculateAccuracy(entity);
|
||||
}
|
||||
return CombatStyle.MAGIC.getSwingHandler().calculateAccuracy(entity);
|
||||
}
|
||||
/**
|
||||
* The melee attack animation.
|
||||
*/
|
||||
private static final Animation MELEE_ATTACK = new Animation(80, Priority.HIGH);
|
||||
|
||||
@Override
|
||||
public int calculateDefence(Entity victim, Entity attacker) {
|
||||
if (style == CombatStyle.MELEE) {
|
||||
return style.getSwingHandler().calculateDefence(victim, attacker);
|
||||
}
|
||||
return CombatStyle.MAGIC.getSwingHandler().calculateDefence(victim, attacker);
|
||||
}
|
||||
/**
|
||||
* The fire type.
|
||||
*/
|
||||
private FireType fireType = FireType.FIERY_BREATH;
|
||||
|
||||
@Override
|
||||
public int calculateHit(Entity entity, Entity victim, double modifier) {
|
||||
if (style == CombatStyle.MELEE) {
|
||||
return style.getSwingHandler().calculateHit(entity, victim, modifier);
|
||||
}
|
||||
int max = 56;
|
||||
int damage = max;
|
||||
if (victim instanceof Player) {
|
||||
int val = victim.getDragonfireProtection(true);
|
||||
if ((val & 0x2) != 0) {
|
||||
damage *= 0.5;
|
||||
}
|
||||
if ((val & 0x4) != 0) {
|
||||
damage -= (int) (damage * 0.85);
|
||||
}
|
||||
if ((val & 0x8) != 0) {
|
||||
damage *= 0.6;
|
||||
}
|
||||
if (damage < 3) {
|
||||
damage = 3;
|
||||
}
|
||||
}
|
||||
if (fireType != FireType.FIERY_BREATH) {
|
||||
damage += 11;
|
||||
}
|
||||
return damage;
|
||||
}
|
||||
/**
|
||||
* Constructs a new {@code KBDCombatSwingHandler} {@Code Object}.
|
||||
*/
|
||||
public KBDCombatSwingHandler() {
|
||||
super(CombatStyle.RANGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionType canSwing(Entity entity, Entity victim) {
|
||||
if (!isProjectileClipped(entity, victim, false)) {
|
||||
return InteractionType.NO_INTERACT;
|
||||
}
|
||||
if (victim.getCenterLocation().withinDistance(entity.getCenterLocation(), getCombatDistance(entity, victim, 9)) && super.canSwing(entity, victim) == InteractionType.STILL_INTERACT) {
|
||||
entity.getWalkingQueue().reset();
|
||||
return InteractionType.STILL_INTERACT;
|
||||
}
|
||||
return InteractionType.NO_INTERACT;
|
||||
}
|
||||
@Override
|
||||
public void adjustBattleState(Entity entity, Entity victim, BattleState state) {
|
||||
if (style == CombatStyle.RANGE) {
|
||||
fireType.getTask().exec(victim, entity);
|
||||
state.setStyle(null);
|
||||
DRAGONFIRE.adjustBattleState(entity, victim, state);
|
||||
state.setStyle(CombatStyle.RANGE);
|
||||
return;
|
||||
}
|
||||
style.getSwingHandler().adjustBattleState(entity, victim, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArmourSet getArmourSet(Entity e) {
|
||||
return style.getSwingHandler().getArmourSet(e);
|
||||
}
|
||||
@Override
|
||||
public int calculateAccuracy(Entity entity) {
|
||||
if (style == CombatStyle.MELEE) {
|
||||
return style.getSwingHandler().calculateAccuracy(entity);
|
||||
}
|
||||
return CombatStyle.MAGIC.getSwingHandler().calculateAccuracy(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getSetMultiplier(Entity e, int skillId) {
|
||||
return style.getSwingHandler().getSetMultiplier(e, skillId);
|
||||
}
|
||||
@Override
|
||||
public int calculateDefence(Entity victim, Entity attacker) {
|
||||
if (style == CombatStyle.MELEE) {
|
||||
return style.getSwingHandler().calculateDefence(victim, attacker);
|
||||
}
|
||||
return CombatStyle.MAGIC.getSwingHandler().calculateDefence(victim, attacker);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void impact(Entity entity, Entity victim, BattleState state) {
|
||||
style.getSwingHandler().impact(entity, victim, state);
|
||||
}
|
||||
@Override
|
||||
public int calculateHit(Entity entity, Entity victim, double modifier) {
|
||||
if (style == CombatStyle.MELEE) {
|
||||
return style.getSwingHandler().calculateHit(entity, victim, modifier);
|
||||
}
|
||||
return calculateDragonfireMaxHit(victim, 56, false, fireType != FireType.FIERY_BREATH ? 10 : 0, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int swing(Entity entity, Entity victim, BattleState state) {
|
||||
style = CombatStyle.RANGE;
|
||||
int hit = 0;
|
||||
int ticks = 1;
|
||||
if (victim.getCenterLocation().withinDistance(entity.getCenterLocation(), getCombatDistance(entity, victim, 1)) && RandomFunction.random(10) < 7) {
|
||||
style = CombatStyle.MELEE;
|
||||
} else {
|
||||
ticks += (int) Math.ceil(entity.getLocation().getDistance(victim.getLocation()) * 0.3);
|
||||
}
|
||||
fireType = FireType.values()[RandomFunction.random(FireType.values().length)];
|
||||
state.setStyle(style);
|
||||
if (isAccurateImpact(entity, victim)) {
|
||||
int max = calculateHit(entity, victim, 1.0);
|
||||
state.setMaximumHit(max);
|
||||
hit = RandomFunction.random(max);
|
||||
}
|
||||
state.setEstimatedHit(hit);
|
||||
((NPC) entity).getAggressiveHandler().setPauseTicks(2);
|
||||
return ticks;
|
||||
}
|
||||
@Override
|
||||
public InteractionType canSwing(Entity entity, Entity victim) {
|
||||
if (!isProjectileClipped(entity, victim, false)) {
|
||||
return InteractionType.NO_INTERACT;
|
||||
}
|
||||
if (victim.getCenterLocation().withinMaxnormDistance(entity.getCenterLocation(), getCombatDistance(entity, victim, 9)) && super.canSwing(entity, victim) == InteractionType.STILL_INTERACT) {
|
||||
entity.getWalkingQueue().reset();
|
||||
return InteractionType.STILL_INTERACT;
|
||||
}
|
||||
return InteractionType.NO_INTERACT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visualize(Entity entity, Entity victim, BattleState state) {
|
||||
switch (style) {
|
||||
case MELEE:
|
||||
entity.animate(MELEE_ATTACK);
|
||||
break;
|
||||
case RANGE:
|
||||
Projectile.ranged(entity, victim, fireType.getProjectileId(), 20, 36, 50, 15).send();
|
||||
entity.animate(fireType.getAnimation());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public ArmourSet getArmourSet(Entity e) {
|
||||
return style.getSwingHandler().getArmourSet(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visualizeImpact(Entity entity, Entity victim, BattleState state) {
|
||||
if (style != CombatStyle.MELEE) {
|
||||
DRAGONFIRE.visualizeImpact(entity, victim, state);
|
||||
} else {
|
||||
style.getSwingHandler().visualizeImpact(entity, victim, state);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public double getSetMultiplier(Entity e, int skillId) {
|
||||
return style.getSwingHandler().getSetMultiplier(e, skillId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the fire type.
|
||||
* @return the type.
|
||||
*/
|
||||
public FireType getFireType() {
|
||||
return fireType;
|
||||
}
|
||||
@Override
|
||||
public void impact(Entity entity, Entity victim, BattleState state) {
|
||||
style.getSwingHandler().impact(entity, victim, state);
|
||||
}
|
||||
|
||||
}
|
||||
@Override
|
||||
public int swing(Entity entity, Entity victim, BattleState state) {
|
||||
style = CombatStyle.RANGE;
|
||||
int hit = 0;
|
||||
int ticks = 1;
|
||||
if (victim.getCenterLocation().withinMaxnormDistance(entity.getCenterLocation(), getCombatDistance(entity, victim, 1)) && RandomFunction.random(10) < 7) {
|
||||
style = CombatStyle.MELEE;
|
||||
} else {
|
||||
ticks += (int) Math.ceil(entity.getLocation().getDistance(victim.getLocation()) * 0.3);
|
||||
}
|
||||
fireType = FireType.values()[RandomFunction.random(FireType.values().length)];
|
||||
state.setStyle(style);
|
||||
if (isAccurateImpact(entity, victim)) {
|
||||
int max = calculateHit(entity, victim, 1.0);
|
||||
state.setMaximumHit(max);
|
||||
hit = RandomFunction.random(max + 1);
|
||||
}
|
||||
state.setEstimatedHit(hit);
|
||||
((NPC) entity).getAggressiveHandler().setPauseTicks(2);
|
||||
return ticks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visualize(Entity entity, Entity victim, BattleState state) {
|
||||
switch (style) {
|
||||
case MELEE:
|
||||
entity.animate(MELEE_ATTACK);
|
||||
break;
|
||||
case RANGE:
|
||||
Projectile.ranged(entity, victim, fireType.getProjectileId(), 20, 36, 50, 15).send();
|
||||
entity.animate(fireType.getAnimation());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visualizeImpact(Entity entity, Entity victim, BattleState state) {
|
||||
if (style != CombatStyle.MELEE) {
|
||||
DRAGONFIRE.visualizeImpact(entity, victim, state);
|
||||
} else {
|
||||
style.getSwingHandler().visualizeImpact(entity, victim, state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the fire type.
|
||||
* @return the type.
|
||||
*/
|
||||
public FireType getFireType() {
|
||||
return fireType;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import core.game.node.entity.player.link.TeleportManager
|
||||
import core.game.node.entity.player.link.audio.Audio
|
||||
import core.game.node.entity.player.link.emote.Emotes
|
||||
import core.game.node.entity.player.link.quest.QuestRepository
|
||||
import core.game.node.entity.player.link.prayer.PrayerType;
|
||||
import core.game.node.entity.skill.Skills
|
||||
import content.data.skill.SkillingTool
|
||||
import content.global.skill.slayer.Tasks
|
||||
@@ -2462,4 +2463,73 @@ fun decantContainer (container: core.game.container.Container) : Pair<List<Item>
|
||||
return Pair<List<Item>,List<Item>>(toRemove, toAdd)
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the user has a valid anti-dragonfire shield equipped.
|
||||
* @param player the player whose shield we are checking.
|
||||
* @param wyvern an optional parameter (default false) whether or not we are checking against wyvern fire, which ignores normal anti-dragon-shields, but accepts elemental/mind shields, etc.
|
||||
* @return whether or not the player is protected by their shield.
|
||||
* @see <a href=https://runescape.wiki/w/Dragonfire?oldid=2068032>Source</a>
|
||||
**/
|
||||
fun hasDragonfireShieldProtection(player: Player, wyvern: Boolean = false): Boolean {
|
||||
val shield = getItemFromEquipment(player, EquipmentSlot.SHIELD) ?: return false
|
||||
return when (shield.id) {
|
||||
Items.ELEMENTAL_SHIELD_2890, Items.MIND_SHIELD_9731 -> wyvern
|
||||
Items.ANTI_DRAGON_SHIELD_1540 -> !wyvern
|
||||
Items.DRAGONFIRE_SHIELD_11283, Items.DRAGONFIRE_SHIELD_11284 -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the expected max hit of dragonfire after checking/applying valid protections.
|
||||
* @param entity the entity whose protection we are checking.
|
||||
* @param maxDamage the max damage the dragonfire can do without protection.
|
||||
* @param wyvern an optional parameter (default false) that defines whether or not this is wyvern fire. Wyvern fire ignores anti-fire potions and regular anti-dragon shield.
|
||||
* @param unprotectableDamage an optional parameter (default 0) that defines how much damage cannot be protected against. Think of it as a minimum-max-hit.
|
||||
* @param sendMessage an optional parameter (default false) whether or not to send a message notifying the player of the damage being blocked.
|
||||
* @return the maximum amount of damage that can be done to the player.
|
||||
* @see <a href=https://runescape.wiki/w/Dragonfire?oldid=2068032>Source</a>
|
||||
**/
|
||||
fun calculateDragonfireMaxHit(entity: Entity, maxDamage: Int, wyvern: Boolean = false, unprotectableDamage: Int = 0, sendMessage: Boolean = false): Int {
|
||||
val hasShield: Boolean
|
||||
val hasPotion: Boolean
|
||||
val hasPrayer: Boolean
|
||||
|
||||
if (entity is Player) {
|
||||
hasShield = hasDragonfireShieldProtection(entity, wyvern)
|
||||
hasPotion = !wyvern && getAttribute(entity, "fire:immune", 0) >= getWorldTicks()
|
||||
hasPrayer = entity.prayer.get(PrayerType.PROTECT_FROM_MAGIC)
|
||||
|
||||
if (sendMessage) {
|
||||
var message = "You are horribly burnt by the ${if (wyvern) "icy" else "fiery"} breath."
|
||||
if (hasShield && hasPotion)
|
||||
message = "Your potion and shield fully absorb the ${if (wyvern) "icy" else "fiery"} breath."
|
||||
else if (hasShield)
|
||||
message = "Your shield absorbs most of the ${if (wyvern) "icy" else "fiery"} breath."
|
||||
else if (hasPotion)
|
||||
message = "Your potion absorbs some of the fiery breath."
|
||||
else if (hasPrayer)
|
||||
message = "Your prayer absorbs some of the ${if (wyvern) "icy" else "fiery"} breath."
|
||||
sendMessage(entity, message)
|
||||
}
|
||||
} else {
|
||||
val dragonfireTokens = entity.getDragonfireProtection(!wyvern)
|
||||
hasShield = dragonfireTokens and 0x2 != 0
|
||||
hasPotion = dragonfireTokens and 0x4 != 0
|
||||
hasPrayer = dragonfireTokens and 0x8 != 0
|
||||
}
|
||||
|
||||
var effectiveDamage = maxDamage.toDouble()
|
||||
if (hasPrayer && !hasShield && !hasPotion)
|
||||
effectiveDamage -= 0.6 * maxDamage
|
||||
else {
|
||||
if (hasShield)
|
||||
effectiveDamage -= 0.8 * maxDamage
|
||||
if (hasPotion)
|
||||
effectiveDamage -= 0.2 * maxDamage
|
||||
}
|
||||
|
||||
return Math.max(unprotectableDamage, effectiveDamage.toInt())
|
||||
}
|
||||
|
||||
private class ContentAPI
|
||||
|
||||
Reference in New Issue
Block a user