From bef103e25934ab2ba465e157fe776d947aa4a49b Mon Sep 17 00:00:00 2001 From: Oven Bread Date: Tue, 15 Jul 2025 12:29:09 +0000 Subject: [PATCH] Implemented semi-authentic Pious Pete random event --- Server/data/configs/npc_spawns.json | 4 + .../main/content/global/ame/RandomEvents.kt | 6 + .../candlelight/CandlelightInterface.kt | 164 ++++++++++++++++++ .../events/candlelight/PiousPeteDialogue.kt | 94 ++++++++++ .../ame/events/candlelight/PiousPeteNPC.kt | 49 ++++++ Server/src/main/core/ServerConstants.kt | 3 + .../game/system/config/ServerConfigParser.kt | 1 + Server/worldprops/default.conf | 2 + 8 files changed, 323 insertions(+) create mode 100644 Server/src/main/content/global/ame/events/candlelight/CandlelightInterface.kt create mode 100644 Server/src/main/content/global/ame/events/candlelight/PiousPeteDialogue.kt create mode 100644 Server/src/main/content/global/ame/events/candlelight/PiousPeteNPC.kt diff --git a/Server/data/configs/npc_spawns.json b/Server/data/configs/npc_spawns.json index 8899eea83..e152ca446 100644 --- a/Server/data/configs/npc_spawns.json +++ b/Server/data/configs/npc_spawns.json @@ -6727,6 +6727,10 @@ "npc_id": "3205", "loc_data": "{3139,3448,0,1,3}-" }, + { + "npc_id": "3207", + "loc_data": "{1970,5002,0,1,4}-" + }, { "npc_id": "3213", "loc_data": "{2568,3334,0,1,0}-" diff --git a/Server/src/main/content/global/ame/RandomEvents.kt b/Server/src/main/content/global/ame/RandomEvents.kt index 4acf90c99..88522b4a0 100644 --- a/Server/src/main/content/global/ame/RandomEvents.kt +++ b/Server/src/main/content/global/ame/RandomEvents.kt @@ -10,6 +10,7 @@ import content.global.ame.events.evilchicken.EvilChickenNPC import content.global.ame.events.freakyforester.FreakyForesterNPC import content.global.ame.events.maze.MazeNPC import content.global.ame.events.genie.GenieNPC +import content.global.ame.events.candlelight.PiousPeteNPC import content.global.ame.events.pillory.PilloryNPC import content.global.ame.events.rickturpentine.RickTurpentineNPC import content.global.ame.events.rivertroll.RiverTrollRENPC @@ -21,6 +22,7 @@ import content.global.ame.events.strangeplant.StrangePlantNPC import content.global.ame.events.swarm.SwarmNPC import content.global.ame.events.treespirit.TreeSpiritRENPC import content.global.ame.events.zombie.ZombieRENPC +import core.ServerConstants import core.api.utils.WeightBasedTable import core.api.utils.WeightedItem @@ -29,6 +31,7 @@ import core.game.node.entity.skill.Skills enum class RandomEvents(val npc: RandomEventNPC, val loot: WeightBasedTable? = null, val skillIds: IntArray = intArrayOf(), val type: String = "") { SANDWICH_LADY(npc = SandwichLadyRENPC()), GENIE(npc = GenieNPC()), + CANDLELIGHT(npc = PiousPeteNPC(), skillIds = intArrayOf(Skills.PRAYER)), CERTER(npc = CerterNPC(), loot = WeightBasedTable.create( WeightedItem(Items.UNCUT_SAPPHIRE_1623,1,1,3.4), WeightedItem(Items.KEBAB_1971,1,1,1.7), @@ -82,6 +85,9 @@ enum class RandomEvents(val npc: RandomEventNPC, val loot: WeightBasedTable? = n private fun populateMappings() { for (event in values()) { + if (!ServerConstants.INAUTHENTIC_CANDLELIGHT_RANDOM && event == CANDLELIGHT) { + continue + } for (id in event.skillIds) { val list = skillMap[id] ?: ArrayList().also { skillMap[id] = it } list.add (event) diff --git a/Server/src/main/content/global/ame/events/candlelight/CandlelightInterface.kt b/Server/src/main/content/global/ame/events/candlelight/CandlelightInterface.kt new file mode 100644 index 000000000..249f9f194 --- /dev/null +++ b/Server/src/main/content/global/ame/events/candlelight/CandlelightInterface.kt @@ -0,0 +1,164 @@ +package content.global.ame.events.candlelight + +import core.api.* +import core.api.utils.PlayerCamera +import core.game.interaction.InteractionListener +import core.game.interaction.InterfaceListener +import core.game.node.entity.Entity +import core.game.node.entity.player.Player +import core.game.world.map.Direction +import core.game.world.map.Location +import core.game.world.map.zone.ZoneBorders +import core.game.world.map.zone.ZoneRestriction +import org.rs09.consts.Scenery + +/** + * Candlelight Interface CANDLELIGHT_178 + * + */ +class CandlelightInterface : InterfaceListener, InteractionListener, MapArea { + companion object { + const val CANDLELIGHT_INTERFACE = 178 + const val CANDLELIGHT_RETURN_LOC = "/save:original-loc" + const val CANDLELIGHT_CANDLE_ARRAY = "/save:candlelight:candle-array" + const val CANDLELIGHT_CAMERA_AT = "candlelight:camera-at" + + val CANDLE_LOC_ARRAY = arrayOf( + Location(1967, 4997), + Location(1968, 4998), + Location(1967, 4999), + Location(1968, 5000), + Location(1967, 5001), + Location(1968, 5002), + Location(1967, 5003), + Location(1968, 5004), + Location(1967, 5005), + Location(1968, 5006), + Location(1967, 5007), + ) + + fun initCandlelight(player: Player) { + val candleArray = intArrayOf(0,0,0,0,0,0,2,2,2,2,2) + candleArray.shuffle() + setAttribute(player, CANDLELIGHT_CANDLE_ARRAY, candleArray) + for (candleIndex in 0..10) { + setVarbit(player, 1771 + candleIndex, candleArray[candleIndex]) + } + } + + fun areCandlesLit(player: Player): Boolean { + val candleArray = getAttribute(player, CANDLELIGHT_CANDLE_ARRAY, intArrayOf(0,0,0,0,0,0,0,0,0,0,0)) + for (candle in candleArray) { + if (candle == 0) { + return false + } + } + return true + } + + fun lightCandle(player: Player) { + var currentCamLoc = getAttribute(player, CANDLELIGHT_CAMERA_AT, Location(1968, 5002)) + val candleIndex = CANDLE_LOC_ARRAY.indexOf(currentCamLoc) + val varbit = candleIndex + 1771 // Essentially all varbits are 1771 .. 1881 + + if (candleIndex != -1) { + val candleArray = getAttribute(player, CANDLELIGHT_CANDLE_ARRAY, intArrayOf(0,0,0,0,0,0,0,0,0,0,0)) + if (candleArray[candleIndex] == 0) { + candleArray[candleIndex] = 1 + setAttribute(player, CANDLELIGHT_CANDLE_ARRAY, candleArray) + setVarbit(player, varbit, 1) + sendMessage(player, "You light the candle.") + } else if (candleArray[candleIndex] == 1) { + sendMessage(player, "This candle is already lit.") + } else { + sendMessage(player, "This candle is too short to light.") + } + } else { + sendMessage(player, "There is nothing to light here.") + } + } + + fun moveCamera(player: Player, direction: Direction, firstTime: Boolean = false) { + var currentCamLoc = getAttribute(player, CANDLELIGHT_CAMERA_AT, Location(1968, 5002)) + when(direction) { + Direction.NORTH -> currentCamLoc = currentCamLoc.transform(Direction.NORTH) + Direction.SOUTH -> currentCamLoc = currentCamLoc.transform(Direction.SOUTH) + Direction.EAST -> currentCamLoc = currentCamLoc.transform(Direction.EAST) + Direction.WEST -> currentCamLoc = currentCamLoc.transform(Direction.WEST) + else -> {} + } + if (currentCamLoc.x < 1967) { currentCamLoc.x = 1967 } + if (currentCamLoc.x > 1968) { currentCamLoc.x = 1968 } + if (currentCamLoc.y < 4997) { currentCamLoc.y = 4997 } + if (currentCamLoc.y > 5007) { currentCamLoc.y = 5007 } + setAttribute(player, CANDLELIGHT_CAMERA_AT, currentCamLoc) + PlayerCamera(player).rotateTo(currentCamLoc.x - 30, currentCamLoc.y,0,200) // height is kind of a relative value? + PlayerCamera(player).panTo(currentCamLoc.x + 2, currentCamLoc.y,350, if(firstTime) 400 else 10) + } + } + + override fun defineInterfaceListeners() { + on(CANDLELIGHT_INTERFACE){ player, component, opcode, buttonID, slot, itemID -> + when (buttonID) { + 1 -> moveCamera(player, Direction.WEST) + 2 -> moveCamera(player, Direction.EAST) + 3 -> lightCandle(player)/* Light */ + 4 -> moveCamera(player, Direction.SOUTH) + 5 -> moveCamera(player, Direction.NORTH) + 9 -> closeInterface(player) + } + return@on true + } + + onOpen(CANDLELIGHT_INTERFACE){ player, component -> + // Move camera + return@onOpen true + } + + onClose(CANDLELIGHT_INTERFACE){ player, component -> + PlayerCamera(player).reset() + // Reset camera + return@onClose true + } + } + + + override fun defineListeners() { + on((11364 .. 11394).toIntArray(), SCENERY, "light") { player, node -> + setAttribute(player, CANDLELIGHT_CAMERA_AT, Location(node.location.x, node.location.y)) + moveCamera(player, Direction.NORTH_WEST, true) + openInterface(player, CANDLELIGHT_INTERFACE) + return@on true + } + } + + override fun defineDestinationOverrides() { + setDest(SCENERY, (11364 .. 11394).toIntArray(),"light"){ player, node -> + return@setDest Location(1970, node.location.y) + } + } + + + override fun defineAreaBorders(): Array { + return arrayOf(ZoneBorders.forRegion(7758)) + } + + override fun getRestrictions(): Array { + return arrayOf(ZoneRestriction.RANDOM_EVENTS, ZoneRestriction.CANNON, ZoneRestriction.FOLLOWERS, ZoneRestriction.TELEPORT, ZoneRestriction.OFF_MAP) + } + + override fun areaEnter(entity: Entity) { + if (entity is Player) { + initCandlelight(entity) + entity.interfaceManager.removeTabs(0, 1, 2, 3, 4, 5, 6, 12) + } + } + + override fun areaLeave(entity: Entity, logout: Boolean) { + if (entity is Player) { + entity.interfaceManager.restoreTabs() + } + } + + +} \ No newline at end of file diff --git a/Server/src/main/content/global/ame/events/candlelight/PiousPeteDialogue.kt b/Server/src/main/content/global/ame/events/candlelight/PiousPeteDialogue.kt new file mode 100644 index 000000000..9eb9b7ede --- /dev/null +++ b/Server/src/main/content/global/ame/events/candlelight/PiousPeteDialogue.kt @@ -0,0 +1,94 @@ +package content.global.ame.events.candlelight + +import content.global.ame.RandomEvents +import content.global.ame.events.pillory.PilloryInterface +import content.global.ame.returnPlayer +import core.api.* +import core.game.dialogue.* +import core.game.interaction.QueueStrength +import core.game.node.entity.npc.NPC +import core.game.node.entity.player.Player +import core.game.world.map.Location +import core.game.world.update.flag.context.Graphics +import core.plugin.Initializable +import core.tools.END_DIALOGUE +import org.rs09.consts.Items +import org.rs09.consts.NPCs +import org.rs09.consts.Sounds + +// iface 178 + +@Initializable +class PiousPeteDialogue (player: Player? = null) : DialoguePlugin(player) { + override fun newInstance(player: Player): DialoguePlugin { + return PiousPeteDialogue(player) + } + override fun handle(interfaceId: Int, buttonId: Int): Boolean { + openDialogue(player, PiousPeteDialogueFile(), npc) + return false + } + override fun getIds(): IntArray { + return intArrayOf(NPCs.PIOUS_PETE_3207, NPCs._6564) + } +} + +class PiousPeteDialogueFile : DialogueLabeller() { + + override fun addConversation() { + npc(ChatAnim.THINKING, "Have you lit all the tall candles?") + exec { player, npc -> + if (CandlelightInterface.areCandlesLit(player)) { + loadLabel(player, "yeslit") + } else { + loadLabel(player, "nolit") + } + } + + label("nolit") + player(ChatAnim.HALF_GUILTY, "Sorry, not yet.") + npc(ChatAnim.SAD, "Please help me in lighting the candles. I just need you to light all the tall candles, but not the short ones.") + line("Click on the pillars to open an interface", "to move around and light the candles.") + + label("yeslit") + player(ChatAnim.FRIENDLY, "Yes, the tall ones are all lit.") + npc(ChatAnim.HAPPY, "Thank you my brother! I will now return you where you came from with a parting gift.") + npc(ChatAnim.FRIENDLY, "Take care brother!") + exec { player, npc -> + queueScript(player, 0, QueueStrength.SOFT) { stage: Int -> + when (stage) { + 0 -> { + lock(player, 6) + sendGraphics(Graphics(1576, 0, 0), player.location) + animate(player,8939) + playAudio(player, Sounds.TELEPORT_ALL_200) + return@queueScript delayScript(player, 3) + } + 1 -> { + returnPlayer(player) + sendGraphics(Graphics(1577, 0, 0), player.location) + animate(player,8941) + closeInterface(player) + return@queueScript delayScript(player, 3) + } + 2 -> { + val loot = RandomEvents.CERTER.loot!!.roll(player)[0] + addItemOrDrop(player, loot.id, loot.amount) + return@queueScript stopExecuting(player) + } + else -> return@queueScript stopExecuting(player) + } + } + } + } +} +class PiousPeteStartingDialogueFile : DialogueLabeller() { + + override fun addConversation() { + npc("I'm sorry to drag you away from your tasks, but I need a little help with something.") + player(ChatAnim.THINKING,"How can I help?") + npc("This is a chapel dedicated to our lord, Saradomin, and I'm tasked with maintaining this chapel.") + npc(ChatAnim.SAD,"My task is to light the chapel candles, but I couldn't reach them myself and I kept getting dazzled by the light whenever I tried.") + npc("So I need your help in lighting the candles. I need you to light all the tall candles, but not the short ones.") + npc(ChatAnim.FRIENDLY, "Once all the tall candles are all lit, come back and see me, and I will reward you for your work.") + } +} \ No newline at end of file diff --git a/Server/src/main/content/global/ame/events/candlelight/PiousPeteNPC.kt b/Server/src/main/content/global/ame/events/candlelight/PiousPeteNPC.kt new file mode 100644 index 000000000..70cf1e11c --- /dev/null +++ b/Server/src/main/content/global/ame/events/candlelight/PiousPeteNPC.kt @@ -0,0 +1,49 @@ +package content.global.ame.events.candlelight + +import content.global.ame.RandomEventNPC +import content.global.ame.kidnapPlayer +import core.api.* +import core.api.utils.WeightBasedTable +import core.game.interaction.QueueStrength +import core.game.node.entity.npc.NPC +import core.game.node.entity.player.link.TeleportManager +import core.game.world.map.Location +import core.game.world.update.flag.context.Graphics +import org.rs09.consts.NPCs +import org.rs09.consts.Sounds + +/** "::revent -p player_name -e candlelight" **/ +class PiousPeteNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.PRIEST_3206) { + + override fun init() { + super.init() + // Supposed to be "I'm sorry to drag you away from your tasks, but I need a little help with something." but it's too goddamn long. + sendChat("${player.username.capitalize()}! I need a little help with something.") + face(player) + queueScript(player, 4, QueueStrength.SOFT) { stage: Int -> + when (stage) { + 0 -> { + lock(player, 6) + sendGraphics(Graphics(1576, 0, 0), player.location) + animate(player,8939) + playAudio(player, Sounds.TELEPORT_ALL_200) + return@queueScript delayScript(player, 3) + } + 1 -> { + CandlelightInterface.initCandlelight(player) + kidnapPlayer(player, Location(1972, 5002, 0), TeleportManager.TeleportType.INSTANT) + // AntiMacro.terminateEventNpc(player) + sendGraphics(Graphics(1577, 0, 0), player.location) + animate(player,8941) + openDialogue(player, PiousPeteStartingDialogueFile(), NPC(NPCs.PIOUS_PETE_3207)) + return@queueScript stopExecuting(player) + } + else -> return@queueScript stopExecuting(player) + } + } + } + + override fun talkTo(npc: NPC) { + player.dialogueInterpreter.open(PiousPeteDialogueFile(),npc) + } +} \ No newline at end of file diff --git a/Server/src/main/core/ServerConstants.kt b/Server/src/main/core/ServerConstants.kt index 30a6ab377..d67997daf 100644 --- a/Server/src/main/core/ServerConstants.kt +++ b/Server/src/main/core/ServerConstants.kt @@ -318,6 +318,9 @@ class ServerConstants { @JvmField var NEW_PLAYER_ANNOUNCEMENT = true + @JvmField + var INAUTHENTIC_CANDLELIGHT_RANDOM = false + @JvmField var HOLIDAY_EVENT_RANDOMS = true diff --git a/Server/src/main/core/game/system/config/ServerConfigParser.kt b/Server/src/main/core/game/system/config/ServerConfigParser.kt index 69c660f44..72df173ff 100644 --- a/Server/src/main/core/game/system/config/ServerConfigParser.kt +++ b/Server/src/main/core/game/system/config/ServerConfigParser.kt @@ -160,6 +160,7 @@ object ServerConfigParser { ServerConstants.GRAFANA_TTL_DAYS = data.getLong("integrations.grafana_log_ttl_days", 7L).toInt() ServerConstants.BETTER_DFS = data.getBoolean("world.better_dfs", true) ServerConstants.NEW_PLAYER_ANNOUNCEMENT = data.getBoolean("world.new_player_announcement", true) + ServerConstants.INAUTHENTIC_CANDLELIGHT_RANDOM = data.getBoolean("world.inauthentic_candlelight_random", false) ServerConstants.HOLIDAY_EVENT_RANDOMS = data.getBoolean("world.holiday_event_randoms", true) ServerConstants.FORCE_HALLOWEEN_EVENTS = data.getBoolean("world.force_halloween_randoms", false) ServerConstants.FORCE_CHRISTMAS_EVENTS = data.getBoolean("world.force_christmas_randoms", false) diff --git a/Server/worldprops/default.conf b/Server/worldprops/default.conf index 6024160fe..511b7e9ce 100644 --- a/Server/worldprops/default.conf +++ b/Server/worldprops/default.conf @@ -99,6 +99,8 @@ better_agility_pyramid_gp = true better_dfs = true #new player announcement new_player_announcement = true +#enables inauthentic candlelight random event (adds an additional normal random event) +inauthentic_candlelight_random = true #enables holiday random events (no effect on normal random events) holiday_event_randoms = true #force holiday randoms (can only force one at a time)