From 60ce5a2390b2991ac5b3528083a36c4ff900b56d Mon Sep 17 00:00:00 2001 From: aidan Date: Fri, 30 Jan 2026 12:28:39 -0600 Subject: [PATCH] DONE --- .../quest/elementalworkshop/EWListeners.kt | 159 +++-- .../seers/quest/elementalworkshop/EWZone.kt | 52 ++ .../quest/elementalworkshop2/EW2Listeners.kt | 541 +++++++++++++++--- .../seers/quest/elementalworkshop2/EW2Zone.kt | 20 + .../elementalworkshop2/ElementalWorkshop2.kt | 167 ++++-- .../JunctionBoxInterface.kt | 3 + 6 files changed, 746 insertions(+), 196 deletions(-) create mode 100644 Server/src/main/content/region/kandarin/seers/quest/elementalworkshop/EWZone.kt diff --git a/Server/src/main/content/region/kandarin/seers/quest/elementalworkshop/EWListeners.kt b/Server/src/main/content/region/kandarin/seers/quest/elementalworkshop/EWListeners.kt index 91eb22bb0..d6d9660cd 100644 --- a/Server/src/main/content/region/kandarin/seers/quest/elementalworkshop/EWListeners.kt +++ b/Server/src/main/content/region/kandarin/seers/quest/elementalworkshop/EWListeners.kt @@ -17,6 +17,7 @@ import core.game.interaction.InteractionListener import core.game.interaction.IntType import core.tools.Log import content.data.Quests +import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.EW2StageVarbit /** * Listeners for the Elemental Workshop I quest @@ -261,7 +262,7 @@ class EWListeners : InteractionListener { // Smithing an elemental shield will complete EW1. // During EW2 you have the option to make an elemental shield, claw, or helm from an elemental bar. // Smithing an elemental mind helm from an elemental mind bar will complete EW2. - onUseWith(IntType.SCENERY, Items.ELEMENTAL_METAL_2893, Items.ELEMENTAL_MIND_BAR_9728, Scenery.WORKBENCH_3402) { player, used, workbench -> + onUseWith(IntType.SCENERY, intArrayOf(Items.ELEMENTAL_METAL_2893, Items.ELEMENTAL_MIND_BAR_9728), Scenery.WORKBENCH_3402) { player, used, workbench -> when(used.id) { Items.ELEMENTAL_METAL_2893 -> { @@ -354,7 +355,7 @@ class EWListeners : InteractionListener { } } - // EW1 fallback + // EW1 fallback } else { // Warn player their smithing level is too low to make the shield if (player.skills.getLevel(Skills.SMITHING) < 20) { @@ -392,66 +393,101 @@ class EWListeners : InteractionListener { } } } - Items.ELEMENTAL_MIND_BAR_9728 -> { - sendDialogueOptions(player, "Would you like to make...", "An elemental mine shield.", "An elemental mind helm.") - addDialogueAction(player) { _, buttonId -> - when (buttonId) { - 2 -> { // ele mind shield - // Warn player their smithing level is too low to make the shield - if (player.skills.getLevel(Skills.SMITHING) < 30) { - sendMessage(player, "You need a smithing level of 30 to create an elemental shield.") - return@addDialogueAction - } - // Warn player they don't have the required book in their inventory - if (!player.inventory.containsAtLeastOneItem(intArrayOf(Items.BEATEN_BOOK_9717))) { - sendDialogue(player, "This workbench is too complicated. You need instructions to follow.") - return@addDialogueAction - } - // Warn player they don't have a hammer in their inventory - if (!inInventory(player, Items.HAMMER_2347)) { - sendDialogue(player, "You don't have a tool available to shape the metal.") - return@addDialogueAction - } - // Successfully smith the elemental mind shield - lock(player, (animationDuration(smithElementalShield) + 2)) - runTask(player) { - face(player, workbench) - animate(player, smithElementalShield) - playAudio(player, smithElementalShieldSFX) - replaceSlot(player, used.asItem().slot, Item(Items.MIND_SHIELD_9731)) - rewardXP(player, Skills.SMITHING, 30.0) - sendMessage(player, "Following the instructions in the book you make an elemental mind shield.") - } - } - 3 -> { // ele mind helm - // Warn player their smithing level is too low to make the helm - if (player.skills.getLevel(Skills.SMITHING) < 30) { - sendMessage(player, "You need a smithing level of 30 to create an elemental mind helm.") - return@addDialogueAction - } - // Warn player they don't have the required book in their inventory - if (!player.inventory.containsAtLeastOneItem(intArrayOf(Items.BEATEN_BOOK_9717))) { - sendDialogue(player, "This workbench is too complicated. You need instructions to follow.") - return@addDialogueAction - } - // Warn player they don't have a hammer in their inventory - if (!inInventory(player, Items.HAMMER_2347)) { - sendDialogue(player, "You don't have a tool available to shape the metal.") - return@addDialogueAction - } - // Successfully smith the elemental helm - lock(player, (animationDuration(smithElementalShield) + 2)) - runTask(player) { - face(player, workbench) - animate(player, smithElementalShield) - playAudio(player, smithElementalShieldSFX) - replaceSlot(player, used.asItem().slot, Item(Items.MIND_HELMET_9733)) - rewardXP(player, Skills.SMITHING, 30.0) - sendMessage(player, "Following the instructions in the book you make an elemental mind helm.") - // complete quest if it's not done. - if (!isQuestComplete(player, Quests.ELEMENTAL_WORKSHOP_II)) { - finishQuest(player, Quests.ELEMENTAL_WORKSHOP_II) + Items.ELEMENTAL_MIND_BAR_9728 -> { + // if EW2 is not complete, the player makes a mind helmet. after the quest, you have a choice. + if(!isQuestComplete(player, Quests.ELEMENTAL_WORKSHOP_II)) { + // Warn player their smithing level is too low to make the helm + if (player.skills.getLevel(Skills.SMITHING) < 30) { + sendMessage(player, "You need a smithing level of 30 to create an elemental mind helm.") + return@onUseWith true + } + // Warn player they don't have the required book in their inventory + if (!player.inventory.containsAtLeastOneItem(intArrayOf(Items.BEATEN_BOOK_9717))) { + sendDialogue(player, "This workbench is too complicated. You need instructions to follow.") + return@onUseWith true + } + // Warn player they don't have a hammer in their inventory + if (!inInventory(player, Items.HAMMER_2347)) { + sendDialogue(player, "You don't have a tool available to shape the metal.") + return@onUseWith true + } + // Successfully smith the elemental helm and complete quest + lock(player, (animationDuration(smithElementalShield) + 2)) + runTask(player) { + face(player, workbench) + animate(player, smithElementalShield) + playAudio(player, smithElementalShieldSFX) + replaceSlot(player, used.asItem().slot, Item(Items.MIND_HELMET_9733)) + rewardXP(player, Skills.SMITHING, 30.0) + sendMessage(player, "Following the instructions in the book you make an elemental mind helm.") + + if(getQuestStage(player, Quests.ELEMENTAL_WORKSHOP_II) <= 10) { + setQuestStage(player, Quests.ELEMENTAL_WORKSHOP_II, 11) + setVarbit(player, EW2StageVarbit, 11, true) + } + // complete quest if it's not done. + if (!isQuestComplete(player, Quests.ELEMENTAL_WORKSHOP_II)) { + finishQuest(player, Quests.ELEMENTAL_WORKSHOP_II) + } + } + // choice to make helmet or shield + } else { + sendDialogueOptions(player, "Would you like to make...", "An elemental mind shield.", "An elemental mind helm.") + addDialogueAction(player) { _, buttonId -> + when (buttonId) { + 2 -> { // ele mind shield + // Warn player their smithing level is too low to make the shield + if (player.skills.getLevel(Skills.SMITHING) < 30) { + sendMessage(player, "You need a smithing level of 30 to create an elemental mind shield.") + return@addDialogueAction + } + // Warn player they don't have the required book in their inventory + if (!player.inventory.containsAtLeastOneItem(intArrayOf(Items.BEATEN_BOOK_9717))) { + sendDialogue(player, "This workbench is too complicated. You need instructions to follow.") + return@addDialogueAction + } + // Warn player they don't have a hammer in their inventory + if (!inInventory(player, Items.HAMMER_2347)) { + sendDialogue(player, "You don't have a tool available to shape the metal.") + return@addDialogueAction + } + // Successfully smith the elemental mind shield + lock(player, (animationDuration(smithElementalShield) + 2)) + runTask(player) { + face(player, workbench) + animate(player, smithElementalShield) + playAudio(player, smithElementalShieldSFX) + replaceSlot(player, used.asItem().slot, Item(Items.MIND_SHIELD_9731)) + rewardXP(player, Skills.SMITHING, 30.0) + sendMessage(player, "Following the instructions in the book you make an elemental mind shield.") + } + } + 3 -> { // ele mind helm + // Warn player their smithing level is too low to make the helm + if (player.skills.getLevel(Skills.SMITHING) < 30) { + sendMessage(player, "You need a smithing level of 30 to create an elemental mind helm.") + return@addDialogueAction + } + // Warn player they don't have the required book in their inventory + if (!player.inventory.containsAtLeastOneItem(intArrayOf(Items.BEATEN_BOOK_9717))) { + sendDialogue(player, "This workbench is too complicated. You need instructions to follow.") + return@addDialogueAction + } + // Warn player they don't have a hammer in their inventory + if (!inInventory(player, Items.HAMMER_2347)) { + sendDialogue(player, "You don't have a tool available to shape the metal.") + return@addDialogueAction + } + // Successfully smith the elemental helm + lock(player, (animationDuration(smithElementalShield) + 2)) + runTask(player) { + face(player, workbench) + animate(player, smithElementalShield) + playAudio(player, smithElementalShieldSFX) + replaceSlot(player, used.asItem().slot, Item(Items.MIND_HELMET_9733)) + rewardXP(player, Skills.SMITHING, 30.0) + sendMessage(player, "Following the instructions in the book you make an elemental mind helm.") } } } @@ -459,7 +495,6 @@ class EWListeners : InteractionListener { } } } - return@onUseWith true } diff --git a/Server/src/main/content/region/kandarin/seers/quest/elementalworkshop/EWZone.kt b/Server/src/main/content/region/kandarin/seers/quest/elementalworkshop/EWZone.kt new file mode 100644 index 000000000..ac0b84f0b --- /dev/null +++ b/Server/src/main/content/region/kandarin/seers/quest/elementalworkshop/EWZone.kt @@ -0,0 +1,52 @@ +package content.region.kandarin.seers.quest.elementalworkshop + +import content.data.Quests +import content.region.kandarin.seers.quest.elementalworkshop.EWUtils.BELLOWS_STATE +import content.region.kandarin.seers.quest.elementalworkshop.EWUtils.FURNACE_STATE +import content.region.kandarin.seers.quest.elementalworkshop.EWUtils.LEFT_WATER_CONTROL_STATE +import content.region.kandarin.seers.quest.elementalworkshop.EWUtils.RIGHT_WATER_CONTROL_STATE +import content.region.kandarin.seers.quest.elementalworkshop.EWUtils.WATER_WHEEL_STATE +import core.api.* +import core.game.node.entity.Entity +import core.game.node.entity.player.Player +import core.plugin.Initializable +import core.game.world.map.zone.MapZone +import core.game.world.map.zone.ZoneBorders +import core.game.world.map.zone.ZoneBuilder +import core.plugin.Plugin + +/** + * This updates the Elemental Workshop I state whenever the player enters, if the quest is complete. + * Workshop should maintain state per this video: https://www.youtube.com/watch?v=YKSWisRgGZk + */ + +@Initializable +class EWZone : MapZone("Elemental Workshop I", true), Plugin { + + override fun newInstance(arg: Any?): EWZone { + ZoneBuilder.configure(this) + return this + } + + override fun configure() { + super.register(ZoneBorders(2688,9862,2744,9920)) + } + + // updates the workshop state based on the varbits for Elemental Workshop II + override fun enter(e: Entity?): Boolean { + if(e is Player) { + if(isQuestComplete(e, Quests.ELEMENTAL_WORKSHOP_I)) { + setVarbit(e, LEFT_WATER_CONTROL_STATE, 1) + setVarbit(e, RIGHT_WATER_CONTROL_STATE, 1) + setVarbit(e, WATER_WHEEL_STATE, 1) + setVarbit(e, FURNACE_STATE, 1) + setVarbit(e, BELLOWS_STATE, 1) + } + } + return super.enter(e) + } + + override fun fireEvent(identifier: String?, vararg args: Any?): Any { + return Unit + } +} \ No newline at end of file diff --git a/Server/src/main/content/region/kandarin/seers/quest/elementalworkshop2/EW2Listeners.kt b/Server/src/main/content/region/kandarin/seers/quest/elementalworkshop2/EW2Listeners.kt index 3a5832ae8..432aba94f 100644 --- a/Server/src/main/content/region/kandarin/seers/quest/elementalworkshop2/EW2Listeners.kt +++ b/Server/src/main/content/region/kandarin/seers/quest/elementalworkshop2/EW2Listeners.kt @@ -1,36 +1,57 @@ package content.region.kandarin.seers.quest.elementalworkshop2 import content.data.Quests +import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.EW2AllCogsVarbit import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.EW2CartLeverVarbit import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.EW2CogVarbit1 import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.EW2CogVarbit2 import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.EW2CogVarbit3 import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.EW2CranePosVarbit import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.EW2CraneStateVarbit -import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.EW2DoorLeverVarbit +import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.EW2TankDoorStatusVarbit import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.EW2ExtractorGun import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.EW2FanLeverVarbit +import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.EW2FanStateVarbit import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.EW2HatchVarbit import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.EW2JigCartVarbit import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.EW2MachineryVarbit import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.EW2PipeVarbit import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.EW2StageVarbit -import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.EW2TankDoorVarbit +import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.EW2TankDoorStateVarbit +import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.EW2ValveEastVarbit +import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.EW2ValveWestVarbit +import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.attrDipped +import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.attrFlattened +import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.attrJigged +import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.attrWatered +import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.attrWinded +import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.badHat +import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.eHelmEquip +import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.eShieldEquip +import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.goodHat +import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.mHelmEquip +import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.mShieldEquip +import core.game.world.update.flag.context.Graphics import core.api.* import core.game.interaction.IntType import core.game.interaction.InteractionListener -import core.game.node.entity.impl.WalkingQueue import core.game.node.entity.npc.NPC import core.game.node.entity.player.Player import core.game.node.entity.skill.Skills -import core.game.system.task.Pulse +import core.game.node.scenery.SceneryBuilder import core.game.world.map.Location import core.game.world.map.RegionManager -import core.game.world.map.path.Pathfinder import org.rs09.consts.* class EW2Listeners : InteractionListener { + // values from 530_synth_debug_names.txt that are still unused + //val ew2_dial_spin = 2326 + //val ew2_ambient_loop = 3149 + //val ew2_machine_loop = 3150 + + // gfx 809 mind shield equip, 810 mind helmet equip + /** * Quest structure and testing notes: * @@ -73,7 +94,7 @@ class EW2Listeners : InteractionListener { Scenery.OLD_CRANE_18636, // broken crane facing north, claw down Scenery.OLD_CRANE_18635, // broken crane facing north, claw up - // Varbit 2644 = 1: Fixed/Empty (18623=N-Up, 18624=N-Down, 18625=S-Up, 18626=S-Down) + // Varbit 2644 = 1: Fixed/Empty Scenery.OLD_CRANE_18626, // fixed crane facing south, claw down Scenery.OLD_CRANE_18625, // fixed crane facing south, claw up Scenery.OLD_CRANE_18624, // fixed crane facing north, claw down @@ -85,21 +106,21 @@ class EW2Listeners : InteractionListener { Scenery.OLD_CRANE_18628, // fixed crane with ele bar facing north, claw down Scenery.OLD_CRANE_18627, // fixed crane with ele bar facing north, claw up - // Varbit 2644 = 3: Mind Bar - Scenery.OLD_CRANE_18634, // fixed crane with mind bar facing south, claw down - Scenery.OLD_CRANE_18633, // fixed crane with mind bar facing south, claw up - Scenery.OLD_CRANE_18632, // fixed crane with mind bar facing north, claw down - Scenery.OLD_CRANE_18631 // fixed crane with mind bar facing north, claw up + // Varbit 2644 = 3: Hot Bar + Scenery.OLD_CRANE_18634, // fixed crane with hot bar facing south, claw down + Scenery.OLD_CRANE_18633, // fixed crane with hot bar facing south, claw up + Scenery.OLD_CRANE_18632, // fixed crane with hot bar facing north, claw down + Scenery.OLD_CRANE_18631 // fixed crane with hot bar facing north, claw up ) // cart state is stored in varbit 2643 val jigCartStates = intArrayOf( - NPCs.JIG_CART_4913, // empty - NPCs.JIG_CART_4914, // ele bar - NPCs.JIG_CART_4915, // hot ele bar - NPCs.JIG_CART_4916, // smashed hot bar - NPCs.JIG_CART_4917, // smashed ele bar - NPCs.JIG_CART_4918, // smashed white bar + NPCs.JIG_CART_4913, // 0 empty + NPCs.JIG_CART_4914, // 1 ele bar + NPCs.JIG_CART_4915, // 2 hot ele bar + NPCs.JIG_CART_4916, // 3 smashed hot bar + NPCs.JIG_CART_4917, // 4 smashed cooled bar + NPCs.JIG_CART_4918, // 5 primed bar ) // locations the jig cart can be at @@ -110,21 +131,27 @@ class EW2Listeners : InteractionListener { Location.create(1961, 5155, 2) // east (fans) ) - // tank door states are currently not updated due to Arios. + // tank door states stored in varbit 2653 val tankDoorStates = intArrayOf( - Scenery.DOOR_18651, // door closed - Scenery.DOOR_18652, - Scenery.DOOR_18653, - Scenery.DOOR_18654, - Scenery.DOOR_18655, - Scenery.DOOR_18656, - Scenery.DOOR_18657, - Scenery.DOOR_18658, - Scenery.DOOR_18659 + Scenery.DOOR_18651, // 0 door closed + Scenery.DOOR_18652, // 1 door opened, grabber inside + Scenery.DOOR_18653, // 2 door opened, grabber out + Scenery.DOOR_18654, // 3 door closed, hot bar inside + Scenery.DOOR_18655, // 4 door opened, hot bar inside + Scenery.DOOR_18656, // 5 door opened, hot bar out + Scenery.DOOR_18657, // 6 door closed, cooled bar inside + Scenery.DOOR_18658, // 7 door opened, cooled bar inside + Scenery.DOOR_18659 // 8 door opened, cooled bar out + ) + + // steam press scenery. right now I just use the third one to make the hammer appear + val steamPressStates = intArrayOf( + Scenery.STEAM_PRESS_18643, // top of the steam press + Scenery.STEAM_PRESS_18644, // press with ele bar cart + Scenery.STEAM_PRESS_18645 // press with nothing under it ) // position the crane based on varbit states - // todo it would be nice to animate this crane fun syncCrane(player: Player) { val mat = getVarbit(player, EW2CraneStateVarbit) val pos = getVarbit(player, EW2CranePosVarbit) @@ -141,8 +168,18 @@ class EW2Listeners : InteractionListener { if (craneStates.contains(currentObject.id)) { // replace crane if current state doesn't match what is called for + // todo it would be nice to animate this crane if (currentObject.id != newId) { replaceScenery(currentObject, newId, -1) + playAudio(player, Sounds.EW2_CRANE_TURN_3170) + //playAudio(player, Sounds.EW2_CRANE_LOWER_3169) + + // if bar is hot set attr for quest log + if(newId == 18634) { + if(!getAttribute(player, attrDipped, false) && getQuestStage(player, Quests.ELEMENTAL_WORKSHOP_II) <= 6) { + setAttribute(player, attrDipped, true) + } + } } } } @@ -154,6 +191,7 @@ class EW2Listeners : InteractionListener { val cartPosIndex = getVarbit(player, EW2CartLeverVarbit) // cart moving lever. 0 = start (south), 1 = west, 2 = north, 3 = east val targetId = jigCartStates[cartState] val targetLocation = jigCartLocations[cartPosIndex] + val tankState = getVarbit(player, EW2TankDoorStateVarbit) // if tank state is 3, 4, 6, 7 the cart is inside the tank and should be removed. // find cart val trackCenter = Location.create(1953, 5155, 2) @@ -163,15 +201,23 @@ class EW2Listeners : InteractionListener { if (existingCart.id != targetId) { existingCart.transform(targetId) } - // failsafe to reset the cart where it's supposed to be + // failsafe to reset the cart where it's supposed to be. right now cart just teleports so this shouldn't trigger if (!existingCart.walkingQueue.isMoving && existingCart.location != targetLocation) { existingCart.teleport(targetLocation) } + // if cart is inside water tank, clear it + if (tankState == 3 || tankState == 4 || tankState == 6 || tankState == 7) { + existingCart.clear() + } - // if there is no cart, spawn a new one (like if this is the quest start) + // if there is no cart, spawn a new one (like if player is just logging in) } else { val newCart = NPC(targetId, targetLocation) newCart.init() + // if cart is inside water tank, clear it + if (tankState == 3 || tankState == 4 || tankState == 6 || tankState == 7) { + newCart.clear() + } } } @@ -181,20 +227,76 @@ class EW2Listeners : InteractionListener { val medCogs = intArrayOf(Scenery.COG_18674, Scenery.COG_18668, Scenery.COG_18671) // pin 1, pin 2, pin 3 val largeCogs = intArrayOf(Scenery.COG_18675, Scenery.COG_18669, Scenery.COG_18672) // pin 1, pin 2, pin 3 - // visualizes the steam press smasher - // todo it doesn't work right now - fun steamPress() { - val pressId = Scenery.STEAM_PRESS_18643 - val currentObject = getScenery(Location.create(1945, 5154, 3)) + /* + // updates the cog states (unused right now) + fun syncCogs(player: Player) { - // check an object actually exists here - if (currentObject != null) { - //println(currentObject.type) + } + */ - // check that the object is the press - if (pressId == currentObject.id) { - replaceScenery(currentObject, Scenery.STEAM_PRESS_18645, 5) // either this or Scenery.STEAM_PRESS_18644 + /* + // visualizes the steam press. right now all it does is spawn the hammer part. no anims or fancy stuff. + // if you just do a simple scenerybuilder.add it'll overwrite the track, so i've disabled it for now. + fun syncSteamPress(player: Player) { + SceneryBuilder.add(core.game.node.scenery.Scenery(steamPressStates[2], Location.create(1946, 5155, 2), 0)) + } + */ + + // syncs the water tank state. this is dependent on the valve states and the door state. also changes cart state (cooling bar) + fun syncTank(player: Player) { + val waterIn = getVarbit(player, EW2ValveWestVarbit) // 0 if valve closed, 1 if open + val waterOut = getVarbit(player, EW2ValveEastVarbit) // 0 if valve closed, 1 if open + val cart = getVarbit(player, EW2TankDoorStateVarbit) // whether the cart is in the tank or not + + if(waterIn == 0 && waterOut == 0) { // both valves closed, nothing happens + return + } else if(waterIn == 0 && waterOut == 1) { // drain is open, remove all added scenery + SceneryBuilder.remove(core.game.node.scenery.Scenery(Scenery.WATER_TANK_18660, location(1951, 5164, 2))) // full tank + SceneryBuilder.remove(core.game.node.scenery.Scenery(Scenery.WATER_TANK_18661, location(1951, 5164, 2))) // full tank + playAudio(player, Sounds.EW2_WATER_RACK_3184) // drain? + return + } else if(waterIn == 1 && waterOut == 0) { // inlet is open, fill tank + SceneryBuilder.add(core.game.node.scenery.Scenery(Scenery.WATER_TANK_18661, location(1951, 5164, 2))) // full tank + playAudio(player, Sounds.EW2_WATER_FLOW_3183) // fill? + if(cart == 3) { // if cart state is hot bar, transform to cool bar. + setVarbit(player, EW2TankDoorStateVarbit, 6, true) + setVarbit(player, EW2JigCartVarbit, 4, true) + syncTankDoor(player) + playAudio(player, Sounds.EW2_COOL_BAR_3168) + if(!getAttribute(player, attrWatered, false) && getQuestStage(player, Quests.ELEMENTAL_WORKSHOP_II) <= 6) { + setAttribute(player, attrWatered, true) + } } + return + } else if(waterIn == 1 && waterOut == 1) { // inlet and drain are open, tank is damp + SceneryBuilder.add(core.game.node.scenery.Scenery(Scenery.WATER_TANK_18660, location(1951, 5164, 2))) // damp tank + playAudio(player, Sounds.EW2_WATER_FLOW_3183) // fill? + return + } + } + + // syncs the tank door state. this is dependent on the corkscrew lever and cart state + fun syncTankDoor(player: Player) { + val state = getVarbit(player, EW2TankDoorStateVarbit) + val doorLoc = Location.create(1953, 5162, 2) + val currentObject = getScenery(doorLoc) + val targetId = tankDoorStates[state] + + // remove old scenery then add the new one + // todo right now this also deletes a piece of track that shares a tile with the door, but I don't really care. + if(currentObject != null && currentObject.id != targetId) { + SceneryBuilder.remove(core.game.node.scenery.Scenery(currentObject.id, doorLoc, 1)) + SceneryBuilder.add(core.game.node.scenery.Scenery(targetId, doorLoc, 1)) + } + } + + // updates fan state. fun fact, the fan state varbit isn't saved even if you say to save it. gotta make sure it's set on login. + fun syncFan(player: Player) { + val fanMachine = getVarbit(player, EW2FanLeverVarbit) + if (fanMachine == 1) { + setVarbit(player, EW2FanStateVarbit, 1) + } else { + setVarbit(player, EW2FanStateVarbit, 0) } } } @@ -247,6 +349,7 @@ class EW2Listeners : InteractionListener { } if(getVarbit(player, EW2MachineryVarbit) == 0) setVarbit(player, EW2MachineryVarbit, 1, true) + // todo the wiki notes that you must actually walk the path for the varbit to flip. Here i just flip it as soon as you read the scroll. return@on true } @@ -255,10 +358,12 @@ class EW2Listeners : InteractionListener { if(!inInventory(player, Items.KEY_9722)) { sendItemDialogue(player, Items.KEY_9722, "You find a key hidden in the third pipe.") addItemOrDrop(player, Items.KEY_9722) + } else { + sendDialogue(player, "You search the machinery but find nothing.") } if(getQuestStage(player, Quests.ELEMENTAL_WORKSHOP_II) == 3) { setQuestStage(player, Quests.ELEMENTAL_WORKSHOP_II, 4) - setVarbit(player, EW2StageVarbit, 4) + setVarbit(player, EW2StageVarbit, 4, true) } return@on true } @@ -277,7 +382,7 @@ class EW2Listeners : InteractionListener { if(getQuestStage(player, Quests.ELEMENTAL_WORKSHOP_II) == 4) { setQuestStage(player, Quests.ELEMENTAL_WORKSHOP_II, 5) - setVarbit(player, EW2StageVarbit, 5) + setVarbit(player, EW2StageVarbit, 5, true) } return@on true } @@ -337,8 +442,10 @@ class EW2Listeners : InteractionListener { on(Scenery.LEVER_18620, IntType.SCENERY, "pull") { player, _ -> val currentPos = getVarbit(player, EW2CartLeverVarbit) // cart moving lever. 0 = start (south), 1 = west, 2 = north, 3 = east val cranePos = getVarbit(player, EW2CranePosVarbit) // 2 if crane is down on north side - val doorPos = getVarbit(player, EW2DoorLeverVarbit) // 1 if door is open - val fanPos = getVarbit(player, EW2FanLeverVarbit) // 1 if the fan is on + val doorPos = getVarbit(player, EW2TankDoorStatusVarbit) // 1 if door is open + val tankState = getVarbit(player, EW2TankDoorStateVarbit) + val fanState = getVarbit(player, EW2FanLeverVarbit) // 1 if the fan is on + // find the cart val trackCenter = Location.create(1953, 5155, 2) @@ -358,9 +465,8 @@ class EW2Listeners : InteractionListener { sendMessage(player, "You cannot do that while the door is open.") return@on true } - // todo check the corkscrew because i think that'll shift the cart off the track - // door must be closed - if (currentPos == 3 && fanPos == 1) { + // fan must be off + if (currentPos == 3 && fanState == 1) { sendMessage(player, "You cannot do that while the fan is on.") return@on true } @@ -368,6 +474,11 @@ class EW2Listeners : InteractionListener { if (existingCart.walkingQueue.isMoving) { return@on true } + // cart must not be in the water tank + if (tankState == 3 || tankState == 4 || tankState == 6 || tankState == 7) { + sendMessage(player, "You cannot do that while the cart is inside the tank.") + return@on true + } // set path val path = when (currentPos) { @@ -396,11 +507,14 @@ class EW2Listeners : InteractionListener { // todo there are weird bugs with walkingQueue. cart sometimes veers off randomly to one of the other destinations. just teleporting for now. // move - //existingCart.walkingQueue.reset() - //for (step in path) { - // existingCart.walkingQueue.addPath(step.x, step.y) - //} + /* + existingCart.walkingQueue.reset() + for (step in path) { + existingCart.walkingQueue.addPath(step.x, step.y) + } + */ teleport(existingCart, path[2]) + playAudio(player, Sounds.EW2_CART_LOOP_3167) } return@on true @@ -418,11 +532,21 @@ class EW2Listeners : InteractionListener { 4915 -> { sendMessage(player, "The bar is too hot to touch.") } + 4916 -> { + sendMessage(player, "The bar is too hot to touch.") + } + 4917 -> { + sendMessage(player, "You should finish the process before taking the bar.") + } 4918 -> { addItemOrDrop(player, Items.PRIMED_BAR_9727) sendItemDialogue(player, Items.PRIMED_BAR_9727, "You take the primed bar.") animate(player, 537) setVarbit(player, EW2JigCartVarbit, 0, true) + if(getQuestStage(player, Quests.ELEMENTAL_WORKSHOP_II) <= 6) { + setQuestStage(player, Quests.ELEMENTAL_WORKSHOP_II, 7) + setVarbit(player, EW2StageVarbit, 7, true) + } } } syncCart(player) @@ -441,8 +565,12 @@ class EW2Listeners : InteractionListener { setVarbit(player, EW2JigCartVarbit, 1, true) animate(player, 537) + playAudio(player, Sounds.EW2_PLACE_BAR_3177) syncCart(player) removeItem(player, used) + if(!getAttribute(player, attrJigged, false) && getQuestStage(player, Quests.ELEMENTAL_WORKSHOP_II) <= 6) { + setAttribute(player, attrJigged, true) + } return@onUseWith true } @@ -465,7 +593,7 @@ class EW2Listeners : InteractionListener { } // fix crane - onUseWith(IntType.SCENERY, Items.CRANE_CLAW_9720, Scenery.OLD_CRANE_18636) { player, used, with -> + onUseWith(IntType.SCENERY, Items.CRANE_CLAW_9720, Scenery.OLD_CRANE_18636) { player, used, _ -> // check if already repaired if(getVarbit(player, EW2CraneStateVarbit) != 0) { sendMessage(player, "The crane is already repaired.") @@ -558,36 +686,44 @@ class EW2Listeners : InteractionListener { if (cartPos == 1) { when (cartState) { 0 -> { // empty - steamPress() sendDialogue(player, "You pull the lever and the press operates, but there is nothing on the cart to flatten.") + playAudio(player, Sounds.EW2_PRESS_BAR_3180) + animate(player, Animations.HUMAN_PULL_LEVER_4909) } 1 -> { // ele bar setVarbit(player, EW2JigCartVarbit, 4) - steamPress() // "hardy" is the real word used. I thought it was a typo for 'hammer' but it's not. https://en.wikipedia.org/wiki/Hardy_tool + // also note during one of the source videos it's authentic that the press state shows a purple ele bar for a moment. weird. sendDialogue(player, "You pull the lever and the press responds. The hardy comes down, hitting the elemental bar. The bar is not hot enough to flatten.") + playAudio(player, Sounds.EW2_PRESS_BAR_3180) + animate(player, Animations.HUMAN_PULL_LEVER_4909) syncCart(player) } 2 -> { // hot ele bar setVarbit(player, EW2JigCartVarbit, 3) - steamPress() // "hardy" is correct. see above. sendDialogue(player, "You pull the lever and the press responds. The hardy comes down, hitting the elemental bar. The bar has been flattened.") + playAudio(player, Sounds.EW2_PRESS_BAR_3180) + animate(player, Animations.HUMAN_PULL_LEVER_4909) syncCart(player) + if(!getAttribute(player, attrFlattened, false) && getQuestStage(player, Quests.ELEMENTAL_WORKSHOP_II) <= 6) { + setAttribute(player, attrFlattened, true) + } } else -> { // smashed hot, smashed cooled, or primed - steamPress() sendDialogue(player, "You pull the lever and the press responds. The hardy comes down, hitting the elemental bar. The bar is already flattened.") + playAudio(player, Sounds.EW2_PRESS_BAR_3180) + animate(player, Animations.HUMAN_PULL_LEVER_4909) } } } else { // cart in wrong position - steamPress() sendDialogue(player, "You pull the lever and the press operates, but the jig cart is not underneath it.") } } else { // The junction box is not configured correctly sendDialogue(player, "You pull the lever but nothing happens.") + animate(player, Animations.HUMAN_PULL_LEVER_4909) } return@on true @@ -614,50 +750,179 @@ class EW2Listeners : InteractionListener { onUseWith(IntType.SCENERY, Items.PIPE_9723, Scenery.PIPING_18650) { player, item, _ -> animate(player, 537) sendItemDialogue(player, item, "You replace the section of broken pipe.") - playAudio(player, Sounds.EW2_PLACE_PIPE_3179) + playAudio(player, Sounds.EW2_PLACE_PIPE_3433) setVarbit(player, EW2PipeVarbit, 1, true) removeItem(player, item) return@onUseWith true } - // todo north lever - // todo see below, note that the door cannot have its scenery updated because it overlaps with the track and our limited engine can't find it. // north lever that opens and closes the door on(Scenery.AN_OLD_LEVER_18648, IntType.SCENERY, "pull") { player, _ -> + val doorOpen = getVarbit(player, EW2TankDoorStatusVarbit) + val tankState = getVarbit(player, EW2TankDoorStateVarbit) + val tankScen = getScenery(location(1951, 5164, 2)) - val currentState = getVarbit(player, EW2TankDoorVarbit) + animate(player, Animations.HUMAN_PULL_LEVER_4909) + // if tank has water, don't open. + if(tankScen != null) { + sendDialogue(player, "You pull the lever but nothing happens. Maybe the tank needs to be empty first.") + return@on true + } + + // check the rack is not out + if(tankState == 2 || tankState == 5 || tankState == 8) { + sendDialogue(player, "You pull the lever but nothing happens. Maybe the rack needs retracting first.") + return@on true + } + + // update door status open/close + if(doorOpen == 0) { + setVarbit(player, EW2TankDoorStatusVarbit, 1, true) + } else { + setVarbit(player, EW2TankDoorStatusVarbit, 0, true) + } + + // update door state + val nextTankState = when (tankState) { + 1 -> 0 // Opened -> Closed + 0 -> 1 // Closed -> Opened + 4 -> 3 // Opened/Hot -> Closed/Hot + 3 -> 4 // Closed/Hot -> Opened/Hot + 7 -> 6 // Opened/Cooled -> Closed/Cooled + 6 -> 7 // Closed/Cooled -> Opened/Cooled + // six seeeven hehehehe + else -> tankState + } + + setVarbit(player, EW2TankDoorStateVarbit, nextTankState) + syncTankDoor(player) return@on true } - // todo corkscrew lever // corkscrew lever that grabs and ungrabs the cart as long as the door is open on(Scenery.CORKSCREW_LEVER_18649, IntType.SCENERY, "turn") { player, _ -> + val cartPos = getVarbit(player, EW2CartLeverVarbit) + val doorStatus = getVarbit(player, EW2TankDoorStatusVarbit) // 0 = closed, 1 = open + val cartState = getVarbit(player, EW2JigCartVarbit) + val tankState = getVarbit(player, EW2TankDoorStateVarbit) + // cart must be at north station + if (cartPos != 2) { + sendMessage(player, "The jig cart is not in position to be grabbed.") + return@on true + } + + // door must be open (this also requires tank to be empty) + if (doorStatus == 0) { + sendMessage(player, "The tank door must be open to use the corkscrew.") + return@on true + } + + playAudio(player, Sounds.EW2_SCREW_TURN_3182) + animate(player, Animations.HUMAN_TURN_CORKSCREW_LEVER_4905) + + // either pull cart in or push it out. transfer between all the door open states + runTask(player, 1) { + when (tankState) { + 1 -> { // 1 door opened, grabber inside + setVarbit(player, EW2TankDoorStateVarbit, 2) // 2 door opened, grabber out + // no cart update + } + 2 -> { // 2 door opened, grabber out + // only grab the hot bar + if(cartState == 3) setVarbit(player, EW2TankDoorStateVarbit, 4) // 4 door opened, hot bar inside + // remove hot bar cart + } + 4 -> { // 4 door opened, hot bar inside + setVarbit(player, EW2TankDoorStateVarbit, 5) // 5 door opened, hot bar out + } + 5 -> { // 5 door opened, hot bar out + setVarbit(player, EW2TankDoorStateVarbit, 1) // 1 door opened, grabber inside + // add hot bar cart + } + 7 -> { // 7 door opened, cooled bar inside + setVarbit(player, EW2TankDoorStateVarbit, 8) // 8 door opened, cooled bar out + } + 8 -> { // 8 door opened, cooled bar out + setVarbit(player, EW2TankDoorStateVarbit, 1) // 1 door opened, grabber inside + // add cool bar cart + } + } + syncTankDoor(player) + syncCart(player) + } return@on true } - // todo west water valve - // west water valve fills the chamber if the door is closed "you open the valve" "you close the valve" make sure it's closed or the chamber will fill up again - // changes cart state into flattened mind bar + // west water valve operates the water inflow on(Scenery.WATER_VALVE_18646, IntType.SCENERY, "turn") { player, _ -> + val valveState = getVarbit(player, EW2ValveWestVarbit) // water valve west. 0 = closed, 1 = open + val door = getVarbit(player, EW2TankDoorStatusVarbit) // 0 if door closed, 1 if open + + if(door == 1) { + sendMessage(player, "The valve won't turn, maybe the door needs to be closed first.") + return@on true + } + + player.locks.lockInteractions(4) + animate(player, 4861) + + // if closed, open the valve + if(valveState == 0){ + setVarbit(player, EW2ValveWestVarbit, 1, true) + runTask(player, 3) { + syncTank(player) + sendDialogue(player, "you open the valve") + playAudio(player, Sounds.EW2_WATER_VALVE_3185) + } + // if open, close the valve + } else { + setVarbit(player, EW2ValveWestVarbit, 0, true) + runTask(player, 3) { + syncTank(player) + sendDialogue(player, "you close the valve") + playAudio(player, Sounds.EW2_WATER_VALVE_3185) + } + } return@on true } - // todo east water valve - // east water valve drains the tank if it is full "you open the valve" + // east water valve operates the drain on(Scenery.WATER_VALVE_18647, IntType.SCENERY, "turn") { player, _ -> + val valveState = getVarbit(player, EW2ValveEastVarbit) // water valve west. 0 = closed, 1 = open + val door = getVarbit(player, EW2TankDoorStatusVarbit) // 0 if door closed, 1 if open + + if(door == 1) { + sendMessage(player, "The valve won't turn, maybe the door needs to be closed first.") + return@on true + } + + player.locks.lockInteractions(4) + animate(player, 4861) + + // if closed, open the valve + if(valveState == 0){ + setVarbit(player, EW2ValveEastVarbit, 1, true) + runTask(player, 3) { + syncTank(player) + sendDialogue(player, "you open the valve") + playAudio(player, Sounds.EW2_WATER_VALVE_3185) + } + // if open, close the valve + } else { + setVarbit(player, EW2ValveEastVarbit, 0, true) + runTask(player, 3) { + syncTank(player) + sendDialogue(player, "you close the valve") + playAudio(player, Sounds.EW2_WATER_VALVE_3185) + } + } return@on true } - /** - * Scenery.WATER_TANK_18660 - * Scenery.WATER_TANK_18661 - */ - - /**------------------------ * SECTION 4 - FAN ** ------------------------ @@ -734,18 +999,21 @@ class EW2Listeners : InteractionListener { setVarbit(player, EW2CogVarbit1, 1, true) sendItemDialogue(player, item, "You put the small cog onto the shaft.") animate(player, 537) + playAudio(player, Sounds.EW2_PLACE_COG_3178) removeItem(player, item) } Items.MEDIUM_COG_9725 -> { setVarbit(player, EW2CogVarbit1, 2, true) sendItemDialogue(player, item, "You put the medium cog onto the shaft.") animate(player, 537) + playAudio(player, Sounds.EW2_PLACE_COG_3178) removeItem(player, item) } Items.LARGE_COG_9724 -> { setVarbit(player, EW2CogVarbit1, 3, true) sendItemDialogue(player, item, "You put the large cog onto the shaft.") animate(player, 537) + playAudio(player, Sounds.EW2_PLACE_COG_3178) removeItem(player, item) } } @@ -822,37 +1090,42 @@ class EW2Listeners : InteractionListener { return@onUseWith true } - // todo see above, note that the fan scenery cannot be animated :( because it must overlap with some other object and our limited engine can't find it. // fan lever. Authentically this check should allow the machine to start and the fan to either not start, start backwards, or start correctly, but I'm simplifying it for my sanity. on(Scenery.AN_OLD_LEVER_18663, IntType.SCENERY, "pull") { player, _ -> animate(player, Animations.HUMAN_PULL_LEVER_4909) - val p1 = getVarbit(player, EW2CogVarbit1) - val p2 = getVarbit(player, EW2CogVarbit2) - val p3 = getVarbit(player, EW2CogVarbit3) + val allCogs = getVarbit(player, EW2AllCogsVarbit) val lever = getVarbit(player, EW2FanLeverVarbit) val cartpos = getVarbit(player, EW2CartLeverVarbit) // needs to be 3 to be at this station val cartstate = getVarbit(player, EW2JigCartVarbit) // needs to be state 4: smashed cooled // check if the cogs are right. pin 1 (2655) should have the small cog. pin 2 (2656) should have the med cog. pin 3 (2656) should have the large cog. - if (p1 == 1 && p2 == 2 && p3 == 3) { + if (allCogs == 57) { if(lever == 0) { // turn on sendDialogue(player, "The machine rumbles and the fan starts to blow.") // Is authentically two messages of "The machine starts rumbling." and "The fan starts to blow.", but I am simplifying this check. + playAudio(player, Sounds.EW2_MACHINE_RUMBLE_3175) + playAudio(player, Sounds.EW2_FANBLADE_3174) setVarbit(player, EW2FanLeverVarbit, 1, true) + syncFan(player) // check cart and cool if necessary. otherwise nothing should happen. if (cartpos == 3 && cartstate == 4) { setVarbit(player, EW2JigCartVarbit, 5, true) syncCart(player) + if(!getAttribute(player, attrWinded, false) && getQuestStage(player, Quests.ELEMENTAL_WORKSHOP_II) <= 6) { + setAttribute(player, attrWinded, true) + } } } else { // turn off sendDialogue(player, "The machine grinds to a standstill.") - setVarbit(player, EW2FanLeverVarbit, 0, true) + setVarbit(player, EW2FanStateVarbit, 0, true) + syncFan(player) } // cogs are not correct } else { sendDialogue(player, "The machine starts up, but the fan does not blow.") + playAudio(player, Sounds.EW2_MACHINE_RUMBLE_3175) } return@on true } @@ -862,47 +1135,127 @@ class EW2Listeners : InteractionListener { ** ------------------------ */ - // todo add graphics to this section - // use bar with extractor gun onUseWith(IntType.SCENERY, intArrayOf(Items.PRIMED_BAR_9727), Scenery.EXTRACTOR_GUN_18693) { player, item, _ -> - setVarbit(player, EW2ExtractorGun, 1, true) + if(removeItem(player, item)) { + setVarbit(player, EW2ExtractorGun, 1, true) + animate(player, 537) + sendDialogue(player, "You place the primed bar under the device.") + if(getQuestStage(player, Quests.ELEMENTAL_WORKSHOP_II) <= 8) { + setQuestStage(player, Quests.ELEMENTAL_WORKSHOP_II, 9) + setVarbit(player, EW2StageVarbit, 9, true) + } + } return@onUseWith true } // take primed bar on(intArrayOf(Scenery.EXTRACTOR_GUN_18694), IntType.SCENERY, "take-from") { player, _ -> addItemOrDrop(player, Items.PRIMED_BAR_9727) + animate(player, 537) setVarbit(player, EW2ExtractorGun, 0, true) + sendDialogue(player, "You take the primed bar.") return@on true } // take mind bar on(intArrayOf(Scenery.EXTRACTOR_GUN_18695), IntType.SCENERY, "take-from") { player, _ -> addItemOrDrop(player, Items.ELEMENTAL_MIND_BAR_9728) + animate(player, 537) setVarbit(player, EW2ExtractorGun, 0, true) + sendDialogue(player, "You take the elemental mind bar.") return@on true } // sit in chair + // todo the extractor gun needs a graphic + // todo per one of the sources the camera angle changes for this. on(intArrayOf(Scenery.EXTRACTOR_HAT_18690), IntType.SCENERY, "operate") { player, _ -> - // if bar is in place + // check magic level + if(getDynLevel(player, Skills.MAGIC) < 20) { + sendMessage(player, "You must have a Magic level of 20 and above to use the device.") + return@on true + } + // if bar is in place, charge it and drain magic if(getVarbit(player, EW2ExtractorGun) == 1) { - setVarbit(player, EW2ExtractorGun, 2, true) + runTask(player) { + forceMove( + player, + Location.create(1961, 5150, 0), + Location.create(1962, 5150, 0), + 0, + 0 + ) + visualize(player, Animations.HUMAN_USE_EXTRACTOR_HAT_CHAIR_4884, goodHat) + playAudio(player, Sounds.EW2_EXTRACTOR_OPERATION_3166) + sendGraphics(809, Location.create(1962, 5148, 0)) + setVarbit(player, EW2ExtractorGun, 2, true) + adjustLevel(player, Skills.MAGIC, -20) + sendMessage(player, "You feel magically weakened.") + if(getQuestStage(player, Quests.ELEMENTAL_WORKSHOP_II) <= 9) { + setQuestStage(player, Quests.ELEMENTAL_WORKSHOP_II, 10) + setVarbit(player, EW2StageVarbit, 10, true) + } + } + forceMove( + player, + Location.create(1962, 5150, 0), + Location.create(1961, 5150, 0), + 200, + 2 + ) + // if bar is not in place (or if it's already a primed bar), hit player + } else { + runTask(player) { // 50 client cycles = 1 second + forceMove( + player, + Location.create(1961, 5150, 0), + Location.create(1962, 5150, 0), + 0, + 0 + ) + visualize(player, Animations.HUMAN_IMPROPERLY_USE_EXTRACTOR_HAT_CHAIR_4885, badHat) + playAudio(player, Sounds.EW2_EXTRACTOR_ZAP_3173) + impact(player, 4) + sendMessage(player, "The extractor hat shocks you!.") + } + forceMove( + player, + Location.create(1962, 5150, 0), + Location.create(1961, 5150, 0), + 350, + 2 + ) } return@on true } - /** - * EXTRACTOR_GUN_18693 - * EXTRACTOR_GUN_18694 - * EXTRACTOR_GUN_18695 - * EXTRACTOR_GUN_18696 - * EXTRACTOR_HAT_18690 - * EXTRACTOR_HAT_18691 - * EXTRACTOR_HAT_TOP_18692 + /**------------------------ + * EXTRA + ** ------------------------ */ + // equip graphics for helmets and shields. the shields should not technically show until the graphic finishes, but I can't find an easy way to do that. + onEquip(Items.MIND_HELMET_9733) { player, _ -> + sendGraphics(mHelmEquip, player.location) + return@onEquip true + } + + onEquip(Items.MIND_SHIELD_9731) { player, _ -> + sendGraphics(Graphics(mShieldEquip,95), player.location) + return@onEquip true + } + + onEquip(Items.ELEMENTAL_HELMET_9729) { player, _ -> + sendGraphics(eHelmEquip, player.location) + return@onEquip true + } + + onEquip(Items.ELEMENTAL_SHIELD_2890) { player, _ -> + sendGraphics(Graphics(eShieldEquip,95), player.location) + return@onEquip true + } + } // fixes to get right interact locations @@ -915,7 +1268,7 @@ class EW2Listeners : InteractionListener { return@setDest Location.create(1954, 5148, 2) } - setDest(IntType.NPC, intArrayOf(NPCs.JIG_CART_4914, NPCs.JIG_CART_4915), "take-from") { _, _ -> + setDest(IntType.NPC, intArrayOf(NPCs.JIG_CART_4914, NPCs.JIG_CART_4915, NPCs.JIG_CART_4916, NPCs.JIG_CART_4917, NPCs.JIG_CART_4918), "take-from") { _, _ -> return@setDest Location.create(1954, 5148, 2) } diff --git a/Server/src/main/content/region/kandarin/seers/quest/elementalworkshop2/EW2Zone.kt b/Server/src/main/content/region/kandarin/seers/quest/elementalworkshop2/EW2Zone.kt index fd4048c45..3980cdce9 100644 --- a/Server/src/main/content/region/kandarin/seers/quest/elementalworkshop2/EW2Zone.kt +++ b/Server/src/main/content/region/kandarin/seers/quest/elementalworkshop2/EW2Zone.kt @@ -1,14 +1,23 @@ package content.region.kandarin.seers.quest.elementalworkshop2 +import content.data.Quests import content.region.kandarin.seers.quest.elementalworkshop2.EW2Listeners.Companion.syncCart import content.region.kandarin.seers.quest.elementalworkshop2.EW2Listeners.Companion.syncCrane +import content.region.kandarin.seers.quest.elementalworkshop2.EW2Listeners.Companion.syncFan +import content.region.kandarin.seers.quest.elementalworkshop2.EW2Listeners.Companion.syncTank +import content.region.kandarin.seers.quest.elementalworkshop2.EW2Listeners.Companion.syncTankDoor +import content.region.kandarin.seers.quest.elementalworkshop2.ElementalWorkshop2.Companion.EW2StageVarbit +import core.api.* import core.game.node.entity.Entity import core.game.node.entity.player.Player +import core.game.node.scenery.SceneryBuilder +import core.game.world.map.Location import core.plugin.Initializable import core.game.world.map.zone.MapZone import core.game.world.map.zone.ZoneBorders import core.game.world.map.zone.ZoneBuilder import core.plugin.Plugin +import org.rs09.consts.Scenery /** * This updates the Elemental Workshop II state whenever the player enters, @@ -30,8 +39,19 @@ class EW2Zone : MapZone("Elemental Workshop II", true), Plugin { // updates the workshop state based on the varbits for Elemental Workshop II override fun enter(e: Entity?): Boolean { if(e is Player) { + + if(getQuestStage(e, Quests.ELEMENTAL_WORKSHOP_II) <= 5) { + setQuestStage(e, Quests.ELEMENTAL_WORKSHOP_II, 6) + setVarbit(e, EW2StageVarbit, 6, true) + } + + SceneryBuilder.add(core.game.node.scenery.Scenery(Scenery.DOOR_18651, Location.create(1953, 5162, 2), 1)) syncCrane(e) syncCart(e) + //syncSteamPress(e) + syncTank(e) + syncTankDoor(e) + syncFan(e) } return super.enter(e) } diff --git a/Server/src/main/content/region/kandarin/seers/quest/elementalworkshop2/ElementalWorkshop2.kt b/Server/src/main/content/region/kandarin/seers/quest/elementalworkshop2/ElementalWorkshop2.kt index 0fe6b7a67..c1dac6f59 100644 --- a/Server/src/main/content/region/kandarin/seers/quest/elementalworkshop2/ElementalWorkshop2.kt +++ b/Server/src/main/content/region/kandarin/seers/quest/elementalworkshop2/ElementalWorkshop2.kt @@ -6,13 +6,15 @@ import core.game.node.entity.player.Player import core.game.node.entity.player.link.quest.Quest import core.game.node.entity.skill.Skills import core.plugin.Initializable +import org.rs09.consts.Graphics import org.rs09.consts.Items /** * ELEMENTAL WORKSHOP II QUEST * * Requirements: 20 Magic, 30 Smithing, completion of Elemental Workshop I - * Primary Source: https://www.youtube.com/watch?v=YKSWisRgGZk + * Primary Sources: https://www.youtube.com/watch?v=YKSWisRgGZk, https://www.youtube.com/watch?v=hv2rCofydXo + * Wiki: https://runescape.wiki/w/Elemental_Workshop_II?oldid=849620 */ @Initializable @@ -37,18 +39,32 @@ class ElementalWorkshop2 : Quest(Quests.ELEMENTAL_WORKSHOP_II, 53, 52, 1, EW2Sta const val EW2ValveEastVarbit = 2652 // water valve east. 0 = closed, 1 = open const val EW2Varp2 = 897 // second EW2 varp that packages varbits 2653-2664 - const val EW2TankDoorVarbit = 2653 // tank door holding state, controlled by corkscrew lever. 0 = closed, 1 = , 2 = , 3 = , 4 = , 5 = , 6 = , 7 = , 8 = // nine values. jig cart has six - const val EW2DoorLeverVarbit = 2654 // door lever for tank. 0 = closed, 1 = open + const val EW2TankDoorStateVarbit = 2653 // tank door holding state, controlled by corkscrew lever. 0 = closed, 1 = door opened grabber inside, 2 = door opened grabber out, 3 = door closed hot bar inside, 4 = door opened hot bar inside, 5 = door opened hot bar out, 6 = door closed cooled bar inside, 7 = door opened cooled bar inside, 8 = door closed cooled bar out + const val EW2TankDoorStatusVarbit = 2654// door lever for tank. 0 = closed, 1 = open const val EW2CogVarbit1 = 2655 // cog pin. 0 = no cog, 1 = small, 2 = med, 3 = large const val EW2CogVarbit2 = 2656 // cog pin. 0 = no cog, 1 = small, 2 = med, 3 = large const val EW2CogVarbit3 = 2657 // cog pin. 0 = no cog, 1 = small, 2 = med, 3 = large - //const val EW2AllCogsVarbit = 2658 // overlaps the cog varbits. could be used to reset all cogs at once. + const val EW2AllCogsVarbit = 2658 // overlaps the cog varbits. const val EW2FanLeverVarbit = 2659 // fan switch. 0 = fan off, 1 = fan on - //const val EW2FanStateVarbit = 2660 // fan blades. 0 = off, 1 = forward, 2 = reverse + const val EW2FanStateVarbit = 2660 // fan blades. 0 = off, 1 = forward, 2 = reverse //const val EW2FanStationVarbit = 2661 // overlaps cogs, fan switch, and fan blades varbits const val EW2ExtractorGun = 2662 // extractor gun. 0 = empty, 1 = primed bar, 2 = mind bar - //const val EW2 = 2663 // - //const val EW2 = 2664 // values from 1 to 7 back at the dig site library where you find the book. + //const val EW2mystery1 = 2663 // no idea what this one does. it's in the place of the hammer lever? + //const val EW2mystery2 = 2664 // no idea what this one does. values from 1 to 7 back at the dig site library where you find the book. + + const val attrJigged = "/save:quest:ew2-jigged" //true after you put a bar on the jig cart + const val attrDipped = "/save:quest:ew2-dipped" //true after dip the bar in the lava + const val attrFlattened = "/save:quest:ew2-flattened" //true after you flatten the hot bar + const val attrWatered = "/save:quest:ew2-watered" //true after you cool the bar in the tank + const val attrWinded = "/save:quest:ew2-winded" //true after you cool the bar in the wind tunnel + + // defining these graphics here because the graphics consts conflicts with the graphics object in the listeners + const val goodHat = Graphics.EXTRACTOR_HAT_CHAIR_807 + const val badHat = Graphics.IMPROPERLY_EXTRACTOR_HAT_CHAIR_808 + const val mShieldEquip = 809 + const val mHelmEquip = 810 + const val eShieldEquip = 244 + const val eHelmEquip = 811 } /** @@ -61,18 +77,21 @@ class ElementalWorkshop2 : Quest(Quests.ELEMENTAL_WORKSHOP_II, 53, 52, 1, EW2Sta * 2 2 read the beaten book * 3 3 read the beaten book's scroll * 4 4 found key - * 5 5 went down center hatch - * 6 6 read the crane schematic - * 7 7 read the lever schematic? + * 5 5 went down center hatch. need to fix equipment + * 6 6 inside the workshop. processing bar + * 7 7 take primed bar * 8 8 went through the mind door - * 9 9 primed a mind bar - * 10 10 primed a mind bar? + * 9 9 placed a primed bar + * 10 10 sat in the extractor * 11 100 smithed a mind helmet, quest complete */ override fun drawJournal(player: Player, stage: Int) { + + // Quest journal source: https://www.youtube.com/watch?v=hv2rCofydXo + super.drawJournal(player, stage) var line = 12 - var stage = getStage(player) + val stage = getStage(player) // unstarted if (stage == 0) { @@ -105,57 +124,116 @@ class ElementalWorkshop2 : Quest(Quests.ELEMENTAL_WORKSHOP_II, 53, 52, 1, EW2Sta // stage 3, read the scroll from the beaten book if (stage >= 3) { - line(player, "The note found with the book has a strange code written on it.", line++, stage > 3) + line(player, "The note found with the book has a !!strange code?? written on it.", line++, stage > 3) // in-progress stage text - //if(stage == 3) line(player, "", line++) + if(stage == 3) line(player, "I wonder what it means.", line++) line++ } // stage 4, finding the key if (stage >= 4) { line(player, "By following the code on the !!note?? I was able to !!find a key??.", line++, stage > 4) + // in-progress stage text + if(stage == 4) line(player, "Now I just have to find what it opens.", line++) line++ } - // stage 5, going down the center hatch + // stage 5, going down the center hatch and getting the machines fixed if (stage >= 5) { - line(player, "The !!key?? I've found opens the !!large hatch?? in the !!workshop??; there are !!4 machines?? on this level to fix:", line++, stage > 5) - line(player, "The crane - now the claw has been replaced the crane looks like it's in good working order.", line++, stage > 5) - line(player, "The pipes - the pipes have now been fitted and it should work as long as it's powered.", line++, stage > 5) - line(player, "The tank - this should work fine now I have replaced the pipe.", line++, stage > 5) - line(player, "A wind tunnel - I have fitted all the cogs on to the pins. The win tunnel should now work as long as it's powered.", line++, stage > 5) - line(player, "A wind tunnel - I have fitted all the cogs on to the pins. The win tunnel should now work as long as it's powered.", line++, stage > 5) + line(player, "Climbing down through the hatch I found a new area in the", line++, (getVarbit(player, EW2CraneStateVarbit) != 0 && JunctionBoxInterface.isSolutionCorrect(player) && getVarbit(player, EW2PipeVarbit) != 0 && getVarbit(player, EW2AllCogsVarbit) == 57)) + line(player, "workshop; there are 4 machines on this level to !!fix??:", line++, (getVarbit(player, EW2CraneStateVarbit) != 0 && JunctionBoxInterface.isSolutionCorrect(player) && getVarbit(player, EW2PipeVarbit) != 0 && getVarbit(player, EW2AllCogsVarbit) == 57)) - line(player, "I have found a track-mounted jig on which I was able to clamp an elemental bar.", line++, stage > 5) - line(player, "I used the press to flatten the hot elemental bar.", line++, stage > 5) - line(player, "The water tank was used to cool the elemental bar down.", line++, stage > 5) - line(player, "The wind tunnel proved a great way to dry off the wet bar.", line++, stage > 5) - line(player, "I have primed a bar of elemental ore.", line++, stage > 5) - line(player, "I placed the primed bar on the device found in the room with the mind symbols on the door.", line++, stage > 5) - line(player, "Operating the device charged the primed bar with some of my own mind power.", line++, stage > 5) - line(player, "I have made an elemental mind bar, now I just have to make one of the helms from it.", line++, stage > 5) - line(player, "Creating the elemental mind helm was easy with the book for instruction.", line++, stage > 5) - line(player, "", line++, stage > 5) + if(getVarbit(player, EW2CraneStateVarbit) == 0)line(player, "The crane - this looks in a state of disrepair.", line++) + // "The crane - this looks in a state of disrepair, but I have \n created a replacement claw for it." + if(getVarbit(player, EW2CraneStateVarbit) != 0)line(player, "The crane - now the claw has been replaced the crane", line++, true) + if(getVarbit(player, EW2CraneStateVarbit) != 0)line(player, "looks like it's in good working order.", line++, true) + line++ + + if(!JunctionBoxInterface.isSolutionCorrect(player))line(player, "The press - I should see if this needs fixing.", line++) + // "The press - I should try to fit all the pipes in the right order." + if(JunctionBoxInterface.isSolutionCorrect(player))line(player, "The press - the pipes have now been fitted and ", line++, true) + if(JunctionBoxInterface.isSolutionCorrect(player))line(player, "it should work as long as it's powered.", line++, true) + line++ + + if(getVarbit(player, EW2PipeVarbit) == 0)line(player, "The tank - I'll need to fix this before I can use it.", line++) + if(getVarbit(player, EW2PipeVarbit) != 0)line(player, "The tank - this should work fine now I have replaced the pipe.", line++, true) + line++ + + if(getVarbit(player, EW2AllCogsVarbit) != 57)line(player, "A wind tunnel - it looks like a few bits are missing from it.", line++) + if(getVarbit(player, EW2AllCogsVarbit) == 57)line(player, "A wind tunnel - I have fitted all the cogs on to the pins.", line++, true) + if(getVarbit(player, EW2AllCogsVarbit) == 57)line(player, "The wind tunnel should now work as long as it's powered.", line++, true) line++ } - // stage 6 - if (stage >= 6) { - line(player, "", line++, stage > 6) + // stage 6, inside the workshop. put bar on cart + if (stage >= 6 && getAttribute(player, attrJigged, false)) { + line(player, "I have found a track-mounted jig", line++, stage > 6) + line(player, "on which I was able to clamp an elemental bar.", line++, stage > 6) line++ } - // stage 7 + // stage 6, inside the workshop. dipped + if (stage >= 6 && getAttribute(player, attrDipped, false)) { + line(player, "I was able to operate the crane and dip the elemental bar", line++, stage > 6) + line(player, "into the lava. The bar is now very hot.", line++, stage > 6) + line++ + } + + // stage 6, inside the workshop. flattened bar + if (stage >= 6 && getAttribute(player, attrFlattened, false)) { + line(player, "I used the press to flatten the hot elemental bar.", line++, stage > 6) + line++ + } + + // stage 6, inside the workshop. water tanked bar + if (stage >= 6 && getAttribute(player, attrWatered, false)) { + line(player, "The water tank was used to cool the elemental bar down.", line++, stage > 6) + line++ + } + + // stage 6, inside the workshop. wind tunneled bar + if (stage >= 6 && getAttribute(player, attrWinded, false)) { + line(player, "The wind tunnel proved a great way to dry off the wet bar.", line++, stage > 6) + line++ + } + + // stage 7, retrieve primed bar if (stage >= 7) { - line(player, "", line++, stage > 7) + line(player, "I have primed a bar of elemental ore, I wonder what to do", line++, stage > 7) + line(player, "with it.", line++, stage > 7) line++ } - // stage 8 + // stage 8, went through the mind door + /* if (stage >= 8) { line(player, "", line++, stage > 8) line++ } + */ + + // stage 9, placed a primed bar + if (stage >= 9) { + line(player, "I placed the primed bar on the device", line++, stage > 9) + line(player, "found in the room with the mind symbols on the door.", line++, stage > 9) + line++ + } + + // stage 10, sat in the extractor + if (stage >= 10) { + line(player, "Operating the device charged the", line++, stage > 10) + line(player, "primed bar with some of my own mind power.", line++, stage > 10) + line++ + line(player, "I have made an elemental mind bar,", line++, stage > 10) + line(player, "now I just have to make one of the helms from it.", line++, stage > 10) + line++ + } + + // stage 11, smithed a mind helmet, quest complete + if (stage >= 11) { + line(player, "Creating the elemental mind helm", line++, stage > 11) + line(player, "was easy with the book for instruction.", line++, stage > 11) + } } // use ::setqueststage 53 0 to reset quest. @@ -163,6 +241,11 @@ class ElementalWorkshop2 : Quest(Quests.ELEMENTAL_WORKSHOP_II, 53, 52, 1, EW2Sta // these varps wipes all the varbits setVarp(player, EW2Varp1, 0, true) setVarp(player, EW2Varp2, 0, true) + removeAttribute(player, attrJigged) + removeAttribute(player, attrDipped) + removeAttribute(player, attrFlattened) + removeAttribute(player, attrWatered) + removeAttribute(player, attrWinded) player.getQuestRepository().syncronizeTab(player) super.reset(player) } @@ -171,7 +254,7 @@ class ElementalWorkshop2 : Quest(Quests.ELEMENTAL_WORKSHOP_II, 53, 52, 1, EW2Sta var ln = 10 super.finish(player) player.packetDispatch.sendString("You have completed the Elemental Workshop II quest!", 277, 4) - player.packetDispatch.sendItemZoomOnInterface(Items.ELEMENTAL_HELMET_9729, 230, 277, 5) + player.packetDispatch.sendItemZoomOnInterface(Items.MIND_HELMET_9733, 230, 277, 5) drawReward(player, "1 Quest Point", ln++) drawReward(player, "7,500 Smithing XP,", ln++) @@ -183,7 +266,11 @@ class ElementalWorkshop2 : Quest(Quests.ELEMENTAL_WORKSHOP_II, 53, 52, 1, EW2Sta rewardXP(player, Skills.SMITHING, 7500.0) rewardXP(player, Skills.CRAFTING, 7500.0) - // remove attributes + removeAttribute(player, attrJigged) + removeAttribute(player, attrDipped) + removeAttribute(player, attrFlattened) + removeAttribute(player, attrWatered) + removeAttribute(player, attrWinded) } override fun newInstance(`object`: Any?): Quest { diff --git a/Server/src/main/content/region/kandarin/seers/quest/elementalworkshop2/JunctionBoxInterface.kt b/Server/src/main/content/region/kandarin/seers/quest/elementalworkshop2/JunctionBoxInterface.kt index 516e0cb8e..3aa5dccd9 100644 --- a/Server/src/main/content/region/kandarin/seers/quest/elementalworkshop2/JunctionBoxInterface.kt +++ b/Server/src/main/content/region/kandarin/seers/quest/elementalworkshop2/JunctionBoxInterface.kt @@ -7,6 +7,7 @@ import core.api.* import core.game.interaction.InterfaceListener import core.game.node.entity.player.Player import org.rs09.consts.Components +import org.rs09.consts.Sounds /** * Junction box in Elemental Workshop II @@ -149,6 +150,7 @@ class JunctionBoxInterface : InterfaceListener { // place the pipe val pipeChild = pipes[pipeIndex] setComponentVisibility(player, junctionBox, pipeChild, false) + playAudio(player, Sounds.EW2_PLACE_PIPE_3179) // pipe status is saved in these varbits and recalled on open. they are linked to main quest progression status val saved = when { @@ -217,6 +219,7 @@ class JunctionBoxInterface : InterfaceListener { // Increment pipes left val left = getVarbit(player, pipesLeftVarbit) setVarbit(player, pipesLeftVarbit, left + 1) + playAudio(player, Sounds.EW2_REMOVE_PIPE_3181) return true } }