Rewrote impling system
Fixed static impling spawns Fixed impling spawn ratio Reworked Puro-Puro, much more authentic Imp defenders now work properly Crop circles now appear Added admin command ::implings to list active implings (excludes implings from Puro-Puro) Fixed bug where you could add to a finished compost bin
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
package content.global.skill.farming
|
||||
|
||||
import core.api.toIntArray
|
||||
import core.api.*
|
||||
import core.game.node.item.Item
|
||||
import core.game.system.task.Pulse
|
||||
import core.game.world.update.flag.context.Animation
|
||||
@@ -65,7 +65,7 @@ class UseWithBinHandler : InteractionListener {
|
||||
if(bin.isFull()){
|
||||
player.sendMessage("This compost bin is already full.")
|
||||
return@onUseWith true
|
||||
} else {
|
||||
} else if (!bin.isFinished) {
|
||||
player.pulseManager.run(object : Pulse(fillAnim.duration){
|
||||
override fun pulse(): Boolean {
|
||||
player.animator.animate(fillAnim)
|
||||
@@ -75,6 +75,8 @@ class UseWithBinHandler : InteractionListener {
|
||||
return bin.isFull() || player.inventory.getAmount(usedNode.asItem()) == 0
|
||||
}
|
||||
})
|
||||
} else {
|
||||
sendMessage (player, "You should empty the remaining compost first.")
|
||||
}
|
||||
}
|
||||
return@onUseWith true
|
||||
@@ -100,4 +102,4 @@ class UseWithBinHandler : InteractionListener {
|
||||
if(this != 6476) return this + 2
|
||||
else return Items.VIAL_229
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,152 +0,0 @@
|
||||
package content.global.skill.hunter;
|
||||
|
||||
import content.global.skill.hunter.bnet.BNetTypes;
|
||||
import content.global.skill.hunter.bnet.ImplingNode;
|
||||
import core.api.StartupListener;
|
||||
import core.game.world.GameWorld;
|
||||
import core.game.world.map.Location;
|
||||
import core.tools.RandomFunction;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Handles the impetuous impulse minigame.
|
||||
* @author Vexia
|
||||
* @author Emperor
|
||||
*/
|
||||
public final class ImpetuousImpulses implements StartupListener {
|
||||
|
||||
/**
|
||||
* The random instance used.
|
||||
*/
|
||||
private static final Random RANDOM = new Random();
|
||||
|
||||
/**
|
||||
* The puro puro locations.
|
||||
*/
|
||||
private static final Location[] PURO_LOCATIONS = new Location[] { new Location(2575, 4314, 0), new Location(2572, 4302, 0), new Location(2575, 4297, 0), new Location(2589, 4297, 0), new Location(2603, 4297, 0), new Location(2612, 4301, 0), new Location(2619, 4296, 0), new Location(2616, 4297, 0), new Location(2620, 4308, 0), new Location(2617, 4313, 0), new Location(2620, 4317, 0), new Location(2611, 4312, 0), new Location(2607, 4305, 0), new Location(2593, 4303, 0), new Location(2578, 4318, 0), new Location(2578, 4330, 0), new Location(2581, 4338, 0), new Location(2586, 4342, 0), Location.create(2585, 4344, 0), Location.create(2573, 4335, 0), Location.create(2570, 4325, 0), Location.create(2567, 4313, 0), Location.create(2566, 4299, 0), Location.create(2573, 4292, 0), Location.create(2603, 4342, 0), Location.create(2616, 4318, 0), Location.create(2616, 4337, 0), Location.create(2584, 4297, 0), Location.create(2596, 4310, 0), Location.create(2596, 4310, 0), Location.create(2588, 4303, 0) };
|
||||
|
||||
/**
|
||||
* The possible locations.
|
||||
*/
|
||||
public static final Location[] LOCATIONS = new Location[] {
|
||||
/*
|
||||
* Camelot
|
||||
*/
|
||||
Location.create(2718 + RANDOM.nextInt(50), 3441 + RANDOM.nextInt(20), 0),
|
||||
/*
|
||||
* Duel arena entrance
|
||||
*/
|
||||
Location.create(3300 + RANDOM.nextInt(10), 3250 + RANDOM.nextInt(10), 0),
|
||||
/*
|
||||
* Castle wars entrance
|
||||
*/
|
||||
Location.create(2478 + RANDOM.nextInt(20), 3068 + RANDOM.nextInt(20), 0),
|
||||
/*
|
||||
* Lumbridge
|
||||
*/
|
||||
Location.create(3175 + RANDOM.nextInt(10), 3261 + RANDOM.nextInt(10), 0),
|
||||
/*
|
||||
* Draynor
|
||||
*/
|
||||
Location.create(3092 + RANDOM.nextInt(5), 3227 + RANDOM.nextInt(5), 0),
|
||||
/*
|
||||
* Falador (east)
|
||||
*/
|
||||
Location.create(3071 + RANDOM.nextInt(10), 3355 + RANDOM.nextInt(10), 0),
|
||||
/*
|
||||
* Varrock (west)
|
||||
*/
|
||||
Location.create(3131 + RANDOM.nextInt(5), 3401 + RANDOM.nextInt(5), 0),
|
||||
/*
|
||||
* Ardougne (south)
|
||||
*/
|
||||
Location.create(2630 + RANDOM.nextInt(10), 3217 + RANDOM.nextInt(10), 0),
|
||||
/*
|
||||
* Yanille (north)
|
||||
*/
|
||||
Location.create(2594 + RANDOM.nextInt(20), 3121 + RANDOM.nextInt(20), 0),
|
||||
/*
|
||||
* Red salamander hunting place (ZMI altar)
|
||||
*/
|
||||
Location.create(2436 + RANDOM.nextInt(15), 3206 + RANDOM.nextInt(15), 0),
|
||||
/*
|
||||
* Shilo hunting area (graahk/larupia/..)
|
||||
*/
|
||||
Location.create(2763 + RANDOM.nextInt(20), 3003 + RANDOM.nextInt(20), 0),
|
||||
/*
|
||||
* Rimmington
|
||||
*/
|
||||
Location.create(2947 + RANDOM.nextInt(20), 3219 + RANDOM.nextInt(20), 0),
|
||||
/*
|
||||
* Karamja volcano
|
||||
*/
|
||||
Location.create(2856 + RANDOM.nextInt(15), 3150 + RANDOM.nextInt(15), 0),
|
||||
/*
|
||||
* Brimhaven dungeon entrance
|
||||
*/
|
||||
Location.create(2733 + RANDOM.nextInt(10), 3146 + RANDOM.nextInt(10), 0),
|
||||
/*
|
||||
* Sophanem
|
||||
*/
|
||||
Location.create(3299 + RANDOM.nextInt(5), 2784 + RANDOM.nextInt(5), 0),
|
||||
/*
|
||||
* Tree gnome stronghold
|
||||
*/
|
||||
Location.create(2438 + RANDOM.nextInt(20), 3420 + RANDOM.nextInt(20), 0),
|
||||
/*
|
||||
* Zanaris (center, just north of grain field)
|
||||
*/
|
||||
Location.create(2416 + RANDOM.nextInt(3), 4456 + RANDOM.nextInt(3), 0), };
|
||||
|
||||
/**
|
||||
* Spawns the imps.
|
||||
*/
|
||||
private void spawnImps() {
|
||||
int amount = BNetTypes.getImplings().size() + 2;
|
||||
for (ImplingNode impling : BNetTypes.getImplings()) {
|
||||
if (impling.getLevel() == 83) {
|
||||
int rand = RandomFunction.random(1, 2);
|
||||
for (int i = 0; i < rand; i++) {
|
||||
createImp(impling, true);
|
||||
}
|
||||
int randAmt = RandomFunction.random(2, 5);
|
||||
for (int i = 0; i < randAmt; i++) {
|
||||
createImp(impling, false);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
for (int i = 0; i < amount; i++) {
|
||||
if (RANDOM.nextInt(10) < 4) {
|
||||
createImp(impling, false);
|
||||
continue;
|
||||
}
|
||||
createImp(impling, true);
|
||||
}
|
||||
amount--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the impling.
|
||||
* @param impling the impling.
|
||||
* @param puro the puro.
|
||||
*/
|
||||
private void createImp(ImplingNode impling, boolean puro) {
|
||||
ImplingNPC npc = null;
|
||||
if (puro) {
|
||||
npc = new ImplingNPC(impling.getNpcs()[1], PURO_LOCATIONS[RANDOM.nextInt(PURO_LOCATIONS.length)], impling);
|
||||
npc.setAttribute("puroPuro", true);
|
||||
} else {
|
||||
npc = new ImplingNPC(impling.getNpcs()[0], LOCATIONS[RANDOM.nextInt(LOCATIONS.length)], impling);
|
||||
npc.setAttribute("nextTeleport", GameWorld.getTicks() + 600);
|
||||
}
|
||||
npc.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startup() {
|
||||
spawnImps();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
package content.global.skill.hunter;
|
||||
|
||||
import content.global.skill.hunter.bnet.ImplingNode;
|
||||
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.system.task.Pulse;
|
||||
import core.game.world.map.Location;
|
||||
import core.game.world.map.path.Pathfinder;
|
||||
import core.game.world.update.flag.context.Graphics;
|
||||
import core.plugin.Initializable;
|
||||
import core.tools.RandomFunction;
|
||||
import core.game.system.config.NPCConfigParser;
|
||||
import core.game.world.GameWorld;
|
||||
|
||||
/**
|
||||
* Handles an impling npc.
|
||||
* @author Vexia
|
||||
*/
|
||||
@Initializable
|
||||
public final class ImplingNPC extends AbstractNPC {
|
||||
|
||||
/**
|
||||
* The impling node.
|
||||
*/
|
||||
private final ImplingNode impling;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code ImplingNPC} {@code Object}.
|
||||
*/
|
||||
public ImplingNPC() {
|
||||
super(0, null);
|
||||
this.impling = null;
|
||||
this.setWalks(true);
|
||||
this.setWalkRadius(20);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code ImplingNPC} {@code Object}.
|
||||
* @param id the id.
|
||||
* @param location the location.
|
||||
*/
|
||||
public ImplingNPC(int id, Location location, ImplingNode impling) {
|
||||
super(id, location);
|
||||
this.impling = impling;
|
||||
if (impling != null) {
|
||||
this.getDefinition().getHandlers().put(NPCConfigParser.RESPAWN_DELAY, impling.getRespawnTime());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractNPC construct(int id, Location location, Object... objects) {
|
||||
return new ImplingNPC(id, location, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleTickActions() {
|
||||
if (!getLocks().isMovementLocked()) {
|
||||
if (isWalks() && !getPulseManager().hasPulseRunning() && nextWalk < GameWorld.getTicks()) {
|
||||
setNextWalk();
|
||||
Location l = getLocation().transform(-5 + RandomFunction.random(getWalkRadius()), -5 + RandomFunction.random(getWalkRadius()), 0);
|
||||
if (canMove(l)) {
|
||||
Pathfinder.find(this, l, true, Pathfinder.PROJECTILE).walk(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (RandomFunction.random(100) < 4) {
|
||||
sendChat("Tee hee!");
|
||||
}
|
||||
int nextTeleport = getAttribute("nextTeleport", -1);
|
||||
if (nextTeleport > -1 && GameWorld.getTicks() > nextTeleport) {
|
||||
setAttribute("nextTeleport", GameWorld.getTicks() + 600);
|
||||
graphics(new Graphics(590));
|
||||
GameWorld.getPulser().submit(new Pulse(1) {
|
||||
@Override
|
||||
public boolean pulse() {
|
||||
teleport(ImpetuousImpulses.LOCATIONS[RandomFunction.random(ImpetuousImpulses.LOCATIONS.length)]);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAttackable(Entity entity, CombatStyle style, boolean message) {
|
||||
if (style != CombatStyle.MAGIC) {
|
||||
return false;
|
||||
}
|
||||
if (entity.getProperties().getSpell().getSpellId() == 12 || entity.getProperties().getSpell().getSpellId() == 30 || entity.getProperties().getSpell().getSpellId() == 56) {
|
||||
return true;
|
||||
}
|
||||
return super.isAttackable(entity, style, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleDrops(Player p, Entity killer) {
|
||||
getProperties().setTeleportLocation(getProperties().getSpawnLocation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkImpact(BattleState state) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getIds() {
|
||||
return new int[] { 1028, 6055, 1029, 6056, 1030, 6057, 1031, 6058, 1032, 6059, 1033, 6060, 1034, 6061, 1035, 6062, 6053, 6063};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the impling.
|
||||
* @return The impling.
|
||||
*/
|
||||
public ImplingNode getImpling() {
|
||||
return impling;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package content.global.skill.hunter.implings
|
||||
|
||||
import core.api.*
|
||||
import core.tools.*
|
||||
import core.game.world.map.RegionManager
|
||||
import core.game.world.map.path.ClipMaskSupplier
|
||||
import core.game.node.entity.npc.*
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.player.link.SpellBookManager;
|
||||
import core.game.node.item.Item
|
||||
import core.game.node.entity.combat.CombatStyle
|
||||
import content.global.skill.magic.spellconsts.Modern
|
||||
|
||||
/**
|
||||
* Manages the behavior for implings themselves.
|
||||
*/
|
||||
class ImplingBehavior : NPCBehavior (*Impling.getIds()) {
|
||||
override fun onCreation (self: NPC) {
|
||||
self.isWalks = true
|
||||
self.isNeverWalks = false
|
||||
self.properties.spawnLocation = self.location
|
||||
}
|
||||
|
||||
override fun tick(self: NPC) : Boolean {
|
||||
if (RandomFunction.roll(10))
|
||||
sendChat(self, "Tee-hee!")
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onRespawn(self: NPC) {
|
||||
if (!isPuroImpling(self))
|
||||
log (this::class.java, Log.ERR, "Non-puro impling has respawned!")
|
||||
sendGraphics(1119, self.properties.teleportLocation)
|
||||
}
|
||||
|
||||
override fun canBeAttackedBy(self: NPC, attacker: Entity, style: CombatStyle, shouldSendMessage: Boolean) : Boolean {
|
||||
if (attacker !is Player) return false;
|
||||
|
||||
if (style != CombatStyle.MAGIC) {
|
||||
if (shouldSendMessage)
|
||||
sendMessage (attacker, "You can't do that.")
|
||||
return false;
|
||||
}
|
||||
|
||||
val spellBook = attacker.spellBookManager.spellBook
|
||||
if (spellBook != SpellBookManager.SpellBook.MODERN.interfaceId) {
|
||||
if (shouldSendMessage)
|
||||
sendMessage (attacker, "The impling is too fast for that.")
|
||||
return false;
|
||||
}
|
||||
|
||||
val spellId = attacker.properties.spell.spellId
|
||||
if (spellId != Modern.BIND && spellId != Modern.SNARE && spellId != Modern.ENTANGLE) {
|
||||
if (shouldSendMessage)
|
||||
sendMessage (attacker, "The impling is immune to that magic.")
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onDeathFinished (self: NPC, killer: Entity) {
|
||||
if (!isPuroImpling(self))
|
||||
ImplingController.deregister(self)
|
||||
else if (self.originalId != self.id) { //if this is a spawner that transformed
|
||||
self.reTransform() //turn back into spawner NPC
|
||||
self.behavior = forId(self.id)
|
||||
}
|
||||
}
|
||||
|
||||
//manually clear any rolled drops so any drops set by JSON are properly ignored.
|
||||
override fun onDropTableRolled (self: NPC, drops: ArrayList<Item>) {
|
||||
drops.clear()
|
||||
}
|
||||
|
||||
override fun getClippingSupplier (self: NPC) : ClipMaskSupplier {
|
||||
return ImplingClipper
|
||||
}
|
||||
|
||||
private fun isPuroImpling (self: NPC) : Boolean {
|
||||
return self.id > 6054
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package content.global.skill.hunter.implings
|
||||
|
||||
import core.api.*
|
||||
import core.tools.*
|
||||
import core.game.world.map.Location
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.system.command.*
|
||||
import kotlin.math.*
|
||||
|
||||
/**
|
||||
* Manages the high-level behavior of implings in the overworld: Spawning them, clearing them, etc.
|
||||
* NOTE: This does not manage the spawns INSIDE puro-puro. Those are actually handled by JSON.
|
||||
*/
|
||||
class ImplingController : TickListener, Commands {
|
||||
override fun tick() {
|
||||
if (--nextCycle > getTicksBeforeNextCycleToDespawn())
|
||||
return
|
||||
if (activeImplings.size > 0) {
|
||||
clearSomeImplings(implingsClearedPerTick)
|
||||
return
|
||||
}
|
||||
generateSpawners()
|
||||
nextCycle = secondsToTicks(60 * 30) // 30 minutes
|
||||
}
|
||||
|
||||
override fun defineCommands() {
|
||||
define ("implings", Privilege.ADMIN, "", "Lists the currently active implings/spawners") { player, _ ->
|
||||
for (i in 0..310)
|
||||
setInterfaceText(player, "", 275, i)
|
||||
setInterfaceText(player, "Implings", 275, 2)
|
||||
for ((index, impling) in activeImplings.withIndex()) {
|
||||
var text = "This shouldn't be here -> ${impling.id}"
|
||||
if (impling.id < 1028) {
|
||||
val table = ImplingSpawner.forId(impling.id)
|
||||
if (table != null)
|
||||
text = table.name
|
||||
}
|
||||
else text = impling.name
|
||||
setInterfaceText(player, "$text -> ${impling.location}", 275, index + 11)
|
||||
}
|
||||
openInterface(player, 275)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val implingsClearedPerTick = 5
|
||||
|
||||
var nextCycle = 0
|
||||
var activeImplings = ArrayList<NPC>()
|
||||
|
||||
fun clearSomeImplings (amount: Int) {
|
||||
for (i in 0 until amount) {
|
||||
val impling = activeImplings.removeAt(0)
|
||||
poofClear(impling)
|
||||
}
|
||||
}
|
||||
|
||||
fun generateSpawners () {
|
||||
val typeLocations = ImplingSpawnLocations.values()
|
||||
for (set in typeLocations) {
|
||||
val locations = set.locations
|
||||
val type = set.type
|
||||
locations.forEach { generateSpawnersAt(it, type) }
|
||||
}
|
||||
}
|
||||
|
||||
fun generateSpawnersAt(location: Location, type: ImplingSpawnTypes) {
|
||||
for (i in 0 until type.spawnRolls) {
|
||||
val spawner = type.table.roll() ?: continue
|
||||
if (spawner == ImplingSpawner.Nothing) continue
|
||||
val npc = NPC.create (spawner.npcId, location)
|
||||
npc.init()
|
||||
activeImplings.add(npc)
|
||||
}
|
||||
}
|
||||
|
||||
fun getTicksBeforeNextCycleToDespawn() : Int {
|
||||
return ceil (activeImplings.size / implingsClearedPerTick.toDouble()).toInt()
|
||||
}
|
||||
|
||||
fun deregister (impling: NPC, graceful: Boolean = false) : Boolean {
|
||||
activeImplings.remove(impling)
|
||||
if (graceful)
|
||||
poofClear(impling)
|
||||
else
|
||||
impling.clear()
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
package content.global.skill.hunter.implings
|
||||
|
||||
import core.api.utils.*
|
||||
import core.game.world.map.*
|
||||
import core.game.world.map.path.*
|
||||
import core.game.world.map.build.*
|
||||
|
||||
enum class Impling (val npcId: Int, val puroId: Int) {
|
||||
Baby (1028, 6055),
|
||||
Young (1029, 6056),
|
||||
Gourmet (1030, 6057),
|
||||
Earth (1031, 6058),
|
||||
Essence (1032, 6059),
|
||||
Eclectic (1033, 6060),
|
||||
Ninja (6053, 6063),
|
||||
Nature (1034, 6061),
|
||||
Magpie (1035, 6062),
|
||||
Dragon (6054, 6064);
|
||||
|
||||
companion object {
|
||||
fun getIds() : IntArray {
|
||||
val list = ArrayList<Int>()
|
||||
for (imp in values()){
|
||||
list.add(imp.npcId)
|
||||
list.add(imp.puroId)
|
||||
}
|
||||
return list.toIntArray()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class ImplingSpawner (val npcId: Int, val table: WeightedTable<Impling>) {
|
||||
LowTier (npcId = 1024, WeightedTable.create
|
||||
(
|
||||
Pair (Impling.Baby, 20.0),
|
||||
Pair (Impling.Young, 20.0),
|
||||
Pair (Impling.Gourmet, 20.0),
|
||||
Pair (Impling.Earth, 20.0),
|
||||
Pair (Impling.Essence, 10.0),
|
||||
Pair (Impling.Eclectic,10.0)
|
||||
)),
|
||||
MidTier (npcId = 1025, WeightedTable.create
|
||||
(
|
||||
Pair (Impling.Gourmet, 10.0),
|
||||
Pair (Impling.Earth, 10.0),
|
||||
Pair (Impling.Essence, 20.0),
|
||||
Pair (Impling.Eclectic, 37.0),
|
||||
Pair (Impling.Nature, 20.0),
|
||||
Pair (Impling.Magpie, 2.0),
|
||||
Pair (Impling.Ninja, 1.0)
|
||||
)),
|
||||
HighTier (npcId = 1026, WeightedTable.create
|
||||
(
|
||||
Pair (Impling.Nature, 10.0),
|
||||
Pair (Impling.Magpie, 50.0),
|
||||
Pair (Impling.Ninja, 30.0),
|
||||
Pair (Impling.Dragon, 10.0)
|
||||
)),
|
||||
LowPuroTier (npcId = 6065, WeightedTable.create
|
||||
(
|
||||
Pair (Impling.Baby, 20.0),
|
||||
Pair (Impling.Young, 20.0),
|
||||
Pair (Impling.Gourmet, 20.0),
|
||||
Pair (Impling.Earth, 20.0),
|
||||
Pair (Impling.Essence, 10.0),
|
||||
Pair (Impling.Eclectic,10.0)
|
||||
)),
|
||||
MidPuroTier (npcId = 6066, WeightedTable.create
|
||||
(
|
||||
Pair (Impling.Gourmet, 10.0),
|
||||
Pair (Impling.Earth, 10.0),
|
||||
Pair (Impling.Essence, 20.0),
|
||||
Pair (Impling.Eclectic, 37.0),
|
||||
Pair (Impling.Nature, 20.0),
|
||||
Pair (Impling.Magpie, 2.0),
|
||||
Pair (Impling.Ninja, 1.0)
|
||||
)),
|
||||
HighPuroTier (npcId = 6067, WeightedTable.create
|
||||
(
|
||||
Pair (Impling.Nature, 150.0),
|
||||
Pair (Impling.Magpie, 114.0),
|
||||
Pair (Impling.Ninja, 37.0),
|
||||
Pair (Impling.Dragon, 10.0),
|
||||
)),
|
||||
Nothing (npcId = -1, WeightedTable<Impling>());
|
||||
|
||||
companion object {
|
||||
private val idMap = values().map { it.npcId to it }.toMap()
|
||||
|
||||
fun forId (id: Int) : ImplingSpawner? {
|
||||
return idMap[id]
|
||||
}
|
||||
|
||||
fun getIds() : IntArray {
|
||||
return idMap.keys.toIntArray()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class ImplingSpawnTypes (val table: WeightedTable<ImplingSpawner>, val spawnRolls: Int) {
|
||||
Standard (WeightedTable.create
|
||||
(
|
||||
Pair (ImplingSpawner.LowTier, 14.0),
|
||||
Pair (ImplingSpawner.MidTier, 7.0),
|
||||
Pair (ImplingSpawner.HighTier, 4.0),
|
||||
Pair (ImplingSpawner.Nothing, 75.0)
|
||||
), spawnRolls = 3),
|
||||
LowTierOnly (WeightedTable.create
|
||||
(
|
||||
Pair (ImplingSpawner.LowTier, 100.0)
|
||||
), spawnRolls = 1),
|
||||
MidTierOnly (WeightedTable.create
|
||||
(
|
||||
Pair (ImplingSpawner.MidTier, 100.0)
|
||||
), spawnRolls = 1),
|
||||
HighTierOnly (WeightedTable.create
|
||||
(
|
||||
Pair (ImplingSpawner.HighTier, 100.0)
|
||||
), spawnRolls = 1),
|
||||
HighPuroTierOnly (WeightedTable.create
|
||||
(
|
||||
Pair (ImplingSpawner.HighPuroTier, 100.0)
|
||||
), spawnRolls = 1)
|
||||
}
|
||||
|
||||
enum class ImplingSpawnLocations (val type: ImplingSpawnTypes, vararg val locations: Location) {
|
||||
StandardSpawns (ImplingSpawnTypes.Standard,
|
||||
Location.create(2204, 3232, 0),
|
||||
Location.create(2582, 2974, 0),
|
||||
Location.create(2522, 3105, 0),
|
||||
Location.create(2470, 3221, 0),
|
||||
Location.create(2593, 3251, 0),
|
||||
Location.create(2735, 3354, 0),
|
||||
Location.create(2646, 3424, 0),
|
||||
Location.create(2462, 3429, 0),
|
||||
Location.create(2386, 3513, 0),
|
||||
Location.create(2335, 3649, 0),
|
||||
Location.create(2740, 3536, 0),
|
||||
Location.create(2654, 3609, 0),
|
||||
Location.create(2724, 3769, 0),
|
||||
Location.create(2817, 3513, 0),
|
||||
Location.create(2844, 3154, 0),
|
||||
Location.create(2844, 3033, 0),
|
||||
Location.create(2841, 2926, 0),
|
||||
Location.create(2907, 3491, 0),
|
||||
Location.create(3020, 3525, 0),
|
||||
Location.create(3021, 3424, 0),
|
||||
Location.create(2981, 3276, 0),
|
||||
Location.create(3135, 3377, 0),
|
||||
Location.create(3149, 3233, 0),
|
||||
Location.create(3170, 3004, 0),
|
||||
Location.create(3239, 3289, 0),
|
||||
Location.create(3287, 3271, 0),
|
||||
Location.create(3418, 3124, 0),
|
||||
Location.create(3356, 3010, 0),
|
||||
Location.create(3550, 3529, 0),
|
||||
Location.create(3449, 3488, 0),
|
||||
Location.create(3441, 3352, 0)
|
||||
),
|
||||
LowTierOnlySpawns (ImplingSpawnTypes.LowTierOnly,
|
||||
Location.create(2348, 3610, 0),
|
||||
Location.create(2277, 3186, 0),
|
||||
Location.create(2459, 3085, 0),
|
||||
Location.create(2564, 3393, 0),
|
||||
Location.create(2780, 3463, 0),
|
||||
Location.create(2966, 3411, 0),
|
||||
Location.create(3094, 3237, 0),
|
||||
Location.create(3281, 3427, 0),
|
||||
Location.create(3278, 3160, 0)
|
||||
)
|
||||
}
|
||||
|
||||
object ImplingClipper : ClipMaskSupplier {
|
||||
override fun getClippingFlag (z: Int, x: Int, y: Int) : Int {
|
||||
var flag = RegionManager.getClippingFlag(z, x, y);
|
||||
return flag and (RegionFlags.SOLID_TILE.inv()) and (RegionFlags.TILE_OBJECT.inv()) //Allow walking on water and flying over small objects, but keep all other tile flags the same.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package content.global.skill.hunter.implings
|
||||
|
||||
import core.api.*
|
||||
import core.tools.*
|
||||
import core.game.node.entity.npc.*
|
||||
import core.game.world.map.path.ClipMaskSupplier
|
||||
|
||||
/**
|
||||
* Manages the behavior for impling spawners (the invisible NPCs that turn into random implings).
|
||||
*/
|
||||
class ImplingSpawnerBehavior : NPCBehavior (*ImplingSpawner.getIds()) {
|
||||
override fun onCreation (self: NPC) {
|
||||
val isPuro = isPuroSpawner(self)
|
||||
val delay = if (isPuro) 120 else 180
|
||||
setAttribute(self, "transformTime", getWorldTicks() + secondsToTicks(delay))
|
||||
self.isRespawn = isPuro
|
||||
self.walkRadius = if (isPuro) 20 else 100
|
||||
self.isWalks = true
|
||||
self.isNeverWalks = false
|
||||
self.setInvisible(true)
|
||||
self.properties.spawnLocation = self.location
|
||||
}
|
||||
|
||||
override fun onRespawn (self: NPC) {
|
||||
if (!isPuroSpawner(self))
|
||||
log (this::class.java, Log.ERR, "Non-puro spawner has respawned!")
|
||||
this.onCreation(self)
|
||||
}
|
||||
|
||||
override fun tick (self: NPC) : Boolean {
|
||||
var transformTime = getAttribute(self, "transformTime", 0)
|
||||
if (transformTime != 0 && transformTime <= getWorldTicks()) {
|
||||
val table = ImplingSpawner.forId(self.id)?.table ?: return ImplingController.deregister(self)
|
||||
val impling = table.roll() ?: return ImplingController.deregister(self)
|
||||
val targetId = if (isPuroSpawner(self)) impling.puroId else impling.npcId
|
||||
self.transform(targetId)
|
||||
self.behavior = forId(self.id)
|
||||
self.setInvisible(false)
|
||||
removeAttribute(self, "transformTime")
|
||||
sendGraphics(1119, self.location)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getClippingSupplier (self: NPC) : ClipMaskSupplier {
|
||||
return ImplingClipper
|
||||
}
|
||||
|
||||
private fun isPuroSpawner(self: NPC) : Boolean {
|
||||
return self.id > 6000
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ object Modern {
|
||||
const val CONFUSE = 2
|
||||
const val BONES_TO_BANANAS = 9
|
||||
const val WEAKEN = 11
|
||||
const val BIND = 12
|
||||
const val LOW_ALCHEMY = 13
|
||||
const val VARROCK_TELEPORT = 15
|
||||
const val LUMBRIDGE_TELEPORT = 18
|
||||
@@ -13,6 +14,7 @@ object Modern {
|
||||
const val SUPERHEAT = 25
|
||||
const val CAMELOT_TELEPORT = 26
|
||||
const val TELEPORT_TO_HOUSE = 23
|
||||
const val SNARE = 30
|
||||
const val ARDOUGNE_TELEPORT = 32
|
||||
const val HIGH_ALCHEMY = 34
|
||||
const val WATCHTOWER_TELEPORT = 37
|
||||
@@ -21,5 +23,6 @@ object Modern {
|
||||
const val APE_ATOLL_TELEPORT = 47
|
||||
const val VULNERABILITY = 50
|
||||
const val ENFEEBLE = 53
|
||||
const val ENTANGLE = 56
|
||||
const val STUN = 57
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,8 +83,7 @@ class DeathspawnBehavior : NPCBehavior(NPCs.DEATH_SPAWN_1614) {
|
||||
|
||||
override fun onRemoval(self: NPC) {
|
||||
val parent = getAttribute<NPC?>(self, "parent", null) ?: return
|
||||
if (parent.behavior !is NechryaelBehavior) return
|
||||
parent.behavior.removeSpawn(parent, self)
|
||||
(parent.behavior as? NechryaelBehavior)?.let { it.removeSpawn (parent, self) }
|
||||
}
|
||||
|
||||
override fun tick(self: NPC): Boolean {
|
||||
@@ -102,4 +101,4 @@ class DeathspawnBehavior : NPCBehavior(NPCs.DEATH_SPAWN_1614) {
|
||||
override fun canBeAttackedBy(self: NPC, attacker: Entity, style: CombatStyle, shouldSendMessage: Boolean): Boolean {
|
||||
return attacker == getAttribute<Player?>(self, "target", null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user