From ac6956b356b39987641eb1af4a7aa5fd06698af1 Mon Sep 17 00:00:00 2001 From: aidan Date: Sat, 4 Jul 2026 13:29:02 -0500 Subject: [PATCH] imp in a box --- .../global/skill/hunter/ImpBoxListener.kt | 218 ++++++++++++++++++ .../global/skill/hunter/ImpBoxPlugin.java | 174 -------------- 2 files changed, 218 insertions(+), 174 deletions(-) create mode 100644 Server/src/main/content/global/skill/hunter/ImpBoxListener.kt delete mode 100644 Server/src/main/content/global/skill/hunter/ImpBoxPlugin.java diff --git a/Server/src/main/content/global/skill/hunter/ImpBoxListener.kt b/Server/src/main/content/global/skill/hunter/ImpBoxListener.kt new file mode 100644 index 000000000..0a601db2c --- /dev/null +++ b/Server/src/main/content/global/skill/hunter/ImpBoxListener.kt @@ -0,0 +1,218 @@ +package content.global.skill.hunter + +import core.api.* +import core.game.dialogue.DialogueLabeller +import core.game.dialogue.DialogueOption +import core.game.dialogue.FacialExpression +import core.game.interaction.IntType +import core.game.interaction.InteractionListener +import core.game.interaction.InterfaceListener +import core.game.node.entity.npc.NPC +import core.game.node.entity.player.Player +import core.game.node.entity.player.link.IronmanMode +import core.game.node.item.Item +import core.game.system.config.ItemConfigParser +import org.rs09.consts.Items +import org.rs09.consts.NPCs + +/** + * The Imp-in-a-box that can bank items. + */ + +class ImpBoxListener : InteractionListener, InterfaceListener { + + // Great source: https://www.youtube.com/watch?v=k0LhRhcQ0g8 + // wiki: https://runescape.wiki/w/Imp-in-a-box, https://runescape.wiki/w/Magic_box?oldid=1743149 + // uses 701.cs2 + + companion object { + val RELEASE_IFACE = 478 + private val BOXES = intArrayOf(Items.IMP_IN_A_BOX2_10027, Items.IMP_IN_A_BOX1_10028) + } + + override fun defineListeners() { + + // use an item with the imp box + onUseAnyWith(IntType.ITEM,*BOXES) { player, used, _ -> + bankItem(player, used.asItem()) + return@onUseAnyWith true + } + + // open the banking interface + on(BOXES, IntType.ITEM, "bank") {player, _ -> + openInterface(player, RELEASE_IFACE) + return@on true + } + + // talk to the imp + on(BOXES, IntType.ITEM, "talk-to") {player, node -> + openDialogue(player, ImpBoxDialogueFile(node.id), NPC(NPCs.IMP_1531)) + return@on true + } + } + + override fun defineInterfaceListeners() { + + // send the interface settings that display the deposit and examine options that get set by the cs2 file + onOpen(RELEASE_IFACE) { player, _ -> + val settings = IfaceSettingsBuilder() + .enableOptions(0, 1) // option 0 = "Deposit" (CS2 slot 1), option 1 = "Examine" (CS2 slot 2) + .build() + player.packetDispatch.sendIfaceSettings(settings, 14, RELEASE_IFACE, 0, 28) + return@onOpen true + } + + on(RELEASE_IFACE) { player, _, opcode, buttonID, slot, _ -> + val clickItemButton = 14 + val depositOpcode = 155 + val examineOpcode = 196 + val item = player.inventory[slot] + + when(buttonID) { + clickItemButton -> { + when(opcode) { + depositOpcode -> bankItem(player, item) + examineOpcode -> sendMessage(player, "${item.definition.examine}") + } + } + } + return@on true + } + } + + // banks the item + private fun bankItem(player: Player, item: Item) { + + if (item != null) { + // check for non-bankable conditions (non-bankable items, banking the imp, ult. ironman, or in wildy) + if (!item.definition.getConfiguration(ItemConfigParser.BANKABLE, true) + || item.id in BOXES + || player.ironmanManager.mode == IronmanMode.ULTIMATE + || player.skullManager.level > 20 + ) { + sendMessage(player, "A magical force prevents you from banking this item.") + return + } + + // can't do in combat + if (player.inCombat()) { + sendMessage(player, "You can't use this while in combat.") + return + } + + // attempt to add to bank + if (addItem(player, item.id, item.amount, Container.BANK) + && removeItem(player, item) + && decrementBox(player) + ) { + closeInterface(player) + sendMessage(player, "The imp teleports away, taking the item to your bank account.") + } else { + sendMessage(player, "You cannot add this item to your bank.") + } + } + } + + // decrements the box + private fun decrementBox(player: Player) : Boolean { + if (amountInInventory(player, Items.IMP_IN_A_BOX1_10028) > 0) { + // replace a 1-charge box with a 0-charge + if (removeItem(player, Items.IMP_IN_A_BOX1_10028)) { + addItem(player, Items.MAGIC_BOX_10025) + return true + } + } else if (amountInInventory(player, Items.IMP_IN_A_BOX2_10027) > 0) { + // replace a 2-charge box with a 1-charge + if (removeItem(player, Items.IMP_IN_A_BOX2_10027)) { + addItem(player, Items.IMP_IN_A_BOX1_10028) + return true + } + } else { + sendMessage(player, "ERROR: No valid imp boxes found. Please report this.") + return false + } + return true + } + +} + +// dialogue for the imp in a box +class ImpBoxDialogueFile(val box: Int) : DialogueLabeller() { + override fun addConversation() { + exec { player, _ -> + if (box == Items.IMP_IN_A_BOX2_10027) { + loadLabel(player, "two start") + } else { + loadLabel(player, "one start") + } + } + + label("one start") + player("Hey imp, are you still there?") + npc(FacialExpression.OLD_DEFAULT, "An who's fault is that, eh? EH? I got betta fings to do dan sit ere waitin' for ya. 'Ave ya made up ya mind what else I'm luggin about?") + options( + DialogueOption("ok", "Yes I have."), + DialogueOption("no escape", "No, I'm afraid you're going to have to wait a bit longer.") + ) + + label("no escape") + npc(FacialExpression.OLD_DEFAULT, "Dat's alright guv'nor. I'll get back to me luvverly dream about beads. Big shiny beads. Love it!") + goto("end") + + label("two start") + player("Hey imp, can you hear me?") + npc(FacialExpression.OLD_DEFAULT, "Of course I can hear ya, ya great big ape. You know,", "'veres not even enuf space to swing Bob about in 'ere.", "How about a breather? You know, stretch me pins for a", "bit?") + options( + DialogueOption("no", "No, I'm going to keep you in there.", "No, I'm going to keep you in there. I might keep you as a pet."), + DialogueOption("not bad", "It's not that bad.", "It's not that bad. You've got four big windows, charming company...er..."), + DialogueOption("wish", "Don't I get three wishes?") + ) + + label("no") + npc(FacialExpression.OLD_DEFAULT, "Pet!! Nah mate. I fink you'd find dat you'd be my pet!! We is not makin good pets.") + player("Really? Why not?") + npc(FacialExpression.OLD_DEFAULT, "Coz...errr...") + npc(FacialExpression.OLD_DEFAULT, "We bite! Yeah we is biting and...and...er...") + npc(FacialExpression.OLD_DEFAULT, "We is fire risk! Yeah dat's it! We be burning down your housey and stealin' all ya shiny gems. Oh, and da beads!! Mmmm, beads.") + player("Fire risk? How does that work?") + npc(FacialExpression.OLD_DEFAULT, "Is those wizzies. Dey don't like de imps so dey make us go BOOOM!!") + goto("end") + + label("not bad") + npc(FacialExpression.OLD_DEFAULT, "Yeah, we's love tiny, crampt space. It be magical. But I is a busy imp, innit? Dragons needin' ticklin', shiny relics needin' stealin', you know how it goes.") + npc(FacialExpression.OLD_DEFAULT, "So, if you's know whas good for ya, you'd be lettin' me go, right?") + options( + DialogueOption("no", "No, I'm going to keep you in there.", "No, I'm going to keep you in there. I might keep you as a pet."), + DialogueOption("wish", "Don't I get three wishes?") + ) + + label("wish") + npc(FacialExpression.OLD_DEFAULT, "Nah, mate. Dunno what you're chirpin' about.") + player("Well, you're a magical creature aren't you? Surely I", "get some wishes for capturing you, or releasing you, or", "something?") + npc(FacialExpression.OLD_DEFAULT, "I'm finking dat you be a bit confoosed. I is an imp, not", "some namby-pamby genie or some kinda fairy. Ye can", "tell by the horns.") + npc(FacialExpression.OLD_DEFAULT, "Sayin' dat, I don't fancy being cooped up like one of", "my uncle's pigeons. Tell you what, is there anything", "you need deliverin' to the bank? I may not be no", "cunjerer or sommink like dat, but I can get about nice") + npc(FacialExpression.OLD_DEFAULT, "an quick like. If you let me scarper, I'll take a couple of", "fings to the bank for ya. You game?") + options( + DialogueOption("ok", "Okay, that sounds fair."), + DialogueOption("three", "Surely it should be three items?", "Surely it should be three items? Then it's one item per wish."), + DialogueOption("nothing", "I've got nothing I need banking right now.") + ) + + label("ok") + exec { player, _ -> + openInterface(player, ImpBoxListener.RELEASE_IFACE) + end() + } + + label("three") + npc(FacialExpression.OLD_DEFAULT, "I've already told ya, I ain't no bloomin' fairy. Besides, you know wot dey say, three's a crowd innit? I don't fink I can hop about carryin' more dan 2 fings.") + options( + DialogueOption("ok", "Okay, that sounds fair."), + DialogueOption("nothing", "I've got nothing I need banking right now.") + ) + + label("nothing") + npc(FacialExpression.OLD_DEFAULT, "Great, just blinkin great, dat is. I'll just sit about", "countin' zombie sheep then. One...two...two and a", "bit...three and a bit more... I don't fink sheep 'ave dat", "many legs...") + goto("end") + } +} \ No newline at end of file diff --git a/Server/src/main/content/global/skill/hunter/ImpBoxPlugin.java b/Server/src/main/content/global/skill/hunter/ImpBoxPlugin.java deleted file mode 100644 index 800e342eb..000000000 --- a/Server/src/main/content/global/skill/hunter/ImpBoxPlugin.java +++ /dev/null @@ -1,174 +0,0 @@ -package content.global.skill.hunter; - -import core.cache.def.impl.ItemDefinition; -import core.game.component.Component; -import core.game.component.ComponentDefinition; -import core.game.component.ComponentPlugin; -import core.plugin.Initializable; -import core.game.dialogue.DialogueInterpreter; -import core.game.dialogue.DialoguePlugin; -import core.game.dialogue.FacialExpression; -import core.game.interaction.OptionHandler; -import core.game.node.Node; -import core.game.node.entity.player.Player; -import core.game.node.item.Item; -import core.net.packet.PacketRepository; -import core.net.packet.context.ContainerContext; -import core.net.packet.out.ContainerPacket; -import core.plugin.Plugin; -import core.plugin.ClassScanner; -import core.tools.RandomFunction; - -/** - * Handles the imp box. - * @author Taylor - */ -@Initializable -public class ImpBoxPlugin extends OptionHandler { - - /** - * The item ids. - */ - private static final int[] IDS = new int[] { 10028, 10027 }; - - @Override - public Plugin newInstance(Object arg) throws Throwable { - ClassScanner.definePlugin(new ImpInterfaceHandler(null)); - for (int id : IDS) { - ItemDefinition.forId(id).getHandlers().put("option:bank", this); - ItemDefinition.forId(id).getHandlers().put("option:talk-to", this); - } - ClassScanner.definePlugin(new ImpBoxDialogue()); - return this; - } - - @Override - public boolean handle(Player player, Node node, String option) { - switch (option) { - case "bank": - Component component = new Component(478); - component.setPlugin(new ImpInterfaceHandler((Item) node)); - player.getInterfaceManager().open(component); - PacketRepository.send(ContainerPacket.class, new ContainerContext(player, 478, 61, 91, player.getInventory(), true)); - break; - case "talk-to": - player.getDialogueInterpreter().open("imp-box"); - break; - } - return true; - } - - @Override - public boolean isWalk() { - return false; - } - - /** - * Handles talk-to dialogue on the imp box. - * @author Taylor - */ - public static class ImpBoxDialogue extends DialoguePlugin { - - /** - * The messages to send. - */ - private static final String[] MESSAGES = { "Let me outa here!", "Errgghh..", "Well look who it is.", "What are you looking at?" }; - - /** - * Constructs a new {@code ImpBoxDialogue} {@code Object}. - */ - public ImpBoxDialogue() { - /** - * empty. - */ - } - - /** - * Constructs a new {@code ImpBoxDialogue} {@code Object}. - * @param player The player. - */ - public ImpBoxDialogue(Player player) { - super(player); - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new ImpBoxDialogue(player); - } - - @Override - public boolean open(Object... args) { - interpreter.sendDialogues(708, FacialExpression.FURIOUS, MESSAGES[RandomFunction.getRandom(MESSAGES.length - 1)]); - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - end(); - return true; - } - - @Override - public int[] getIds() { - return new int[] { DialogueInterpreter.getDialogueKey("imp-box") }; - } - - } - - /** - * Handles the imp interface. - * @author Taylor - */ - public class ImpInterfaceHandler extends ComponentPlugin { - - /** - * The message to show when the imp is gone. - */ - private static final String FINISHING_MESSAGE = "The imp teleports away, taking the item to your bank account."; - - /** - * The box the player is using. - */ - private Item box; - - /** - * Constructs a new {@code ImpInterfaceHandler} {@code Object}. - * @param box The box the player is using. - */ - public ImpInterfaceHandler(Item box) { - this.box = box; - } - - @Override - public Plugin newInstance(Object arg) throws Throwable { - ComponentDefinition.forId(478).setPlugin(this); - return this; - } - - @Override - public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) { - Item item = player.getInventory().get(slot); - if (item != null) { - if (player.getBank().canAdd(item) && item.getId() != box.getId()) { - player.getDialogueInterpreter().close(); - player.getInventory().remove(item); - player.getBank().add(item); - PacketRepository.send(ContainerPacket.class, new ContainerContext(player, 478, 61, 91, player.getInventory(), true)); - if (box.getId() == IDS[1]) { - int boxSlot = player.getInventory().getSlot(box); - player.getInventory().replace((box = new Item(IDS[0])), boxSlot); - } else if (box.getId() == IDS[0]) { - int boxSlot = player.getInventory().getSlot(box); - player.getInventory().replace(new Item(10025), boxSlot); - player.getInterfaceManager().close(component); - player.sendMessage(FINISHING_MESSAGE); - } - } - } else { - player.sendMessage("You cannot add this item to your bank."); - return false; - } - return true; - } - } -}