From 23bc5944693b5ac740d94782bb2d72d852a69cca Mon Sep 17 00:00:00 2001 From: Kermit Frog Date: Wed, 1 Apr 2026 14:37:51 +0000 Subject: [PATCH] Extended ::bury command to support hiding player name and adding message Implemented ::buryitem [msg] Implemented ::burymessage --- .../game/system/command/sets/FunCommandSet.kt | 267 +++++++++++++++++- 1 file changed, 253 insertions(+), 14 deletions(-) diff --git a/Server/src/main/core/game/system/command/sets/FunCommandSet.kt b/Server/src/main/core/game/system/command/sets/FunCommandSet.kt index 918fe488f..05b59c153 100644 --- a/Server/src/main/core/game/system/command/sets/FunCommandSet.kt +++ b/Server/src/main/core/game/system/command/sets/FunCommandSet.kt @@ -3,11 +3,13 @@ package core.game.system.command.sets import content.global.handlers.item.SpadeDigListener import content.region.misc.tutisland.handlers.iface.CharacterDesign import core.api.* +import core.ServerStore import core.game.dialogue.DialogueFile import core.game.node.entity.combat.ImpactHandler import core.game.node.entity.npc.NPC import core.game.node.entity.player.Player import core.game.node.entity.player.info.login.PlayerSaver +import core.game.node.item.Item import core.game.system.command.Privilege import core.game.system.task.Pulse import core.game.world.GameWorld @@ -17,8 +19,9 @@ import core.game.world.repository.Repository.getPlayerByName import core.game.world.update.flag.context.Animation import core.game.world.update.flag.context.Graphics import core.plugin.Initializable -import core.tools.END_DIALOGUE import core.tools.RandomFunction +import core.tools.Log +import org.json.simple.JSONArray import org.json.simple.JSONObject import org.rs09.consts.Sounds import java.awt.HeadlessException @@ -30,6 +33,60 @@ import kotlin.streams.toList class FunCommandSet : CommandSet(Privilege.ADMIN) { var npcs: List = ArrayList() + private val TREASURE_KEY = "fun_command_buried_treasures" + private val treasures = ArrayList() + + init { + loadTreasures() + } + + /** + * I hope ceikry doesn't punish me for this ~ used SkillcapePerks for a base idea tried to make it modular. + * Supports persistence across reboots for bury, buryitem, and burymessage supporting all command arguments. + */ + private fun loadTreasures() { + + val archive = ServerStore.getArchive(TREASURE_KEY) + if (!archive.containsKey("data")) return + + try { + val array = archive["data"] as JSONArray + + for (obj in array) { + + val json = obj as JSONObject + val x = (json["x"] as Long).toInt() + val y = (json["y"] as Long).toInt() + val z = (json["z"] as Long).toInt() + val loc = Location.create(x, y, z) + + val type = TreasureType.valueOf(json["type"] as String) + val hiderName = json["hiderName"] as? String ?: "Unknown" + val hideName = json["hideName"] as? Boolean ?: false + val customMessage = json["customMessage"] as? String + val message = json["message"] as? String ?: "" + + val items = ArrayList() + if (json.containsKey("items")) { + val itemsJson = json["items"] as JSONArray + for (i in itemsJson) { + val itemObj = i as JSONObject + val id = (itemObj["id"] as Long).toInt() + val amount = (itemObj["amount"] as Long).toInt() + items.add(Item(id, amount)) + } + } + + val treasure = BuriedTreasure(loc, type, items, message, hiderName, hideName, customMessage) + treasures.add(treasure) + registerTreasureListener(treasure) + } + log(FunCommandSet::class.java, Log.DEBUG, "Loaded ${treasures.size} buried treasures.") + } catch (e: Exception) { + log(FunCommandSet::class.java, Log.ERR, "Failed to load buried treasures: ${e.message}") + e.printStackTrace() + } + } override fun defineCommands() { @@ -175,19 +232,39 @@ class FunCommandSet : CommandSet(Privilege.ADMIN) { /** * Bury inventory at current location */ - define("bury", description = "Buries your entire inventory at your current location."){player, _ -> + define("bury", description = "Buries your entire inventory at your current location for treasure hunters. Required true/false to hide players name and an optional custom message."){player, args -> if(player.inventory.isEmpty){ reject(player, "You have no items to bury.") } + if (args.size < 2) { + reject(player, "Usage: ::bury true | false [custom news message]") + return@define + } + + val hideName = when(args[1].lowercase()) { + "true" -> true + "false" -> false + else -> { + reject(player, "Invalid argument. Usage: ::bury true | false [custom news message]") + return@define + } + } + + val customMessage = if (args.size > 2) { + args.slice(2 until args.size).joinToString(" ") + } else { + null + } + player.dialogueInterpreter.open(object : DialogueFile(){ override fun handle(componentID: Int, buttonID: Int) { when(stage){ - 0 -> dialogue("This will bury your whole inventory in this spot.","Are you sure?").also { stage++ } + 0 -> dialogue("This will bury your whole inventory at this spot.","Are you sure?").also { stage++ } 1 -> options("Yes","No").also { stage++ } 2 -> when(buttonID){ - 1 -> bury(player).also { end() } - 2 -> stage = END_DIALOGUE + 1 -> bury(player, hideName, customMessage).also { end() } + 2 -> end() } } } @@ -195,6 +272,78 @@ class FunCommandSet : CommandSet(Privilege.ADMIN) { } + /** + * Bury a secret message at current location for a player to find. + */ + define("burymessage", description = "Buries a secret message at your current location."){ player, args -> + if (args.size < 2) { + reject(player, "Usage: ::burymessage [message]") + return@define + } + + val message = args.slice(1 until args.size).joinToString(" ") + val loc = Location.create(player.location) + + if(SpadeDigListener.listeners.containsKey(loc)){ + reject(player, "There is already something buried here.") + return@define + } + + val treasure = BuriedTreasure(loc, TreasureType.MESSAGE, emptyList(), message, player.username, false, null) + treasures.add(treasure) + saveTreasures() + registerTreasureListener(treasure) + + notify(player, "You have buried the message '$message' at $loc") + log(FunCommandSet::class.java, Log.DEBUG, "Message buried by ${player.username} at $loc: \"$message\"") + } + + /** + * Bury a specific item at current location + */ + define("buryitem", description = "Buries a specific item at your current location."){ player, args -> + if (args.size < 3) { + reject(player, "Usage: ::buryitem item id true | false [custom message]") + return@define + } + + val itemId = args[1].toIntOrNull() + if (itemId == null) { + reject(player, "Invalid item ID.") + return@define + } + + val hideName = when(args[2].lowercase()) { + "true" -> true + "false" -> false + else -> { + reject(player, "Invalid argument. Usage: ::buryitem item id true | false [custom message]") + return@define + } + } + + val customMessage = if (args.size > 3) { + args.slice(3 until args.size).joinToString(" ") + } else { + null + } + + player.dialogueInterpreter.open(object : DialogueFile(){ + override fun handle(componentID: Int, buttonID: Int) { + when(stage){ + 0 -> dialogue("This will bury a ${Item(itemId).name} at this spot.","Are you sure?").also { stage++ } + 1 -> options("Yes","No").also { stage++ } + 2 -> when(buttonID){ + 1 -> buryItem(player, itemId, hideName, customMessage).also { end() } + 2 -> end() + } + } + } + }) + + + } + define("appearance", Privilege.ADMIN, "", "Allows you to change your appearance."){ player, _ -> CharacterDesign.reopen(player) } @@ -249,19 +398,109 @@ class FunCommandSet : CommandSet(Privilege.ADMIN) { } - fun bury(player: Player){ + fun bury(player: Player, hideName: Boolean = false, customMessage: String? = null){ + val loc = Location.create(player.location) - val inv = player.inventory.toArray().filterNotNull() - SpadeDigListener.registerListener(player.location){ p -> - for(item in inv){ - addItemOrDrop(p, item.id, item.amount) - sendMessage(p, "You dig and find ${if(item.amount > 1) "some" else "a"} ${item.name}") - } - sendNews("${player.username} has found the hidden treasure! Congratulations!!!") - SpadeDigListener.listeners.remove(loc) + if(SpadeDigListener.listeners.containsKey(loc)){ + notify(player, "There is already something buried here.") + return } + + val inv = player.inventory.toArray().filterNotNull().toList() + if (inv.isEmpty()) { + notify(player, "You have nothing to bury.") + return + } + + val treasure = BuriedTreasure(loc, TreasureType.ITEM, inv, "", player.username, hideName, customMessage) + treasures.add(treasure) + saveTreasures() + registerTreasureListener(treasure) + player.inventory.clear() notify(player, "You have buried your loot at ${loc.toString()}") + log(FunCommandSet::class.java, Log.DEBUG, "Loot buried by ${player.username} at $loc. Masked: $hideName") } + fun buryItem(player: Player, itemId: Int, hideName: Boolean, customMessage: String? = null) { + val loc = Location.create(player.location) + if(SpadeDigListener.listeners.containsKey(loc)){ + notify(player, "There is already something buried here.") + return + } + + val treasure = BuriedTreasure(loc, TreasureType.ITEM, listOf(Item(itemId, 1)), "", player.username, hideName, customMessage) + treasures.add(treasure) + saveTreasures() + registerTreasureListener(treasure) + + notify(player, "You have buried item ${Item(itemId).name} at $loc") + log(FunCommandSet::class.java, Log.DEBUG, "Item $itemId buried by ${player.username} at $loc. Masked: $hideName") + } + + private fun registerTreasureListener(t: BuriedTreasure) { + + SpadeDigListener.registerListener(t.location) { p -> + log(FunCommandSet::class.java, Log.DEBUG, "SpadeDigListener triggered for ${p.username} at ${t.location}") + + if (t.type == TreasureType.ITEM) { + for(item in t.items){ + addItemOrDrop(p, item.id, item.amount) + sendMessage(p, "You dig and find ${if(item.amount > 1) "some" else "a"} ${item.name}") + } + val finderName = if (t.hideName) "Someone" else p.username + val message = t.customMessage ?: "$finderName has found the hidden treasure! Congratulations!!!" + sendNews(message) + } else { + sendMessage(p, t.message) + } + + SpadeDigListener.listeners.remove(t.location) + treasures.remove(t) + saveTreasures() + } + } + + private fun saveTreasures() { + + val array = JSONArray() + + for (t in treasures) { + val json = JSONObject() + json["x"] = t.location.x + json["y"] = t.location.y + json["z"] = t.location.z + json["type"] = t.type.name + json["hiderName"] = t.hiderName + json["hideName"] = t.hideName + if (t.customMessage != null) json["customMessage"] = t.customMessage + json["message"] = t.message + + val itemsArray = JSONArray() + for (i in t.items) { + val itemObj = JSONObject() + itemObj["id"] = i.id + itemObj["amount"] = i.amount + itemsArray.add(itemObj) + } + json["items"] = itemsArray + + array.add(json) + } + val archive = ServerStore.getArchive(TREASURE_KEY) + archive["data"] = array + } + + private data class BuriedTreasure( + val location: Location, + val type: TreasureType, + val items: List, + val message: String, + val hiderName: String, + val hideName: Boolean, + val customMessage: String? + ) + + private enum class TreasureType { ITEM, MESSAGE } + }