Implemented ContentInterface-based NPC Scripting
Obsoleted AbstractNPC Implemented desert bandits Rewrote a handful of existing NPCs into NPCBehaviors (e.g. rock slugs, nechryaels, water fiend and more)
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
package content.global.skill.slayer
|
||||
|
||||
import core.api.animate
|
||||
import core.api.getAttribute
|
||||
import core.api.setAttribute
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.combat.BattleState
|
||||
import core.game.node.entity.combat.CombatStyle
|
||||
import core.game.node.entity.combat.DeathTask
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.npc.NPCBehavior
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.world.GameWorld
|
||||
import core.tools.RandomFunction
|
||||
import org.rs09.consts.NPCs
|
||||
|
||||
class NechryaelBehavior : NPCBehavior(*Tasks.NECHRYAELS.npcs) {
|
||||
private val ATTR_SPAWNS = "deathSpawns"
|
||||
private val ATTR_NEXTSPAWN = "deathSpawnNextTick"
|
||||
|
||||
override fun afterDamageReceived(self: NPC, attacker: Entity, state: BattleState) {
|
||||
if (attacker !is Player) return
|
||||
if (!canSpawnDeathspawn(self)) return
|
||||
if (!RandomFunction.roll(5)) return
|
||||
spawnDeathSpawn(self, attacker)
|
||||
}
|
||||
|
||||
fun spawnDeathSpawn(self: NPC, player: Player) {
|
||||
val npc = NPC.create(NPCs.DEATH_SPAWN_1614, self.location.transform(self.direction, 1))
|
||||
setAttribute(npc, "parent", self)
|
||||
setAttribute(npc, "target", player)
|
||||
npc.isRespawn = false
|
||||
npc.init()
|
||||
addSpawn(self, npc)
|
||||
setNextSpawn(self)
|
||||
animate(self, 9491)
|
||||
}
|
||||
|
||||
fun canSpawnDeathspawn(self: NPC) : Boolean {
|
||||
if (getSpawns(self).size >= 2) {
|
||||
setNextSpawn(self)
|
||||
return false
|
||||
}
|
||||
return getNextSpawn(self) <= GameWorld.ticks
|
||||
}
|
||||
|
||||
fun getNextSpawn(self: NPC) : Int {
|
||||
return getAttribute(self, ATTR_NEXTSPAWN, 0)
|
||||
}
|
||||
|
||||
fun setNextSpawn(self: NPC) {
|
||||
setAttribute(self, ATTR_NEXTSPAWN, GameWorld.ticks + 50)
|
||||
}
|
||||
|
||||
fun getSpawns(self: NPC) : ArrayList<NPC> {
|
||||
return getAttribute(self, ATTR_SPAWNS, ArrayList())
|
||||
}
|
||||
|
||||
fun addSpawn(self: NPC, spawn: NPC) {
|
||||
val list = getSpawns(self)
|
||||
list.add(spawn)
|
||||
setAttribute(self, ATTR_SPAWNS, list)
|
||||
}
|
||||
|
||||
fun removeSpawn(self: NPC, spawn: NPC) {
|
||||
val list = getSpawns(self)
|
||||
list.remove(spawn)
|
||||
setAttribute(self, ATTR_SPAWNS, list)
|
||||
}
|
||||
}
|
||||
|
||||
class DeathspawnBehavior : NPCBehavior(NPCs.DEATH_SPAWN_1614) {
|
||||
override fun onCreation(self: NPC) {
|
||||
setAttribute(self, "despawn-time", GameWorld.ticks + 100)
|
||||
val target = getAttribute<Player?>(self, "target", null) ?: return
|
||||
self.attack(target)
|
||||
}
|
||||
|
||||
override fun onRemoval(self: NPC) {
|
||||
val parent = getAttribute<NPC?>(self, "parent", null) ?: return
|
||||
if (parent.behavior !is NechryaelBehavior) return
|
||||
parent.behavior.removeSpawn(parent, self)
|
||||
}
|
||||
|
||||
override fun tick(self: NPC): Boolean {
|
||||
val target = getAttribute<Player?>(self, "target", null) ?: return true
|
||||
|
||||
if (!target.isActive || DeathTask.isDead(target) || getAttribute(self, "despawn-time", 0) <= GameWorld.ticks)
|
||||
self.clear()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun shouldIgnoreMultiRestrictions(self: NPC, victim: Entity): Boolean {
|
||||
return victim == getAttribute<Player?>(self, "target", null)
|
||||
}
|
||||
|
||||
override fun canBeAttackedBy(self: NPC, attacker: Entity, style: CombatStyle, shouldSendMessage: Boolean): Boolean {
|
||||
return attacker == getAttribute<Player?>(self, "target", null)
|
||||
}
|
||||
}
|
||||
@@ -1,193 +0,0 @@
|
||||
package content.global.skill.slayer;
|
||||
|
||||
import core.game.node.entity.Entity;
|
||||
import core.game.node.entity.combat.BattleState;
|
||||
import core.game.node.entity.combat.CombatStyle;
|
||||
import core.game.node.entity.npc.AbstractNPC;
|
||||
import core.game.node.entity.player.Player;
|
||||
import core.game.world.GameWorld;
|
||||
import core.game.world.map.Location;
|
||||
import core.game.world.update.flag.context.Animation;
|
||||
import core.plugin.Initializable;
|
||||
import core.tools.RandomFunction;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Handles the nechryael npc.
|
||||
* @author Vexia
|
||||
*/
|
||||
@Initializable
|
||||
public final class NechryaelNPC extends AbstractNPC {
|
||||
|
||||
/**
|
||||
* The death spawn id.
|
||||
*/
|
||||
private static final int DEATH_SPAWN = 1614;
|
||||
|
||||
/**
|
||||
* The death spawn npcs.
|
||||
*/
|
||||
private List<DeathSpawnNPC> spawns = new ArrayList<>(10);
|
||||
|
||||
/**
|
||||
* The next spawn time.
|
||||
*/
|
||||
private int nextSpawn;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code NechryaelNPC} {@code Object}.
|
||||
* @param id the id.
|
||||
* @param location the location.
|
||||
*/
|
||||
public NechryaelNPC(int id, Location location) {
|
||||
super(id, location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code NechryaelNPC} {@code Object}.
|
||||
*/
|
||||
public NechryaelNPC() {
|
||||
super(0, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onImpact(Entity entity, final BattleState state) {
|
||||
super.onImpact(entity, state);
|
||||
if (entity instanceof Player && RandomFunction.random(5) == 1) {
|
||||
spawn((Player) entity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawns a death spawn.
|
||||
* @param player the player.
|
||||
*/
|
||||
public void spawn(Player player) {
|
||||
if (!canSpawn()) {
|
||||
return;
|
||||
}
|
||||
final DeathSpawnNPC spawn = new DeathSpawnNPC(DEATH_SPAWN, getLocation().transform(getDirection(), 1), player, this);
|
||||
spawn.init();
|
||||
setSpawnTime();
|
||||
spawns.add(spawn);
|
||||
animate(Animation.create(9491));
|
||||
spawn.getProperties().getCombatPulse().attack(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the next spawn time.
|
||||
*/
|
||||
private void setSpawnTime() {
|
||||
nextSpawn = GameWorld.getTicks() + 50;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a death spawn can spawn.
|
||||
* @return {@code True} if so.
|
||||
*/
|
||||
private boolean canSpawn() {
|
||||
if (spawns.size() >= 2) {
|
||||
setSpawnTime();
|
||||
return false;
|
||||
}
|
||||
return nextSpawn < GameWorld.getTicks();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractNPC construct(int id, Location location, Object... objects) {
|
||||
return new NechryaelNPC(id, location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getIds() {
|
||||
return Tasks.NECHRYAELS.getNpcs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the death spawn npc.
|
||||
* @author Vexia
|
||||
*/
|
||||
public static final class DeathSpawnNPC extends AbstractNPC {
|
||||
|
||||
/**
|
||||
* The player binded with the death spawn.
|
||||
*/
|
||||
private final Player player;
|
||||
|
||||
/**
|
||||
* The parent npc.
|
||||
*/
|
||||
private final NechryaelNPC parent;
|
||||
|
||||
/**
|
||||
* The time until its cleared.
|
||||
*/
|
||||
private int time;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code DeathSpawnNPC} {@code Object}.
|
||||
* @param id the id.
|
||||
* @param location the location.
|
||||
*/
|
||||
public DeathSpawnNPC(int id, Location location, final Player player, NechryaelNPC parent) {
|
||||
super(id, location);
|
||||
this.player = player;
|
||||
this.parent = parent;
|
||||
this.setRespawn(false);
|
||||
this.time = GameWorld.getTicks() + 120;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleTickActions() {
|
||||
super.handleTickActions();
|
||||
if (!inCombat() || !player.inCombat()) {
|
||||
getProperties().getCombatPulse().attack(player);
|
||||
}
|
||||
if (time < GameWorld.getTicks() || !player.isActive() || player.getLocation().getDistance(getLocation()) > 15) {
|
||||
clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
super.clear();
|
||||
parent.spawns.remove(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractNPC construct(int id, Location location, Object... objects) {
|
||||
return new DeathSpawnNPC(id, location, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAttackable(Entity entity, CombatStyle style, boolean message) {
|
||||
if (entity instanceof Player) {
|
||||
final Player t = (Player) entity;
|
||||
if (t != player) {
|
||||
if(message) {
|
||||
t.getPacketDispatch().sendMessage("This isn't spawned for you.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return super.isAttackable(entity, style, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIgnoreMultiBoundaries(Entity victim) {
|
||||
return victim == player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPoisonImmune() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getIds() {
|
||||
return new int[] { DEATH_SPAWN };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package content.global.skill.slayer
|
||||
|
||||
import core.api.*
|
||||
import core.game.interaction.IntType
|
||||
import core.game.interaction.InteractionListener
|
||||
import core.game.node.Node
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.combat.BattleState
|
||||
import core.game.node.entity.combat.ImpactHandler
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.npc.NPCBehavior
|
||||
import core.game.node.entity.player.Player
|
||||
import org.rs09.consts.Items
|
||||
import java.lang.Integer.max
|
||||
|
||||
class RockSlug : NPCBehavior(*Tasks.ROCK_SLUGS.ids), InteractionListener {
|
||||
override fun defineListeners() {
|
||||
onUseWith(IntType.NPC, Items.BAG_OF_SALT_4161, *ids, handler = ::handleSaltUsage)
|
||||
}
|
||||
|
||||
override fun beforeDamageReceived(self: NPC, attacker: Entity, state: BattleState) {
|
||||
val lifepoints = self.skills.lifepoints
|
||||
if (state.estimatedHit + max(state.secondaryHit, 0) > lifepoints - 1) {
|
||||
state.estimatedHit = lifepoints - 1
|
||||
state.secondaryHit = -1
|
||||
setAttribute(self, "shouldRun", true)
|
||||
}
|
||||
}
|
||||
|
||||
override fun tick(self: NPC): Boolean {
|
||||
if (getAttribute(self, "shouldRun", false)){
|
||||
self.properties.combatPulse.stop()
|
||||
forceWalk(self, self.properties.spawnLocation, "smart")
|
||||
removeAttribute(self, "shouldRun")
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun handleSaltUsage(player: Player, used: Node, with: Node) : Boolean {
|
||||
if (with !is NPC) return false
|
||||
if (!removeItem(player, used.id)) return false
|
||||
if (with.skills.lifepoints >= 5)
|
||||
sendMessage(player, "Your bag of salt is ineffective. The Rockslug is not weak enough.")
|
||||
else {
|
||||
sendMessage(player, "The Rockslug shrivels up and dies.")
|
||||
with.impactHandler.manualHit(player, with.skills.lifepoints, ImpactHandler.HitsplatType.NORMAL)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
package content.global.skill.slayer;
|
||||
|
||||
import core.game.interaction.NodeUsageEvent;
|
||||
import core.game.interaction.UseWithHandler;
|
||||
import core.game.node.entity.combat.BattleState;
|
||||
import core.game.node.entity.combat.ImpactHandler.HitsplatType;
|
||||
import core.game.node.entity.npc.AbstractNPC;
|
||||
import core.game.node.entity.npc.NPC;
|
||||
import core.game.node.entity.player.Player;
|
||||
import core.game.node.item.Item;
|
||||
import core.game.world.map.Location;
|
||||
import core.game.world.map.path.Pathfinder;
|
||||
import core.plugin.Initializable;
|
||||
import core.plugin.Plugin;
|
||||
import core.plugin.ClassScanner;
|
||||
|
||||
/**
|
||||
* Handles the interactions of a rock slug.
|
||||
* @author Vexia
|
||||
*/
|
||||
@Initializable
|
||||
public final class RockSlugPlugin implements Plugin<Object> {
|
||||
|
||||
/**
|
||||
* The bag of salt item.
|
||||
*/
|
||||
private static final Item SALT = new Item(4161, 1);
|
||||
|
||||
/**
|
||||
* The rockslug npc ids.
|
||||
*/
|
||||
private static final int[] IDS = new int[] { 1631, 1632 };
|
||||
|
||||
@Override
|
||||
public Plugin<Object> newInstance(Object arg) throws Throwable {
|
||||
ClassScanner.definePlugin(new RockSlugNPC());
|
||||
ClassScanner.definePlugin(new SaltBagHandler());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fireEvent(String identifier, Object... args) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The use with handler for the bag of salt on a rock slug.
|
||||
* @author Vexia
|
||||
*/
|
||||
public final class SaltBagHandler extends UseWithHandler {
|
||||
|
||||
/**
|
||||
* Constructs a new {@code SaltBagHandler} {@code Object}.
|
||||
*/
|
||||
public SaltBagHandler() {
|
||||
super(SALT.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Plugin<Object> newInstance(Object arg) throws Throwable {
|
||||
for (int id : IDS) {
|
||||
addHandler(id, NPC_TYPE, this);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(NodeUsageEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
final NPC npc = (NPC) event.getUsedWith();
|
||||
player.getInventory().remove(SALT);
|
||||
if (npc.getSkills().getLifepoints() < 10) {
|
||||
npc.getImpactHandler().manualHit(player, npc.getSkills().getLifepoints(), HitsplatType.NORMAL);
|
||||
player.getPacketDispatch().sendMessage("The rockslug shrivels up and dies.");
|
||||
} else {
|
||||
player.sendMessage("Your bag of salt is ineffective. The Rockslug is not weak enough.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The rock slug npc.
|
||||
* @author Vexia
|
||||
*/
|
||||
public final class RockSlugNPC extends AbstractNPC {
|
||||
|
||||
/**
|
||||
* Constructs a new {@code RockSlugNPC} {@code Object}.
|
||||
*/
|
||||
public RockSlugNPC() {
|
||||
super(-1, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code RockSlugNPC} {@code Object}.
|
||||
* @param id the id.
|
||||
* @param location the location.
|
||||
*/
|
||||
public RockSlugNPC(int id, Location location) {
|
||||
super(id, location, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractNPC construct(int id, Location location, Object... objects) {
|
||||
return new RockSlugNPC(id, location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkImpact(BattleState state) {
|
||||
super.checkImpact(state);
|
||||
int lifepoints = getSkills().getLifepoints();
|
||||
boolean run = false;
|
||||
if (state.getEstimatedHit() > -1) {
|
||||
lifepoints -= state.getEstimatedHit();
|
||||
if (lifepoints < 1) {
|
||||
run = true;
|
||||
state.setEstimatedHit(lifepoints - 1);
|
||||
}
|
||||
if (state.getEstimatedHit() < 0) {
|
||||
state.setEstimatedHit(0);
|
||||
}
|
||||
}
|
||||
if (state.getSecondaryHit() > -1) {
|
||||
lifepoints -= state.getSecondaryHit();
|
||||
if (lifepoints < 1) {
|
||||
run = true;
|
||||
state.setSecondaryHit(lifepoints - 1);
|
||||
}
|
||||
if (state.getSecondaryHit() < 0) {
|
||||
state.setSecondaryHit(0);
|
||||
}
|
||||
}
|
||||
if (run) {
|
||||
getProperties().getCombatPulse().stop();
|
||||
Pathfinder.find(getLocation(), getProperties().getSpawnLocation());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getIds() {
|
||||
return IDS;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package content.global.skill.slayer
|
||||
|
||||
import content.global.handlers.item.equipment.special.DragonfireSwingHandler
|
||||
import core.api.EquipmentSlot
|
||||
import core.api.getItemFromEquipment
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.combat.BattleState
|
||||
import core.game.node.entity.combat.CombatStyle
|
||||
import core.game.node.entity.combat.CombatSwingHandler
|
||||
import core.game.node.entity.combat.MultiSwingHandler
|
||||
import core.game.node.entity.combat.equipment.SwitchAttack
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.npc.NPCBehavior
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.player.link.prayer.PrayerType
|
||||
import core.game.world.update.flag.context.Animation
|
||||
import core.game.world.update.flag.context.Graphics
|
||||
import core.tools.RandomFunction
|
||||
import org.rs09.consts.Items
|
||||
|
||||
class SkeletalWyvernBehavior : NPCBehavior(*Tasks.SKELETAL_WYVERN.ids) {
|
||||
/**
|
||||
* The combat swing handler.
|
||||
*/
|
||||
private val COMBAT_HANDLER = MultiSwingHandler(SwitchAttack(CombatStyle.MELEE.swingHandler, Animation(2985)), SwitchAttack(CombatStyle.RANGE.swingHandler, Animation(2989), Graphics(499)), DragonfireSwingHandler.get(false, 54, Animation(2988), Graphics(501), null, null, false))
|
||||
|
||||
/**
|
||||
* The combat swing handler for far combat (5+ tile distance)
|
||||
*/
|
||||
private val COMBAT_HANDLER_FAR = MultiSwingHandler(SwitchAttack(CombatStyle.RANGE.swingHandler, Animation(2989), Graphics(499)))
|
||||
|
||||
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
|
||||
|
||||
return if (victim.location.getDistance(self.location) >= 5)
|
||||
COMBAT_HANDLER_FAR
|
||||
else
|
||||
COMBAT_HANDLER
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
package content.global.skill.slayer;
|
||||
|
||||
import core.game.container.impl.EquipmentContainer;
|
||||
import core.game.node.entity.combat.BattleState;
|
||||
import core.game.node.entity.combat.CombatStyle;
|
||||
import core.game.node.entity.combat.equipment.SwitchAttack;
|
||||
import content.global.handlers.item.equipment.special.DragonfireSwingHandler;
|
||||
import core.game.node.entity.npc.AbstractNPC;
|
||||
import core.game.node.entity.player.Player;
|
||||
import core.game.node.entity.player.link.prayer.PrayerType;
|
||||
import core.game.node.item.Item;
|
||||
import core.game.world.map.Location;
|
||||
import core.game.world.update.flag.context.Animation;
|
||||
import core.game.world.update.flag.context.Graphics;
|
||||
import core.plugin.Initializable;
|
||||
import core.tools.RandomFunction;
|
||||
import core.game.node.entity.combat.CombatSwingHandler;
|
||||
import core.game.node.entity.combat.MultiSwingHandler;
|
||||
|
||||
/**
|
||||
* Handles the skeletal wyvern npc.
|
||||
* @author Vexia
|
||||
* @author Splinter
|
||||
* @version 1.0
|
||||
*/
|
||||
@Initializable
|
||||
public final class SkeletalWyvernNPC extends AbstractNPC {
|
||||
|
||||
/**
|
||||
* The combat swing handler.
|
||||
*/
|
||||
private static final MultiSwingHandler COMBAT_HANDLER = new MultiSwingHandler(new SwitchAttack(CombatStyle.MELEE.getSwingHandler(), new Animation(2985)), new SwitchAttack(CombatStyle.RANGE.getSwingHandler(), new Animation(2989), new Graphics(499)), DragonfireSwingHandler.get(false, 54, new Animation(2988), new Graphics(501), null, null, false));
|
||||
|
||||
/**
|
||||
* The combat swing handler for far combat (5+ tile distance)
|
||||
*/
|
||||
private static final MultiSwingHandler COMBAT_HANDLER_FAR = new MultiSwingHandler(new SwitchAttack(CombatStyle.RANGE.getSwingHandler(), new Animation(2989), new Graphics(499)));
|
||||
|
||||
/**
|
||||
* Constructs a new {@code SkeletalWyvernNPC} {@code Object}.
|
||||
* @param id the id.
|
||||
* @param location the location.
|
||||
*/
|
||||
public SkeletalWyvernNPC(int id, Location location) {
|
||||
super(id, location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code SkeletalWyvernNPC} {@code Object}.
|
||||
*/
|
||||
public SkeletalWyvernNPC() {
|
||||
super(0, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractNPC construct(int id, Location location, Object... objects) {
|
||||
return new SkeletalWyvernNPC(id, location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendImpact(BattleState state) {
|
||||
if (state.getStyle() == CombatStyle.MAGIC && state.getVictim() != null && state.getVictim().isPlayer()) {
|
||||
Player p = state.getVictim().asPlayer();
|
||||
Item item = p.getEquipment().get(EquipmentContainer.SLOT_SHIELD);
|
||||
if (item != null && (item.getId() == 2890 || item.getId() == 9731 || item.getId() == 11283) && state.getEstimatedHit() > 10) {
|
||||
state.setEstimatedHit(RandomFunction.random(10));
|
||||
}
|
||||
}
|
||||
Player p = state.getVictim().asPlayer();
|
||||
Item item = p.getEquipment().get(EquipmentContainer.SLOT_SHIELD);
|
||||
if(state.getVictim().getLocation().getDistance(state.getAttacker().getLocation()) >= 5
|
||||
&& state.getVictim().asPlayer().getPrayer().get(PrayerType.PROTECT_FROM_MAGIC) && (item.getId() == 2890 || item.getId() == 9731 || item.getId() == 11283)){
|
||||
state.setEstimatedHit(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CombatSwingHandler getSwingHandler(boolean swing) {
|
||||
if (this.getProperties().getCombatPulse().getVictim() != null && this.getProperties().getCombatPulse().getVictim().getLocation().getDistance(this.getLocation()) >= 5){
|
||||
return COMBAT_HANDLER_FAR;
|
||||
}
|
||||
return COMBAT_HANDLER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getIds() {
|
||||
return Tasks.SKELETAL_WYVERN.getNpcs();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package content.global.skill.slayer
|
||||
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.combat.BattleState
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.npc.NPCBehavior
|
||||
import core.game.node.entity.player.Player
|
||||
|
||||
class TurothBehavior : NPCBehavior(*Tasks.TUROTHS.ids) {
|
||||
override fun beforeDamageReceived(self: NPC, attacker: Entity, state: BattleState) {
|
||||
if (attacker is Player) {
|
||||
if (!SlayerUtils.hasBroadWeaponEquipped(attacker, state))
|
||||
state.neutralizeHits()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
package content.global.skill.slayer;
|
||||
|
||||
import core.game.node.entity.combat.BattleState;
|
||||
import core.game.node.entity.npc.AbstractNPC;
|
||||
import core.game.node.entity.player.Player;
|
||||
import core.game.world.map.Location;
|
||||
import core.plugin.Initializable;
|
||||
|
||||
/**
|
||||
* Handles the turoth npc.
|
||||
* @author Vexia
|
||||
*/
|
||||
@Initializable
|
||||
public final class TurothNPC extends AbstractNPC {
|
||||
|
||||
/**
|
||||
* Constructs a new {@code TurothNPC} {@code Object}.
|
||||
* @param id the id.
|
||||
* @param location the location.
|
||||
*/
|
||||
public TurothNPC(int id, Location location) {
|
||||
super(id, location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code TurothNPC} {@code Object}.
|
||||
*/
|
||||
public TurothNPC() {
|
||||
super(0, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractNPC construct(int id, Location location, Object... objects) {
|
||||
return new TurothNPC(id, location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkImpact(final BattleState state) {
|
||||
super.checkImpact(state);
|
||||
boolean effective = false;
|
||||
if (state.getAttacker() instanceof Player) {
|
||||
final Player player = (Player) state.getAttacker();
|
||||
effective = SlayerUtils.hasBroadWeaponEquipped(player, state);
|
||||
}
|
||||
if (!effective) {
|
||||
state.setEstimatedHit(0);
|
||||
if (state.getSecondaryHit() > 0) {
|
||||
state.setSecondaryHit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getIds() {
|
||||
return new int[] { 1626, 1627, 1628, 1629, 1630 };
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
package content.global.skill.slayer;
|
||||
|
||||
import core.game.node.entity.Entity;
|
||||
import core.game.node.entity.combat.CombatStyle;
|
||||
import core.game.node.entity.combat.equipment.SwitchAttack;
|
||||
import core.game.node.entity.impl.Animator.Priority;
|
||||
import core.game.node.entity.impl.Projectile;
|
||||
import core.game.node.entity.npc.AbstractNPC;
|
||||
import core.game.world.map.Location;
|
||||
import core.game.world.update.flag.context.Animation;
|
||||
import core.plugin.Initializable;
|
||||
import core.game.node.entity.combat.CombatSwingHandler;
|
||||
import core.game.node.entity.combat.MultiSwingHandler;
|
||||
|
||||
/**
|
||||
* Handles the water fiend npc.
|
||||
* @author Vexia
|
||||
*/
|
||||
@Initializable
|
||||
public final class WaterFiendNPC extends AbstractNPC {
|
||||
|
||||
/**
|
||||
* Handles the combat.
|
||||
*/
|
||||
private final CombatSwingHandler combatAction = new MultiSwingHandler(true, new SwitchAttack(CombatStyle.MAGIC.getSwingHandler(), new Animation(1581, Priority.HIGH), null, null, Projectile.create((Entity) null, null, 500, 15, 30, 50, 50, 14, 255)), new SwitchAttack(CombatStyle.RANGE.getSwingHandler(), new Animation(1581, Priority.HIGH), null, null, Projectile.create((Entity) null, null, 16, 15, 30, 50, 50, 14, 255)));
|
||||
|
||||
/**
|
||||
* Constructs a new {@code WaterFiendNPC} {@code Object}.
|
||||
* @param id the id.
|
||||
* @param location the location.
|
||||
*/
|
||||
public WaterFiendNPC(int id, Location location) {
|
||||
super(id, location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code WaterFiendNPC} {@code Object}.
|
||||
*/
|
||||
public WaterFiendNPC() {
|
||||
super(0, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractNPC construct(int id, Location location, Object... objects) {
|
||||
return new WaterFiendNPC(id, location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CombatSwingHandler getSwingHandler(boolean swing) {
|
||||
return combatAction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getIds() {
|
||||
return Tasks.WATERFIENDS.getNpcs();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package content.global.skill.slayer
|
||||
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.combat.CombatStyle
|
||||
import core.game.node.entity.combat.CombatSwingHandler
|
||||
import core.game.node.entity.combat.MultiSwingHandler
|
||||
import core.game.node.entity.combat.equipment.SwitchAttack
|
||||
import core.game.node.entity.impl.Animator.Priority
|
||||
import core.game.node.entity.impl.Projectile
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.npc.NPCBehavior
|
||||
import core.game.world.update.flag.context.Animation
|
||||
|
||||
class WaterfiendBehavior : NPCBehavior(*Tasks.WATERFIENDS.ids) {
|
||||
private val combatHandler = MultiSwingHandler(
|
||||
true,
|
||||
SwitchAttack(
|
||||
CombatStyle.MAGIC.swingHandler,
|
||||
Animation(1581, Priority.HIGH),
|
||||
null,
|
||||
null,
|
||||
Projectile.create(
|
||||
null as Entity?,
|
||||
null,
|
||||
500,
|
||||
15,
|
||||
30,
|
||||
50,
|
||||
50,
|
||||
14,
|
||||
255
|
||||
)
|
||||
),
|
||||
SwitchAttack(
|
||||
CombatStyle.RANGE.swingHandler,
|
||||
Animation(1581, Priority.HIGH),
|
||||
null,
|
||||
null,
|
||||
Projectile.create(
|
||||
null as Entity?,
|
||||
null,
|
||||
16,
|
||||
15,
|
||||
30,
|
||||
50,
|
||||
50,
|
||||
14,
|
||||
255
|
||||
)
|
||||
)
|
||||
)
|
||||
override fun getSwingHandlerOverride(self: NPC, original: CombatSwingHandler): CombatSwingHandler {
|
||||
return combatHandler
|
||||
}
|
||||
}
|
||||
@@ -229,7 +229,7 @@ public enum Pets {
|
||||
// BABY_GOLD_CHINCHOMPA(14826, -1, -1, 8658, -1, -1, 0.0, 1),
|
||||
// HERON(14827, -1, -1, 8647, -1, -1, 0.0, 1),
|
||||
// TZREK_JAD(14828, -1, -1, 8650, -1, -1, 0.0, 1);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The baby pets mapping.
|
||||
@@ -451,12 +451,12 @@ public enum Pets {
|
||||
*/
|
||||
public int getNpcId(int stage) {
|
||||
switch (stage) {
|
||||
case 0:
|
||||
return babyNpcId;
|
||||
case 1:
|
||||
return grownNpcId;
|
||||
case 2:
|
||||
return overgrownNpcId;
|
||||
case 0:
|
||||
return babyNpcId;
|
||||
case 1:
|
||||
return grownNpcId;
|
||||
case 2:
|
||||
return overgrownNpcId;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -468,13 +468,13 @@ public enum Pets {
|
||||
*/
|
||||
public int getItemId(int stage) {
|
||||
switch (stage) {
|
||||
case 0:
|
||||
return babyItemId;
|
||||
case 1:
|
||||
return grownItemId;
|
||||
case 2:
|
||||
return overgrownItemId;
|
||||
case 0:
|
||||
return babyItemId;
|
||||
case 1:
|
||||
return grownItemId;
|
||||
case 2:
|
||||
return overgrownItemId;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package content.region.desert.bandits.handlers
|
||||
|
||||
import core.api.*
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.combat.BattleState
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.npc.NPCBehavior
|
||||
import core.game.world.map.RegionManager
|
||||
import core.tools.RandomFunction
|
||||
import org.rs09.consts.NPCs
|
||||
|
||||
class BanditBehavior : NPCBehavior(NPCs.BANDIT_1926) {
|
||||
override fun tick(self: NPC): Boolean {
|
||||
if (!self.inCombat() && RandomFunction.roll(3) && getWorldTicks() % 5 == 0) {
|
||||
val players = RegionManager.getLocalPlayers(self, 5)
|
||||
for (player in players) {
|
||||
if (player.inCombat()) continue
|
||||
if (hasGodItem(player, God.SARADOMIN)) {
|
||||
sendChat(self, "Prepare to die, Saradominist scum!")
|
||||
self.attack(player)
|
||||
break
|
||||
}
|
||||
else if (hasGodItem(player, God.ZAMORAK)) {
|
||||
sendChat(self, "Prepare to die, Zamorakian scum!")
|
||||
self.attack(player)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun afterDamageReceived(self: NPC, attacker: Entity, state: BattleState) {
|
||||
if (getAttribute(self, "alerted-others", false)) return
|
||||
val otherBandits = RegionManager.getLocalNpcs(self, 3).filter { it.id == self.id }
|
||||
for (bandit in otherBandits) {
|
||||
if (!bandit.inCombat())
|
||||
bandit.attack(attacker)
|
||||
}
|
||||
setAttribute(self, "alerted-others", true)
|
||||
}
|
||||
|
||||
override fun onDeathStarted(self: NPC, killer: Entity) {
|
||||
removeAttribute(self, "alerted-others")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user