diff --git a/Server/data/configs/item_configs.json b/Server/data/configs/item_configs.json index b928857e7..1c38971dc 100644 --- a/Server/data/configs/item_configs.json +++ b/Server/data/configs/item_configs.json @@ -4736,8 +4736,6 @@ "name": "Ghost's skull", "examine": "Ooooh spooky!", "archery_ticket_price": "0", - "destroy": "true", - "destroy_message": "If you get rid of the skull you'll have to search for it again.", "durability": null, "tradeable": "false" }, diff --git a/Server/src/main/content/region/misthalin/draynor/quest/anma/OldCroneDialogue.kt b/Server/src/main/content/region/misthalin/draynor/quest/anma/OldCroneDialogue.kt index 22a7a8bbd..46f47c201 100644 --- a/Server/src/main/content/region/misthalin/draynor/quest/anma/OldCroneDialogue.kt +++ b/Server/src/main/content/region/misthalin/draynor/quest/anma/OldCroneDialogue.kt @@ -30,15 +30,13 @@ class OldCroneDialogueFile : DialogueLabeller() { override fun addConversation() { - label("anma_entry") { - exec { player, npc -> - when (getQuestStage(player, Quests.ANIMAL_MAGNETISM)) { - 16, 17, 18 -> { - loadLabel(player, "about_the_farmers") - } - else -> { - loadLabel(player, "hello_old") - } + exec { player, npc -> + when (getQuestStage(player, Quests.ANIMAL_MAGNETISM)) { + 16, 17, 18 -> { + loadLabel(player, "about_the_farmers") + } + else -> { + loadLabel(player, "hello_old") } } } diff --git a/Server/src/main/content/region/misthalin/lumbridge/dialogue/FatherAereckDefaultDialogue.kt b/Server/src/main/content/region/misthalin/lumbridge/dialogue/FatherAereckDefaultDialogue.kt index cc2b813af..902514bf1 100644 --- a/Server/src/main/content/region/misthalin/lumbridge/dialogue/FatherAereckDefaultDialogue.kt +++ b/Server/src/main/content/region/misthalin/lumbridge/dialogue/FatherAereckDefaultDialogue.kt @@ -32,22 +32,21 @@ class FatherAereckDefaultDialogue : InteractionListener { class FatherAereckDefaultDialogueFile : DialogueLabeller() { override fun addConversation() { - label("entry_logic") - //allows skipping the main dialogue while Restless Ghost quest is started - exec { player, npc -> - when (getQuestStage(player, Quests.THE_RESTLESS_GHOST)) { - 0 -> { - loadLabel(player, "main_entry_transcript") - } - 10, 20, 30, 40 -> { - //passthrough for mid-quest dialogue skip - open(player, FatherAereckQuestDialogueFile(), npc) - } - else -> { - loadLabel(player, "main_entry_transcript") - } + //allows skipping the main dialogue while Restless Ghost quest is started + exec { player, npc -> + when (getQuestStage(player, Quests.THE_RESTLESS_GHOST)) { + 0 -> { + loadLabel(player, "main_entry_transcript") + } + 10, 20, 30, 40 -> { + //passthrough for mid-quest dialogue skip + open(player, FatherAereckQuestDialogueFile(), npc) + } + else -> { + loadLabel(player, "main_entry_transcript") } } + } label("main_entry_transcript") { npc("Welcome to the church of holy Saradomin.") diff --git a/Server/src/main/content/region/misthalin/lumbridge/dialogue/FatherUrhneyDefaultDialogue.kt b/Server/src/main/content/region/misthalin/lumbridge/dialogue/FatherUrhneyDefaultDialogue.kt index ecd83b018..bbc6ac05f 100644 --- a/Server/src/main/content/region/misthalin/lumbridge/dialogue/FatherUrhneyDefaultDialogue.kt +++ b/Server/src/main/content/region/misthalin/lumbridge/dialogue/FatherUrhneyDefaultDialogue.kt @@ -33,18 +33,16 @@ class FatherUrhneyDefaultDialogueFile: DialogueLabeller() { npc(FacialExpression.ANGRY, "Go away! I'm meditating!"); - label("main_opts") { - exec {player, npc -> - when (getQuestStage(player, Quests.THE_RESTLESS_GHOST)) { - 0 -> { - loadLabel(player, "pre_quest_opts") - } - 10 -> { - loadLabel(player, "mid_quest_opts") - } - else -> { - loadLabel(player, "post_quest_opts") - } + exec { player, npc -> + when (getQuestStage(player, Quests.THE_RESTLESS_GHOST)) { + 0 -> { + loadLabel(player, "pre_quest_opts") + } + 10 -> { + loadLabel(player, "mid_quest_opts") + } + else -> { + loadLabel(player, "post_quest_opts") } } } diff --git a/Server/src/main/content/region/misthalin/lumbridge/quest/therestlessghost/FatherAereckQuestDialogueFile.kt b/Server/src/main/content/region/misthalin/lumbridge/quest/therestlessghost/FatherAereckQuestDialogueFile.kt index 7c2e43828..21a963614 100644 --- a/Server/src/main/content/region/misthalin/lumbridge/quest/therestlessghost/FatherAereckQuestDialogueFile.kt +++ b/Server/src/main/content/region/misthalin/lumbridge/quest/therestlessghost/FatherAereckQuestDialogueFile.kt @@ -3,6 +3,7 @@ package content.region.misthalin.lumbridge.quest.therestlessghost; import content.data.Quests import core.api.getQuestStage import core.api.setQuestStage +import core.api.setVarbit import core.game.dialogue.DialogueLabeller import core.game.dialogue.DialogueOption import core.game.dialogue.FacialExpression @@ -63,6 +64,9 @@ class FatherAereckQuestDialogueFile : DialogueLabeller() { label("let_me_help") { exec { player, npc -> setQuestStage(player, Quests.THE_RESTLESS_GHOST, 10) + //ensures the varbits is set to default state + setVarbit(player, 2128, 0, true) + setVarbit(player, 2130, 0, true) } npc("Thank you. The problem is, there is a ghost in the", "church graveyard. I would like you to get rid of it.") diff --git a/Server/src/main/content/region/misthalin/lumbridge/quest/therestlessghost/RestlessGhost.kt b/Server/src/main/content/region/misthalin/lumbridge/quest/therestlessghost/RestlessGhost.kt index a0bc51016..05af5aeb0 100644 --- a/Server/src/main/content/region/misthalin/lumbridge/quest/therestlessghost/RestlessGhost.kt +++ b/Server/src/main/content/region/misthalin/lumbridge/quest/therestlessghost/RestlessGhost.kt @@ -92,6 +92,11 @@ class RestlessGhost : Quest(Quests.THE_RESTLESS_GHOST, 25, 24, 1, 107, 0, 4, 5) player.interfaceManager.closeChatbox() player.packetDispatch.sendString("You have completed The Restless Ghost Quest!", 277, 2 + 2) - setVarp(player, 728, 31, true) + + //post quest skeleton scenery and altar visually correct + setVarbit(player, 2128, 1, true) + setVarbit(player, 2130, 1, true) + + //setVarp(player, 728, 31, true) } } \ No newline at end of file diff --git a/Server/src/main/content/region/misthalin/lumbridge/quest/therestlessghost/RestlessGhostListeners.kt b/Server/src/main/content/region/misthalin/lumbridge/quest/therestlessghost/RestlessGhostListeners.kt index 30ad706c0..3647f6253 100644 --- a/Server/src/main/content/region/misthalin/lumbridge/quest/therestlessghost/RestlessGhostListeners.kt +++ b/Server/src/main/content/region/misthalin/lumbridge/quest/therestlessghost/RestlessGhostListeners.kt @@ -2,6 +2,7 @@ package content.region.misthalin.lumbridge.quest.therestlessghost; import content.data.Quests import core.api.* +import core.game.global.action.DropListener import core.game.interaction.IntType import core.game.interaction.InteractionListener import core.game.node.entity.Entity @@ -9,6 +10,7 @@ import core.game.node.entity.combat.CombatStyle import core.game.node.entity.npc.NPC import core.game.node.entity.player.Player import core.game.node.scenery.SceneryBuilder +import core.game.system.task.Pulse import core.game.world.map.Direction import core.game.world.map.Location import core.game.world.map.RegionManager @@ -22,17 +24,20 @@ import org.rs09.consts.Sounds /** * Authenticity source Aug 18 2009 * https://www.youtube.com/watch?v=ikbX12Xywxs +* https://www.youtube.com/watch?v=gC3qR9tKJMI * * Author Beck, Vexia **/ class RestlessGhostListeners : InteractionListener { companion object { - //This is not in the Animations consts + //This is not in the Animations consts, added in Constlib MR !22 private const val Animations_HUMAN_CLOSE_CHEST_535 = 535 private const val CLOSED_COFFIN = Scenery.COFFIN_2145 private const val INCOMPLETE_COFFIN_OPEN = Scenery.COFFIN_15052 private const val COMPLETE_COFFIN_OPEN = Scenery.COFFIN_15053 + private const val ALTAR_WITH_SKULL = Scenery.ALTAR_15050 + private const val ALTAR_NO_SKULL = Scenery.ALTAR_15051 private fun createRestlessGhostNPC() : NPC { val restlessGhostNPC = NPC(NPCs.RESTLESS_GHOST_457, Location(3250, 3195, 0)) @@ -45,14 +50,26 @@ class RestlessGhostListeners : InteractionListener { return restlessGhostNPC } - //removes the skeleton on ground, resets in ~2mins - private fun animSkeleAlive(player: Player, skeleScenery: core.game.node.scenery.Scenery) { - - // TODO: find animation and maybe sfx of the skeleton coming alive, from a still scenery of a skeleton slumped on the ground against the wall and then rises to life - - queueScript(player, 4) {_ -> - SceneryBuilder.remove(skeleScenery, 200) - return@queueScript stopExecuting(player) + //Scenery 15057 changes to 15060 hidden and plays animation, resets in ~2mins if player still doing quest, otherwise it stays at 15060 forever + private fun animSkeleAlive(player: Player) { + + //set scenery to 15060 which hides the ground skeleton + setVarbit(player, 2128, 1, true) + + // TODO: Scenery skeleton id 15057 turns into a hidden 15060 then with an animation, uses varbit 2128, client side only + // TODO: find animation and maybe sfx of the skeleton coming alive, from a still scenery 15057 (15060 is the post animation?) of a skeleton slumped on the ground against the wall and then rises to life + // TODO: convert to queuescript on Scenery objects when engine is capable to be attached to them. + // https://www.youtube.com/watch?v=gC3qR9tKJMI + + // Use world pulse in the mean time, in the edge case where a player logs off in middle of the script + if (getQuestStage(player, Quests.THE_RESTLESS_GHOST) in 30..40) { + submitWorldPulse(object : Pulse(200) { + override fun pulse(): Boolean { + //resets the skeleton on the ground + setVarbit(player, 2128, 0, true) + return true + } + }) } } @@ -106,8 +123,8 @@ class RestlessGhostListeners : InteractionListener { toggleCoffinSceneryObj(player, node as core.game.node.scenery.Scenery) if (!isQuestComplete(player, Quests.THE_RESTLESS_GHOST)) { - //is this from the center of the scenery/node object? val ghostExists = RegionManager.getLocalNPCs(node.centerLocation).find { it.id == NPCs.RESTLESS_GHOST_457 } + //val ghostExists = RegionManager.getLocalNpcs(node.centerLocation).find { it.id == NPCs.RESTLESS_GHOST_457 } //not within rendering distance or doesn't exist at all if (ghostExists == null) { @@ -115,11 +132,21 @@ class RestlessGhostListeners : InteractionListener { val ghost = createRestlessGhostNPC() //despawn ghost after awhile and shut the coffin - queueScript(player, 200) { _ -> + // TODO: convert to queuescript on Scenery objects when engine is capable to be attached to them. + // Use world pulse in the mean time, in the edge case where a player logs off in middle of the script + /* queueScript(player, 200) { _ -> ghost.clear() toggleCoffinSceneryObj(player, node) return@queueScript stopExecuting(player) - } + } */ + + submitWorldPulse(object : Pulse(200) { + override fun pulse(): Boolean { + ghost.clear() + toggleCoffinSceneryObj(player, node) + return true + } + }) } } @@ -166,42 +193,88 @@ class RestlessGhostListeners : InteractionListener { with as core.game.node.scenery.Scenery SceneryBuilder.replace(with, with.transform(COMPLETE_COFFIN_OPEN)) - } return@onUseWith true } - on(Scenery.ALTAR_15050, IntType.SCENERY, "search") { player, node -> + on(ALTAR_WITH_SKULL, IntType.SCENERY, "search") { player, node -> - if (!inInventory(player, Items.GHOSTS_SKULL_553)) { + if (!inInventory(player, Items.GHOSTS_SKULL_553) && !inBank(player, Items.GHOSTS_SKULL_553)) { if (getQuestStage(player, Quests.THE_RESTLESS_GHOST) !in 30..40) { sendMessage(player, "You search the altar and find nothing.") } else { if (freeSlots(player) >= 1) { if (addItem(player, Items.GHOSTS_SKULL_553)) { setQuestStage(player, Quests.THE_RESTLESS_GHOST, 40) - sendMessage(player, "The skeleton in the corner suddenly comes to life!") - //skele comes to live from scenery 15057 with an animation, - //but idk how to select it to at least remove/hide it from the world briefly - //animSkeleAlive(player, node as core.game.node.scenery.Scenery) - - //spawn in skeleton - val s = createLevel13SkeletonNPC(player) + //update altar to without the skull, altar is now scenery 15051 + setVarbit(player, 2130, 1, true) + + //if skeleton scenery is visible such first time coming alive + //so that it can only be killed/spawned to attack once to prevent some sort of griefing exploit + if (getVarbit(player, 2128) == 0) { + sendMessage(player, "The skeleton in the corner suddenly comes to life!") - // despawn after awhile if it never dies - // so there isnt a group of them for next visitor lol - queueScript(player, 200) { _ -> - s.clear() - return@queueScript stopExecuting(player) + animSkeleAlive(player) + + //spawn in skeleton + val s = createLevel13SkeletonNPC(player) + + // despawn after awhile if it never dies so there isnt a group of them for next visitor lol + + // TODO: convert to queuescript on Scenery objects when engine is capable to be attached to them. + // Use world pulse in the mean time, in the edge case where a player logs off in middle of the script + + /* queueScript(player, 200) { _ -> + s.clear() + return@queueScript stopExecuting(player) + } */ + + submitWorldPulse(object : Pulse(200) { + override fun pulse(): Boolean { + s.clear() + return true + } + }) } } + } else { + sendMessage(player, "You don't have enough inventory space.") } } } return@on true } + + on(ALTAR_NO_SKULL, IntType.SCENERY, "search") { player, node -> + //Mainly for a weird edge case if some how the varbit wasn't set correctly + if (getQuestStage(player, Quests.THE_RESTLESS_GHOST) !in 30..40) { + sendMessage(player, "You search the altar and find nothing.") + } else { + if (!inInventory(player, Items.GHOSTS_SKULL_553) && !inBank(player, Items.GHOSTS_SKULL_553)) { + //guard clause if for when player does the drop trick, etc + if (!addItem(player, Items.GHOSTS_SKULL_553)) { + sendMessage(player, "You don't have enough inventory space.") + } + } else { + // TODO: Authenticity check needed for exact message + sendMessage(player, "You already have the Ghost's Skull!") + } + } + return@on true + } + + on(Items.GHOSTS_SKULL_553, IntType.ITEM, "drop") { player, node -> + DropListener.drop(player, node.asItem()) + + if (getQuestStage(player, Quests.THE_RESTLESS_GHOST) in 30..40) { + //update altar to one with the skull, altar is now scenery 15060 + setVarbit(player, 2130, 0, true) + } + + return@on true + } } } \ No newline at end of file