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.game.world.update.flag.context.Graphics;
|
||||||
import core.tools.RandomFunction;
|
import core.tools.RandomFunction;
|
||||||
|
|
||||||
|
import static core.api.ContentAPIKt.calculateDragonfireMaxHit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles dragonfire combat.
|
* Handles dragonfire combat.
|
||||||
* @author Emperor
|
* @author Emperor
|
||||||
*/
|
*/
|
||||||
public class DragonfireSwingHandler extends CombatSwingHandler {
|
public class DragonfireSwingHandler extends CombatSwingHandler {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the NPC has to be in melee range.
|
* If the NPC has to be in melee range.
|
||||||
*/
|
*/
|
||||||
private boolean meleeRange;
|
private boolean meleeRange;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The maximum hit.
|
* The maximum hit.
|
||||||
*/
|
*/
|
||||||
private int maximumHit;
|
private int maximumHit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The attack data.
|
* The attack data.
|
||||||
*/
|
*/
|
||||||
private SwitchAttack attack;
|
private SwitchAttack attack;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IF the dragon attack is firey or icey.
|
* IF the dragon attack is firey or icey.
|
||||||
*/
|
*/
|
||||||
private boolean fire;
|
private boolean fire;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new {@code DragonfireSwingHandler} {@code Object}.
|
* Constructs a new {@code DragonfireSwingHandler} {@code Object}.
|
||||||
* @param meleeRange If the NPC has to be in melee range.
|
* @param meleeRange If the NPC has to be in melee range.
|
||||||
* @param maximumHit The maximum hit.
|
* @param maximumHit The maximum hit.
|
||||||
* @param fire if firey.
|
* @param fire if firey.
|
||||||
*/
|
*/
|
||||||
public DragonfireSwingHandler(boolean meleeRange, int maximumHit, SwitchAttack attack, boolean fire) {
|
public DragonfireSwingHandler(boolean meleeRange, int maximumHit, SwitchAttack attack, boolean fire) {
|
||||||
super(CombatStyle.MAGIC);
|
super(CombatStyle.MAGIC);
|
||||||
this.meleeRange = meleeRange;
|
this.meleeRange = meleeRange;
|
||||||
this.maximumHit = maximumHit;
|
this.maximumHit = maximumHit;
|
||||||
this.attack = attack;
|
this.attack = attack;
|
||||||
this.fire = fire;
|
this.fire = fire;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the switch attack instance for a dragonfire attack.
|
* Gets the switch attack instance for a dragonfire attack.
|
||||||
* @param meleeRange If the attack is melee range.
|
* @param meleeRange If the attack is melee range.
|
||||||
* @param maximumHit The maximum hit.
|
* @param maximumHit The maximum hit.
|
||||||
* @param animation The animation.
|
* @param animation The animation.
|
||||||
* @param startGraphic The start graphic.
|
* @param startGraphic The start graphic.
|
||||||
* @param endGraphic The end graphic.
|
* @param endGraphic The end graphic.
|
||||||
* @param projectile The projectile.
|
* @param projectile The projectile.
|
||||||
* @return The switch attack instance.
|
* @return The switch attack instance.
|
||||||
*/
|
*/
|
||||||
public static SwitchAttack get(boolean meleeRange, int maximumHit, Animation animation, Graphics startGraphic, Graphics endGraphic, Projectile projectile) {
|
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);
|
SwitchAttack attack = new SwitchAttack(null, animation, startGraphic, endGraphic, projectile).setUseHandler(true);
|
||||||
attack.setHandler(new DragonfireSwingHandler(meleeRange, maximumHit, attack, true));
|
attack.setHandler(new DragonfireSwingHandler(meleeRange, maximumHit, attack, true));
|
||||||
return attack;
|
return attack;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the switch attack instance for a dragonfire attack.
|
* Gets the switch attack instance for a dragonfire attack.
|
||||||
* @param meleeRange If the attack is melee range.
|
* @param meleeRange If the attack is melee range.
|
||||||
* @param maximumHit The maximum hit.
|
* @param maximumHit The maximum hit.
|
||||||
* @param animation The animation.
|
* @param animation The animation.
|
||||||
* @param startGraphic The start graphic.
|
* @param startGraphic The start graphic.
|
||||||
* @param endGraphic The end graphic.
|
* @param endGraphic The end graphic.
|
||||||
* @param projectile The projectile.
|
* @param projectile The projectile.
|
||||||
* @return The switch attack instance.
|
* @return The switch attack instance.
|
||||||
*/
|
*/
|
||||||
public static SwitchAttack get(boolean meleeRange, int maximumHit, Animation animation, Graphics startGraphic, Graphics endGraphic, Projectile projectile, boolean fire) {
|
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);
|
SwitchAttack attack = new SwitchAttack(null, animation, startGraphic, endGraphic, projectile).setUseHandler(true);
|
||||||
attack.setHandler(new DragonfireSwingHandler(meleeRange, maximumHit, attack, fire));
|
attack.setHandler(new DragonfireSwingHandler(meleeRange, maximumHit, attack, fire));
|
||||||
return attack;
|
return attack;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InteractionType canSwing(Entity entity, Entity victim) {
|
public InteractionType canSwing(Entity entity, Entity victim) {
|
||||||
if (meleeRange) {
|
if (meleeRange) {
|
||||||
return CombatStyle.MELEE.getSwingHandler().canSwing(entity, victim);
|
return CombatStyle.MELEE.getSwingHandler().canSwing(entity, victim);
|
||||||
}
|
}
|
||||||
return CombatStyle.MAGIC.getSwingHandler().canSwing(entity, victim);
|
return CombatStyle.MAGIC.getSwingHandler().canSwing(entity, victim);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int swing(Entity entity, Entity victim, BattleState state) {
|
public int swing(Entity entity, Entity victim, BattleState state) {
|
||||||
int max = calculateHit(entity, victim, 1.0);
|
int max = calculateHit(entity, victim, 1.0);
|
||||||
int hit = RandomFunction.random(max);
|
int hit = RandomFunction.random(max + 1);
|
||||||
assert state != null;
|
assert state != null;
|
||||||
state.setMaximumHit(max);
|
state.setMaximumHit(max);
|
||||||
state.setStyle(CombatStyle.MAGIC);
|
state.setStyle(CombatStyle.MAGIC);
|
||||||
state.setEstimatedHit(hit);
|
state.setEstimatedHit(hit);
|
||||||
if (meleeRange) {
|
if (meleeRange) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
int ticks = 2 + (int) Math.floor(entity.getLocation().getDistance(victim.getLocation()) * 0.5);
|
int ticks = 2 + (int) Math.floor(entity.getLocation().getDistance(victim.getLocation()) * 0.5);
|
||||||
entity.setAttribute("fireBreath", GameWorld.getTicks() + (ticks + 2));
|
entity.setAttribute("fireBreath", GameWorld.getTicks() + (ticks + 2));
|
||||||
return ticks;
|
return ticks;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visualize(Entity entity, Entity victim, BattleState state) {
|
public void visualize(Entity entity, Entity victim, BattleState state) {
|
||||||
entity.visualize(attack.getAnimation(), attack.getStartGraphic());
|
entity.visualize(attack.getAnimation(), attack.getStartGraphic());
|
||||||
if (attack.getProjectile() != null) {
|
if (attack.getProjectile() != null) {
|
||||||
attack.getProjectile().copy(entity, victim, 5).send();
|
attack.getProjectile().copy(entity, victim, 5).send();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visualizeImpact(Entity entity, Entity victim, BattleState state) {
|
public void visualizeImpact(Entity entity, Entity victim, BattleState state) {
|
||||||
if (entity instanceof NPC && victim instanceof Player) {
|
if (entity instanceof NPC && victim instanceof Player) {
|
||||||
Player p = (Player) victim;
|
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);
|
||||||
Item shield = p.getEquipment().get(EquipmentContainer.SLOT_SHIELD);
|
if (shield != null && (shield.getId() == 11283 || shield.getId() == 11284)) {
|
||||||
if (shield != null && (shield.getId() == 11283 || shield.getId() == 11284)) {
|
if (shield.getId() == 11284) {
|
||||||
if (shield.getId() == 11284) {
|
p.getEquipment().replace(new Item(11283), EquipmentContainer.SLOT_SHIELD);
|
||||||
p.getEquipment().replace(new Item(11283), EquipmentContainer.SLOT_SHIELD);
|
shield = p.getEquipment().get(EquipmentContainer.SLOT_SHIELD);
|
||||||
shield = p.getEquipment().get(EquipmentContainer.SLOT_SHIELD);
|
shield.setCharge(0);
|
||||||
shield.setCharge(0);
|
}
|
||||||
}
|
if (shield.getCharge() < 1000) {
|
||||||
if (shield.getCharge() < 1000) {
|
shield.setCharge(shield.getCharge() + 20);
|
||||||
shield.setCharge(shield.getCharge() + 20);
|
EquipmentContainer.updateBonuses(p);
|
||||||
EquipmentContainer.updateBonuses(p);
|
p.getPacketDispatch().sendMessage("Your dragonfire shield glows more brightly.");
|
||||||
p.getPacketDispatch().sendMessage("Your dragonfire shield glows more brightly.");
|
|
||||||
|
|
||||||
p.faceLocation(entity.getCenterLocation());
|
p.faceLocation(entity.getCenterLocation());
|
||||||
victim.visualize(Animation.create(6695), Graphics.create(1163));
|
victim.visualize(Animation.create(6695), Graphics.create(1163));
|
||||||
} else {
|
} else {
|
||||||
p.getPacketDispatch().sendMessage("Your dragonfire shield is already fully charged.");
|
p.getPacketDispatch().sendMessage("Your dragonfire shield is already fully charged.");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!fire && victim.getAttribute("freeze_immunity", -1) < GameWorld.getTicks() && RandomFunction.random(4) == 2) {
|
if (!fire && victim.getAttribute("freeze_immunity", -1) < GameWorld.getTicks() && RandomFunction.random(4) == 2) {
|
||||||
victim.getStateManager().set(EntityState.FROZEN, 16);
|
victim.getStateManager().set(EntityState.FROZEN, 16);
|
||||||
victim.graphics(Graphics.create(502));
|
victim.graphics(Graphics.create(502));
|
||||||
}
|
}
|
||||||
Graphics graphic = attack != null ? attack.getEndGraphic() : null;
|
Graphics graphic = attack != null ? attack.getEndGraphic() : null;
|
||||||
victim.visualize(victim.getProperties().getDefenceAnimation(), graphic);
|
victim.visualize(victim.getProperties().getDefenceAnimation(), graphic);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void impact(Entity entity, Entity victim, BattleState state) {
|
public void impact(Entity entity, Entity victim, BattleState state) {
|
||||||
assert state != null;
|
assert state != null;
|
||||||
int hit = state.getEstimatedHit();
|
int hit = state.getEstimatedHit();
|
||||||
if (hit > -1) {
|
if (hit > -1) {
|
||||||
victim.getImpactHandler().handleImpact(entity, hit, CombatStyle.MAGIC, state);
|
victim.getImpactHandler().handleImpact(entity, hit, CombatStyle.MAGIC, state);
|
||||||
}
|
}
|
||||||
hit = state.getSecondaryHit();
|
hit = state.getSecondaryHit();
|
||||||
if (hit > -1) {
|
if (hit > -1) {
|
||||||
victim.getImpactHandler().handleImpact(entity, hit, CombatStyle.MAGIC, state);
|
victim.getImpactHandler().handleImpact(entity, hit, CombatStyle.MAGIC, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void adjustBattleState(Entity entity, Entity victim, BattleState state) {
|
public void adjustBattleState(Entity entity, Entity victim, BattleState state) {
|
||||||
if (victim.isPlayer() && !fire) {
|
if (victim.isPlayer() && !fire) {
|
||||||
Item item = victim.asPlayer().getEquipment().get(EquipmentContainer.SLOT_SHIELD);
|
Item item = victim.asPlayer().getEquipment().get(EquipmentContainer.SLOT_SHIELD);
|
||||||
if (item != null && (item.getId() == 2890 || item.getId() == 9731) && state.getEstimatedHit() > 10) {
|
if (item != null && (item.getId() == 2890 || item.getId() == 9731) && state.getEstimatedHit() > 10) {
|
||||||
state.setEstimatedHit(RandomFunction.random(10));
|
state.setEstimatedHit(RandomFunction.random(10));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CombatStyle style = state.getStyle();
|
CombatStyle style = state.getStyle();
|
||||||
super.adjustBattleState(entity, victim, state);
|
super.adjustBattleState(entity, victim, state);
|
||||||
state.setStyle(style);
|
state.setStyle(style);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int getFormattedHit(Entity entity, Entity victim, BattleState state, int hit) {
|
protected int getFormattedHit(Entity entity, Entity victim, BattleState state, int hit) {
|
||||||
return formatHit(victim, hit);
|
return formatHit(victim, hit);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int calculateAccuracy(Entity entity) {
|
public int calculateAccuracy(Entity entity) {
|
||||||
return 4000;
|
return 4000;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int calculateHit(Entity entity, Entity victim, double modifier) {
|
public int calculateHit(Entity entity, Entity victim, double modifier) {
|
||||||
int damage = maximumHit;
|
return calculateDragonfireMaxHit(victim, maximumHit, !fire, 0, true);
|
||||||
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
|
@Override
|
||||||
public int calculateDefence(Entity victim, Entity attacker) {
|
public int calculateDefence(Entity victim, Entity attacker) {
|
||||||
return CombatStyle.MAGIC.getSwingHandler().calculateDefence(victim, attacker);
|
return CombatStyle.MAGIC.getSwingHandler().calculateDefence(victim, attacker);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double getSetMultiplier(Entity e, int skillId) {
|
public double getSetMultiplier(Entity e, int skillId) {
|
||||||
return 1.0;
|
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)
|
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 {
|
override fun getSwingHandlerOverride(self: NPC, original: CombatSwingHandler): CombatSwingHandler {
|
||||||
val victim = self.properties.combatPulse.getVictim() ?: return original
|
val victim = self.properties.combatPulse.getVictim() ?: return original
|
||||||
if (victim !is Player) return original
|
if (victim !is Player) return original
|
||||||
@@ -53,4 +40,4 @@ class SkeletalWyvernBehavior : NPCBehavior(*Tasks.SKELETAL_WYVERN.ids) {
|
|||||||
else
|
else
|
||||||
COMBAT_HANDLER
|
COMBAT_HANDLER
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+249
-263
@@ -25,6 +25,8 @@ import core.plugin.Initializable;
|
|||||||
import core.tools.RandomFunction;
|
import core.tools.RandomFunction;
|
||||||
import content.global.handlers.item.equipment.special.DragonfireSwingHandler;
|
import content.global.handlers.item.equipment.special.DragonfireSwingHandler;
|
||||||
|
|
||||||
|
import static core.api.ContentAPIKt.calculateDragonfireMaxHit;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the Elvarg npc.
|
* Represents the Elvarg npc.
|
||||||
@@ -34,311 +36,295 @@ import content.global.handlers.item.equipment.special.DragonfireSwingHandler;
|
|||||||
@Initializable
|
@Initializable
|
||||||
public final class ElvargNPC extends AbstractNPC {
|
public final class ElvargNPC extends AbstractNPC {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The NPC ids of NPCs using this plugin.
|
* The NPC ids of NPCs using this plugin.
|
||||||
*/
|
*/
|
||||||
private static final int[] ID = { 742 };
|
private static final int[] ID = { 742 };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the animations to use.
|
* Represents the animations to use.
|
||||||
*/
|
*/
|
||||||
private static final Animation[] ANIMATIONS = new Animation[] { new Animation(6654), new Animation(6655) };
|
private static final Animation[] ANIMATIONS = new Animation[] { new Animation(6654), new Animation(6655) };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the combat swing handler.
|
* Represents the combat swing handler.
|
||||||
*/
|
*/
|
||||||
private final CombatSwingHandler combatHandler = new ElvargCombatSwingHandler();
|
private final CombatSwingHandler combatHandler = new ElvargCombatSwingHandler();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new {@code ElvargNPC} {@code Object}.
|
* Constructs a new {@code ElvargNPC} {@code Object}.
|
||||||
*/
|
*/
|
||||||
public ElvargNPC() {
|
public ElvargNPC() {
|
||||||
super(0, null);
|
super(0, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new {@code ElvargNPC} {@code Object}.
|
* Constructs a new {@code ElvargNPC} {@code Object}.
|
||||||
* @param id The NPC id.
|
* @param id The NPC id.
|
||||||
* @param location The location.
|
* @param location The location.
|
||||||
*/
|
*/
|
||||||
private ElvargNPC(int id, Location location) {
|
private ElvargNPC(int id, Location location) {
|
||||||
super(id, location);
|
super(id, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AbstractNPC construct(int id, Location location, Object... objects) {
|
public AbstractNPC construct(int id, Location location, Object... objects) {
|
||||||
return new ElvargNPC(id, location);
|
return new ElvargNPC(id, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void commenceDeath(Entity killer) {
|
public void commenceDeath(Entity killer) {
|
||||||
final Direction direction = Direction.getLogicalDirection(getLocation(), killer.getLocation());
|
final Direction direction = Direction.getLogicalDirection(getLocation(), killer.getLocation());
|
||||||
GameWorld.getPulser().submit(new Pulse(1, this) {
|
GameWorld.getPulser().submit(new Pulse(1, this) {
|
||||||
@Override
|
@Override
|
||||||
public boolean pulse() {
|
public boolean pulse() {
|
||||||
faceLocation(getCenterLocation().transform(direction.getStepX() * 3, direction.getStepY() * 3, 0));
|
faceLocation(getCenterLocation().transform(direction.getStepX() * 3, direction.getStepY() * 3, 0));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
setDirection(direction);
|
setDirection(direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void finalizeDeath(final Entity killer) {
|
public void finalizeDeath(final Entity killer) {
|
||||||
super.finalizeDeath(killer);
|
super.finalizeDeath(killer);
|
||||||
final Scenery object = new Scenery(25202, getLocation(), getRotation());
|
final Scenery object = new Scenery(25202, getLocation(), getRotation());
|
||||||
SceneryBuilder.add(object);
|
SceneryBuilder.add(object);
|
||||||
killer.faceLocation(object.getCenterLocation());
|
killer.faceLocation(object.getCenterLocation());
|
||||||
killer.lock();
|
killer.lock();
|
||||||
GameWorld.getPulser().submit(new Pulse(1) {
|
GameWorld.getPulser().submit(new Pulse(1) {
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pulse() {
|
public boolean pulse() {
|
||||||
counter++;
|
counter++;
|
||||||
if (counter == 1) {
|
if (counter == 1) {
|
||||||
killer.animate(ANIMATIONS[0]);
|
killer.animate(ANIMATIONS[0]);
|
||||||
} else if (counter == 4) {
|
} else if (counter == 4) {
|
||||||
final Player player = ((Player) killer);
|
final Player player = ((Player) killer);
|
||||||
SceneryBuilder.replace(object, object.transform(25203));
|
SceneryBuilder.replace(object, object.transform(25203));
|
||||||
if (!player.getInventory().add(DragonSlayer.ELVARG_HEAD)) {
|
if (!player.getInventory().add(DragonSlayer.ELVARG_HEAD)) {
|
||||||
GroundItemManager.create(DragonSlayer.ELVARG_HEAD, player);
|
GroundItemManager.create(DragonSlayer.ELVARG_HEAD, player);
|
||||||
}
|
}
|
||||||
killer.animate(ANIMATIONS[1]);
|
killer.animate(ANIMATIONS[1]);
|
||||||
killer.unlock();
|
killer.unlock();
|
||||||
} else if (counter == 12) {
|
} else if (counter == 12) {
|
||||||
SceneryBuilder.remove(RegionManager.getObject(object.getLocation()));
|
SceneryBuilder.remove(RegionManager.getObject(object.getLocation()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CombatSwingHandler getSwingHandler(boolean swing) {
|
public CombatSwingHandler getSwingHandler(boolean swing) {
|
||||||
return combatHandler;
|
return combatHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int[] getIds() {
|
public int[] getIds() {
|
||||||
return ID;
|
return ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method used to get the rotation.
|
* Method used to get the rotation.
|
||||||
* @return the rotation.
|
* @return the rotation.
|
||||||
*/
|
*/
|
||||||
public int getRotation() {
|
public int getRotation() {
|
||||||
switch (getDirection()) {
|
switch (getDirection()) {
|
||||||
case EAST:
|
case EAST:
|
||||||
return 3;
|
return 3;
|
||||||
case NORTH:
|
case NORTH:
|
||||||
return 2;
|
return 2;
|
||||||
case WEST:
|
case WEST:
|
||||||
return 1;
|
return 1;
|
||||||
case SOUTH:
|
case SOUTH:
|
||||||
return 0;
|
return 0;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isAttackable(Entity entity, CombatStyle style, boolean message) {
|
public boolean isAttackable(Entity entity, CombatStyle style, boolean message) {
|
||||||
if (!(entity instanceof Player)) {
|
if (!(entity instanceof Player)) {
|
||||||
return super.isAttackable(entity, style, message);
|
return super.isAttackable(entity, style, message);
|
||||||
}
|
}
|
||||||
final Player player = (Player) entity;
|
final Player player = (Player) entity;
|
||||||
if (player.getQuestRepository().getQuest("Dragon Slayer").getStage(player) == 40 && (player.getInventory().containsItem(DragonSlayer.ELVARG_HEAD))) {
|
if (player.getQuestRepository().getQuest("Dragon Slayer").getStage(player) == 40 && (player.getInventory().containsItem(DragonSlayer.ELVARG_HEAD))) {
|
||||||
if(message) {
|
if(message) {
|
||||||
player.getPacketDispatch().sendMessage("You have already slain the dragon. Now you just need to return to Oziach for");
|
player.getPacketDispatch().sendMessage("You have already slain the dragon. Now you just need to return to Oziach for");
|
||||||
player.getPacketDispatch().sendMessage("your reward!");
|
player.getPacketDispatch().sendMessage("your reward!");
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (player.getQuestRepository().getQuest("Dragon Slayer").getStage(player) > 40) {
|
if (player.getQuestRepository().getQuest("Dragon Slayer").getStage(player) > 40) {
|
||||||
if(message) {
|
if(message) {
|
||||||
player.getPacketDispatch().sendMessage("You have already slain Elvarg.");
|
player.getPacketDispatch().sendMessage("You have already slain Elvarg.");
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return super.isAttackable(entity, style, message);
|
return super.isAttackable(entity, style, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getDragonfireProtection(boolean fire) {
|
public int getDragonfireProtection(boolean fire) {
|
||||||
return 0x2 | 0x4 | 0x8;
|
return 0x2 | 0x4 | 0x8;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the Elvarg combat swing handler.
|
* Handles the Elvarg combat swing handler.
|
||||||
* @author Emperor
|
* @author Emperor
|
||||||
*/
|
*/
|
||||||
static class ElvargCombatSwingHandler extends CombatSwingHandler {
|
static class ElvargCombatSwingHandler extends CombatSwingHandler {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The style.
|
* The style.
|
||||||
*/
|
*/
|
||||||
private CombatStyle style = CombatStyle.RANGE;
|
private CombatStyle style = CombatStyle.RANGE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The melee attack animation.
|
* The melee attack animation.
|
||||||
*/
|
*/
|
||||||
private static final Animation MELEE_ATTACK = new Animation(80, Priority.HIGH);
|
private static final Animation MELEE_ATTACK = new Animation(80, Priority.HIGH);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The fire type.
|
* The fire type.
|
||||||
*/
|
*/
|
||||||
private final FireType fireType = FireType.FIERY_BREATH;
|
private final FireType fireType = FireType.FIERY_BREATH;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The DragonFire Attack */
|
* The DragonFire Attack */
|
||||||
private static final DragonfireSwingHandler DRAGONFIRE = new DragonfireSwingHandler(false, 60, null, true);
|
private static final DragonfireSwingHandler DRAGONFIRE = new DragonfireSwingHandler(false, 60, null, true);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new {@Code ElvargCombatSwingHandler} {@Code CombatStyle}.
|
* Constructs a new {@Code ElvargCombatSwingHandler} {@Code CombatStyle}.
|
||||||
* The Combat style.
|
* The Combat style.
|
||||||
*/
|
*/
|
||||||
public ElvargCombatSwingHandler() {
|
public ElvargCombatSwingHandler() {
|
||||||
super(CombatStyle.RANGE);
|
super(CombatStyle.RANGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void adjustBattleState(Entity entity, Entity victim, BattleState state) {
|
public void adjustBattleState(Entity entity, Entity victim, BattleState state) {
|
||||||
if (style == CombatStyle.RANGE) {
|
if (style == CombatStyle.RANGE) {
|
||||||
fireType.getTask().exec(victim, entity);
|
fireType.getTask().exec(victim, entity);
|
||||||
state.setStyle(null);
|
state.setStyle(null);
|
||||||
DRAGONFIRE.adjustBattleState(entity, victim, state);
|
DRAGONFIRE.adjustBattleState(entity, victim, state);
|
||||||
state.setStyle(CombatStyle.RANGE);
|
state.setStyle(CombatStyle.RANGE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
style.getSwingHandler().adjustBattleState(entity, victim, state);
|
style.getSwingHandler().adjustBattleState(entity, victim, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int calculateAccuracy(Entity entity) {
|
public int calculateAccuracy(Entity entity) {
|
||||||
// If in melee combat, calculate attackers accuracy level.
|
// If in melee combat, calculate attackers accuracy level.
|
||||||
if (style == CombatStyle.MELEE) {
|
if (style == CombatStyle.MELEE) {
|
||||||
return style.getSwingHandler().calculateAccuracy(entity);
|
return style.getSwingHandler().calculateAccuracy(entity);
|
||||||
}
|
}
|
||||||
// Else calculate attackers accuracy based on their magic level.
|
// Else calculate attackers accuracy based on their magic level.
|
||||||
return CombatStyle.MAGIC.getSwingHandler().calculateAccuracy(entity);
|
return CombatStyle.MAGIC.getSwingHandler().calculateAccuracy(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int calculateDefence(Entity victim, Entity attacker) {
|
public int calculateDefence(Entity victim, Entity attacker) {
|
||||||
// If in melee combat, calculate players defense level.
|
// If in melee combat, calculate players defense level.
|
||||||
if (style == CombatStyle.MELEE) {
|
if (style == CombatStyle.MELEE) {
|
||||||
return style.getSwingHandler().calculateDefence(victim, attacker);
|
return style.getSwingHandler().calculateDefence(victim, attacker);
|
||||||
}
|
}
|
||||||
// Else calculate players defense against attack based on their magic level.
|
// Else calculate players defense against attack based on their magic level.
|
||||||
return CombatStyle.MAGIC.getSwingHandler().calculateDefence(victim, attacker);
|
return CombatStyle.MAGIC.getSwingHandler().calculateDefence(victim, attacker);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int calculateHit(Entity entity, Entity victim, double modifier) {
|
public int calculateHit(Entity entity, Entity victim, double modifier) {
|
||||||
if (style == CombatStyle.MELEE) {
|
if (style == CombatStyle.MELEE) {
|
||||||
return style.getSwingHandler().calculateHit(entity, victim, modifier);
|
return style.getSwingHandler().calculateHit(entity, victim, modifier);
|
||||||
}
|
}
|
||||||
int maxDamage = 60; // Max Possible hit without shield protection
|
|
||||||
int finalDamage = maxDamage;
|
|
||||||
|
|
||||||
if (victim instanceof Player) {
|
return calculateDragonfireMaxHit(victim, 60, false, 3, true);
|
||||||
int val = victim.getDragonfireProtection(true); // DragonFireShield Protection
|
}
|
||||||
|
|
||||||
if ((val & 0x2) != 0) { // 0x2 - Anti Fire potion used?
|
@Override
|
||||||
finalDamage -= 0.22 * maxDamage; // = 20% protection
|
public InteractionType canSwing(Entity entity, Entity victim) {
|
||||||
}
|
if (!isProjectileClipped(entity, victim, false)) {
|
||||||
if ((val & 0x4) != 0) { // 0x4 - Anti Dragon Fire Shield equipped?
|
return InteractionType.NO_INTERACT;
|
||||||
finalDamage -= 0.78 * maxDamage; // Should always equal 13 as that is the max hit possible with the shield equipped, 80% protection
|
}
|
||||||
}
|
if (victim.getCenterLocation().withinDistance(entity.getCenterLocation(), getCombatDistance(entity, victim, 9)) && super.canSwing(entity, victim) != InteractionType.NO_INTERACT) {
|
||||||
if ( (val & 0x2) == 0 && (val & 0x4) == 0 && (val & 0x8) != 0) { // 0x8 - Magic Prayer Protection, should not stack with the others
|
entity.getWalkingQueue().reset();
|
||||||
finalDamage -= 0.6 * maxDamage; // = 36
|
return InteractionType.STILL_INTERACT;
|
||||||
}
|
}
|
||||||
}
|
return InteractionType.NO_INTERACT;
|
||||||
|
}
|
||||||
|
|
||||||
return finalDamage;
|
@Override
|
||||||
}
|
public ArmourSet getArmourSet(Entity e) {
|
||||||
|
return style.getSwingHandler().getArmourSet(e);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InteractionType canSwing(Entity entity, Entity victim) {
|
public double getSetMultiplier(Entity e, int skillId) {
|
||||||
if (!isProjectileClipped(entity, victim, false)) {
|
return style.getSwingHandler().getSetMultiplier(e, skillId);
|
||||||
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
|
@Override
|
||||||
public ArmourSet getArmourSet(Entity e) {
|
public void impact(Entity entity, Entity victim, BattleState state) {
|
||||||
return style.getSwingHandler().getArmourSet(e);
|
style.getSwingHandler().impact(entity, victim, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double getSetMultiplier(Entity e, int skillId) {
|
public int swing(Entity entity, Entity victim, BattleState state) {
|
||||||
return style.getSwingHandler().getSetMultiplier(e, skillId);
|
style = CombatStyle.RANGE;
|
||||||
}
|
int hit = 0;
|
||||||
|
int ticks = 1;
|
||||||
|
|
||||||
@Override
|
if (victim.getCenterLocation().withinDistance(entity.getCenterLocation(), getCombatDistance(entity, victim, 1)) ) {
|
||||||
public void impact(Entity entity, Entity victim, BattleState state) {
|
if ( RandomFunction.random(10) < 7 ){
|
||||||
style.getSwingHandler().impact(entity, victim, state);
|
style = CombatStyle.MELEE;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
ticks += (int) Math.ceil(entity.getLocation().getDistance(victim.getLocation()) * 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
state.setStyle(style);
|
||||||
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)) ) {
|
if (isAccurateImpact(entity, victim)) {
|
||||||
if ( RandomFunction.random(10) < 7 ){
|
int max = calculateHit(entity, victim, 1.0);
|
||||||
style = CombatStyle.MELEE;
|
state.setMaximumHit(max);
|
||||||
}
|
hit = RandomFunction.random(max + 1);
|
||||||
} else {
|
}
|
||||||
ticks += (int) Math.ceil(entity.getLocation().getDistance(victim.getLocation()) * 0.3);
|
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)) {
|
@Override
|
||||||
int max = calculateHit(entity, victim, 1.0);
|
public void visualizeImpact(Entity entity, Entity victim, BattleState state) {
|
||||||
state.setMaximumHit(max);
|
if (style != CombatStyle.MELEE) {
|
||||||
hit = RandomFunction.random(max);
|
DRAGONFIRE.visualizeImpact(entity, victim, state);
|
||||||
}
|
} else {
|
||||||
state.setEstimatedHit(hit);
|
style.getSwingHandler().visualizeImpact(entity, victim, state);
|
||||||
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, 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.plugin.Plugin;
|
||||||
import core.tools.RandomFunction;
|
import core.tools.RandomFunction;
|
||||||
|
|
||||||
|
import static core.api.ContentAPIKt.calculateDragonfireMaxHit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the King Black Dragon NPC.
|
* Represents the King Black Dragon NPC.
|
||||||
* @author Emperor
|
* @author Emperor
|
||||||
@@ -28,236 +30,216 @@ import core.tools.RandomFunction;
|
|||||||
@Initializable
|
@Initializable
|
||||||
public final class KingBlackDragonNPC extends AbstractNPC {
|
public final class KingBlackDragonNPC extends AbstractNPC {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default spawn location.
|
* The default spawn location.
|
||||||
*/
|
*/
|
||||||
private static final Location DEFAULT_SPAWN = Location.create(2273, 4698, 0);
|
private static final Location DEFAULT_SPAWN = Location.create(2273, 4698, 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The combat swing handler.
|
* The combat swing handler.
|
||||||
*/
|
*/
|
||||||
private CombatSwingHandler combatHandler = new KBDCombatSwingHandler();
|
private CombatSwingHandler combatHandler = new KBDCombatSwingHandler();
|
||||||
|
|
||||||
|
|
||||||
public KingBlackDragonNPC() {
|
public KingBlackDragonNPC() {
|
||||||
super(-1,null);
|
super(-1,null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void finalizeDeath(Entity killer) {
|
public void finalizeDeath(Entity killer) {
|
||||||
super.finalizeDeath(killer);
|
super.finalizeDeath(killer);
|
||||||
BossKillCounter.addtoKillcount((Player) killer, this.getId());
|
BossKillCounter.addtoKillcount((Player) killer, this.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new {@code KingBlackDragonNPC} {@code Object}.
|
* Constructs a new {@code KingBlackDragonNPC} {@code Object}.
|
||||||
* @param id the id.
|
* @param id the id.
|
||||||
* @param l the l.
|
* @param l the l.
|
||||||
*/
|
*/
|
||||||
public KingBlackDragonNPC(int id, Location l) {
|
public KingBlackDragonNPC(int id, Location l) {
|
||||||
super(id, l);
|
super(id, l);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init() {
|
public void init() {
|
||||||
super.init();
|
super.init();
|
||||||
configureBossData();
|
configureBossData();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AbstractNPC construct(int id, Location location, Object... objects) {
|
public AbstractNPC construct(int id, Location location, Object... objects) {
|
||||||
return new KingBlackDragonNPC(id, location);
|
return new KingBlackDragonNPC(id, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getDragonfireProtection(boolean fire) {
|
public int getDragonfireProtection(boolean fire) {
|
||||||
return 0x2 | 0x4 | 0x8;
|
return 0x2 | 0x4 | 0x8;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int[] getIds() {
|
public int[] getIds() {
|
||||||
return new int[] { 50 };
|
return new int[] { 50 };
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CombatSwingHandler getSwingHandler(boolean swing) {
|
public CombatSwingHandler getSwingHandler(boolean swing) {
|
||||||
return combatHandler;
|
return combatHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Plugin<Object> newInstance(Object arg) throws Throwable {
|
public Plugin<Object> newInstance(Object arg) throws Throwable {
|
||||||
return super.newInstance(arg);
|
return super.newInstance(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the King Black Dragon's combat swings.
|
* Handles the King Black Dragon's combat swings.
|
||||||
* @author Emperor
|
* @author Emperor
|
||||||
*/
|
*/
|
||||||
static class KBDCombatSwingHandler extends CombatSwingHandler {
|
static class KBDCombatSwingHandler extends CombatSwingHandler {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The style.
|
* 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}.
|
|
||||||
*/
|
*/
|
||||||
public KBDCombatSwingHandler() {
|
private CombatStyle style = CombatStyle.RANGE;
|
||||||
super(CombatStyle.RANGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public void adjustBattleState(Entity entity, Entity victim, BattleState state) {
|
* Dragonfire.
|
||||||
if (style == CombatStyle.RANGE) {
|
*/
|
||||||
fireType.getTask().exec(victim, entity);
|
private static final DragonfireSwingHandler DRAGONFIRE = new DragonfireSwingHandler(false, 56, null, true);
|
||||||
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) {
|
* The melee attack animation.
|
||||||
if (style == CombatStyle.MELEE) {
|
*/
|
||||||
return style.getSwingHandler().calculateAccuracy(entity);
|
private static final Animation MELEE_ATTACK = new Animation(80, Priority.HIGH);
|
||||||
}
|
|
||||||
return CombatStyle.MAGIC.getSwingHandler().calculateAccuracy(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public int calculateDefence(Entity victim, Entity attacker) {
|
* The fire type.
|
||||||
if (style == CombatStyle.MELEE) {
|
*/
|
||||||
return style.getSwingHandler().calculateDefence(victim, attacker);
|
private FireType fireType = FireType.FIERY_BREATH;
|
||||||
}
|
|
||||||
return CombatStyle.MAGIC.getSwingHandler().calculateDefence(victim, attacker);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public int calculateHit(Entity entity, Entity victim, double modifier) {
|
* Constructs a new {@code KBDCombatSwingHandler} {@Code Object}.
|
||||||
if (style == CombatStyle.MELEE) {
|
*/
|
||||||
return style.getSwingHandler().calculateHit(entity, victim, modifier);
|
public KBDCombatSwingHandler() {
|
||||||
}
|
super(CombatStyle.RANGE);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InteractionType canSwing(Entity entity, Entity victim) {
|
public void adjustBattleState(Entity entity, Entity victim, BattleState state) {
|
||||||
if (!isProjectileClipped(entity, victim, false)) {
|
if (style == CombatStyle.RANGE) {
|
||||||
return InteractionType.NO_INTERACT;
|
fireType.getTask().exec(victim, entity);
|
||||||
}
|
state.setStyle(null);
|
||||||
if (victim.getCenterLocation().withinDistance(entity.getCenterLocation(), getCombatDistance(entity, victim, 9)) && super.canSwing(entity, victim) == InteractionType.STILL_INTERACT) {
|
DRAGONFIRE.adjustBattleState(entity, victim, state);
|
||||||
entity.getWalkingQueue().reset();
|
state.setStyle(CombatStyle.RANGE);
|
||||||
return InteractionType.STILL_INTERACT;
|
return;
|
||||||
}
|
}
|
||||||
return InteractionType.NO_INTERACT;
|
style.getSwingHandler().adjustBattleState(entity, victim, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ArmourSet getArmourSet(Entity e) {
|
public int calculateAccuracy(Entity entity) {
|
||||||
return style.getSwingHandler().getArmourSet(e);
|
if (style == CombatStyle.MELEE) {
|
||||||
}
|
return style.getSwingHandler().calculateAccuracy(entity);
|
||||||
|
}
|
||||||
|
return CombatStyle.MAGIC.getSwingHandler().calculateAccuracy(entity);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double getSetMultiplier(Entity e, int skillId) {
|
public int calculateDefence(Entity victim, Entity attacker) {
|
||||||
return style.getSwingHandler().getSetMultiplier(e, skillId);
|
if (style == CombatStyle.MELEE) {
|
||||||
}
|
return style.getSwingHandler().calculateDefence(victim, attacker);
|
||||||
|
}
|
||||||
|
return CombatStyle.MAGIC.getSwingHandler().calculateDefence(victim, attacker);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void impact(Entity entity, Entity victim, BattleState state) {
|
public int calculateHit(Entity entity, Entity victim, double modifier) {
|
||||||
style.getSwingHandler().impact(entity, victim, state);
|
if (style == CombatStyle.MELEE) {
|
||||||
}
|
return style.getSwingHandler().calculateHit(entity, victim, modifier);
|
||||||
|
}
|
||||||
|
return calculateDragonfireMaxHit(victim, 56, false, fireType != FireType.FIERY_BREATH ? 10 : 0, true);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int swing(Entity entity, Entity victim, BattleState state) {
|
public InteractionType canSwing(Entity entity, Entity victim) {
|
||||||
style = CombatStyle.RANGE;
|
if (!isProjectileClipped(entity, victim, false)) {
|
||||||
int hit = 0;
|
return InteractionType.NO_INTERACT;
|
||||||
int ticks = 1;
|
}
|
||||||
if (victim.getCenterLocation().withinDistance(entity.getCenterLocation(), getCombatDistance(entity, victim, 1)) && RandomFunction.random(10) < 7) {
|
if (victim.getCenterLocation().withinMaxnormDistance(entity.getCenterLocation(), getCombatDistance(entity, victim, 9)) && super.canSwing(entity, victim) == InteractionType.STILL_INTERACT) {
|
||||||
style = CombatStyle.MELEE;
|
entity.getWalkingQueue().reset();
|
||||||
} else {
|
return InteractionType.STILL_INTERACT;
|
||||||
ticks += (int) Math.ceil(entity.getLocation().getDistance(victim.getLocation()) * 0.3);
|
}
|
||||||
}
|
return InteractionType.NO_INTERACT;
|
||||||
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
|
@Override
|
||||||
public void visualize(Entity entity, Entity victim, BattleState state) {
|
public ArmourSet getArmourSet(Entity e) {
|
||||||
switch (style) {
|
return style.getSwingHandler().getArmourSet(e);
|
||||||
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
|
@Override
|
||||||
public void visualizeImpact(Entity entity, Entity victim, BattleState state) {
|
public double getSetMultiplier(Entity e, int skillId) {
|
||||||
if (style != CombatStyle.MELEE) {
|
return style.getSwingHandler().getSetMultiplier(e, skillId);
|
||||||
DRAGONFIRE.visualizeImpact(entity, victim, state);
|
}
|
||||||
} else {
|
|
||||||
style.getSwingHandler().visualizeImpact(entity, victim, state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Gets the fire type.
|
public void impact(Entity entity, Entity victim, BattleState state) {
|
||||||
* @return the type.
|
style.getSwingHandler().impact(entity, victim, state);
|
||||||
*/
|
}
|
||||||
public FireType getFireType() {
|
|
||||||
return fireType;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
@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.audio.Audio
|
||||||
import core.game.node.entity.player.link.emote.Emotes
|
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.quest.QuestRepository
|
||||||
|
import core.game.node.entity.player.link.prayer.PrayerType;
|
||||||
import core.game.node.entity.skill.Skills
|
import core.game.node.entity.skill.Skills
|
||||||
import content.data.skill.SkillingTool
|
import content.data.skill.SkillingTool
|
||||||
import content.global.skill.slayer.Tasks
|
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)
|
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
|
private class ContentAPI
|
||||||
|
|||||||
Reference in New Issue
Block a user