From 09e92e9256da463fb426ddc1e26db7bb606ec7e8 Mon Sep 17 00:00:00 2001 From: aidan Date: Mon, 1 Dec 2025 09:24:21 -0600 Subject: [PATCH 1/7] initial commit. --- Server/data/configs/npc_spawns.json | 10 +- Server/data/configs/object_configs.json | 10 +- .../handlers/AbandonedMineListeners.kt | 150 ++++++++++++++++++ .../quest/hauntedmine/HauntedMine.kt | 139 ++++++++++++++++ .../quest/hauntedmine/HauntedMineListeners.kt | 19 +++ .../quest/hauntedmine/ZealotDialogue.kt | 108 +++++++++++++ .../main/core/game/requirement/Requirement.kt | 2 +- 7 files changed, 433 insertions(+), 5 deletions(-) create mode 100644 Server/src/main/content/region/morytania/handlers/AbandonedMineListeners.kt create mode 100644 Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMine.kt create mode 100644 Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMineListeners.kt create mode 100644 Server/src/main/content/region/morytania/quest/hauntedmine/ZealotDialogue.kt diff --git a/Server/data/configs/npc_spawns.json b/Server/data/configs/npc_spawns.json index 46a5a18e7..e5e5395ae 100644 --- a/Server/data/configs/npc_spawns.json +++ b/Server/data/configs/npc_spawns.json @@ -157,7 +157,7 @@ }, { "npc_id": "47", - "loc_data": "{2821,3170,0,1,1}-{3341,3267,0,1,5}-{3076,3282,0,1,5}-{3089,3266,0,1,4}-{3091,3266,0,1,4}-{3097,3364,0,1,3}-{3102,3363,0,1,5}-{3127,3487,0,1,4}-{3125,3486,0,1,6}-{3127,3486,0,1,4}-{2339,9356,0,1,0}-{2354,9390,0,1,0}-{2361,9403,0,1,0}-{2362,9347,0,1,0}-{2603,9480,0,1,1}-{2600,9477,0,1,0}-{2579,9496,0,1,4}-{2580,9508,0,1,0}-{2571,9522,0,1,4}-{2565,9505,0,1,1}-{2566,9510,0,1,6}-{2594,9497,0,1,4}-{2852,9642,0,1,6}-{2858,9632,0,1,3}-{2568,9620,0,1,0}-{2573,9612,0,1,0}-{2579,9631,0,1,0}-{2580,9600,0,1,0}-{2580,9614,0,1,0}-{2580,9620,0,1,0}-{2580,9626,0,1,0}-{2583,9632,0,1,0}-{2584,9625,0,1,0}-{2584,9637,0,1,0}-{2589,9644,0,1,0}-{2590,9601,0,1,0}-{2590,9638,0,1,0}-{2591,9601,0,1,0}-{2591,9621,0,1,0}-{2594,9636,0,1,0}-{2594,9644,0,1,0}-{2597,9604,0,1,0}-{2607,9615,0,1,0}-{2608,9628,0,1,0}-{2614,9651,0,1,0}-{2614,9656,0,1,0}-{2615,9647,0,1,0}-{2615,9661,0,1,0}-{2616,9633,0,1,0}-{2618,9630,0,1,0}-{3108,9754,0,1,5}-{3110,9754,0,1,5}-{3108,9750,0,1,5}-{2592,9831,0,1,3}-{2588,9825,0,1,6}-{2583,9829,0,1,4}-{2581,9841,0,1,0}-{2597,9823,0,1,2}-{2579,9805,0,1,3}-{2576,9804,0,1,0}-{2573,9805,0,1,5}-{2571,9808,0,1,3}-{2576,9810,0,1,2}-{2587,9802,0,1,2}-{2592,9800,0,1,4}-{2596,9805,0,1,6}-{2601,9802,0,1,5}-{2585,9801,0,1,7}-{2594,9803,0,1,0}-{2590,9806,0,1,3}-{2612,9808,0,1,6}-{2604,9810,0,1,6}-{2579,9821,0,1,2}-{2576,9812,0,1,6}-{2580,9813,0,1,6}-{2600,9813,0,1,4}-{2599,9809,0,1,4}-{3158,3226,0,1,5}-{3160,3202,0,1,4}-{3192,3203,0,1,0}-{3194,3204,0,1,0}-{3196,3206,0,1,0}-{3197,3204,0,1,0}-{2654,9640,0,1,6}-{2655,9637,0,1,4}-{2656,9639,0,1,7}-{2651,9636,0,1,5}-{2648,9637,0,1,4}-{2651,9642,0,1,1}-{2654,9640,0,1,0}-{2654,9635,0,1,6}-{2655,9635,0,1,3}-{2664,9626,0,1,6}-{2664,9624,0,1,1}-{2661,9623,0,1,1}-{2663,9623,0,1,3}-{2664,9626,0,1,6}-{2930,9699,0,1,0}-{2933,9697,0,1,0}-{2932,9685,0,1,0}-{2930,9693,0,1,0}-{3235,3224,0,1,3}-{3229,3220,0,1,4}-{3211,3211,0,1,3}-{3225,3220,0,1,1}-{3237,3215,0,1,5}-{3211,3210,0,1,7}-{3227,3220,0,1,7}-{3233,3227,0,1,5}-{3227,3210,0,1,6}-{3228,3222,0,1,4}-{3229,3226,0,1,0}-{3236,3217,0,1,4}-{3259,3230,0,1,4}-{3233,3237,0,1,7}-{3205,3204,0,1,0}-{3206,3204,0,1,0}-{3205,3203,0,1,0}-{3206,3202,0,1,0}-{3207,3202,0,1,0}-{3208,3203,0,1,0}-{3001,3202,0,1,5}-{3243,3687,0,1,5}-{3249,3669,0,1,3}-{3252,3675,0,1,4}-{3252,3680,0,1,3}-{3259,3683,0,1,0}-{3475,9840,0,1,6}-{3481,9842,0,1,1}-{3486,9843,0,1,7}-{3483,9824,0,1,4}-{3496,9808,0,0,5}-{3490,9815,0,1,1}-{3478,9834,0,0,3}-{3490,9824,0,1,4}-{3225,9862,0,1,4}-{3222,9861,0,1,6}-{3220,9860,0,1,6}-{3219,9865,0,1,6}-{3237,9862,0,1,4}-{2536,2982,0,1,3}-{2531,2980,0,1,0}-{2522,2981,0,1,4}-{2545,2989,0,1,4}-{2523,2970,0,1,2}-{3026,3174,0,1,5}-{3019,3176,0,1,7}-{2801,3158,0,1,2}-{2514,3193,0,1,6}-{2518,3192,0,1,3}-{2507,3181,0,1,3}-{2508,3178,0,1,6}-{2511,3183,0,1,3}-{2515,3182,0,1,1}-{3021,3205,0,1,6}-{3019,3292,0,1,7}-{3018,3295,0,1,7}-{2531,3325,0,1,3}-{2530,3327,0,1,5}-{2521,3331,0,1,3}-{2526,3328,0,1,3}-{2523,3331,0,1,4}-{2523,3334,0,1,1}-{2531,3329,0,1,5}-{2532,3333,0,1,5}-{3276,9871,0,1,1}-{3277,9871,0,1,3}-" + "loc_data": "{2821,3170,0,1,1}-{3076,3282,0,1,5}-{3089,3266,0,1,4}-{3091,3266,0,1,4}-{3341,3267,0,1,5}-{3097,3364,0,1,3}-{3102,3363,0,1,5}-{3127,3487,0,1,4}-{3125,3486,0,1,6}-{3127,3486,0,1,4}-{2339,9356,0,1,0}-{2354,9390,0,1,0}-{2361,9403,0,1,0}-{2362,9347,0,1,0}-{2603,9480,0,1,1}-{2600,9477,0,1,0}-{2579,9496,0,1,4}-{2580,9508,0,1,0}-{2571,9522,0,1,4}-{2565,9505,0,1,1}-{2566,9510,0,1,6}-{2594,9497,0,1,4}-{2852,9642,0,1,6}-{2858,9632,0,1,3}-{2568,9620,0,1,0}-{2573,9612,0,1,0}-{2579,9631,0,1,0}-{2580,9600,0,1,0}-{2580,9614,0,1,0}-{2580,9620,0,1,0}-{2580,9626,0,1,0}-{2583,9632,0,1,0}-{2584,9625,0,1,0}-{2584,9637,0,1,0}-{2589,9644,0,1,0}-{2590,9601,0,1,0}-{2590,9638,0,1,0}-{2591,9601,0,1,0}-{2591,9621,0,1,0}-{2594,9636,0,1,0}-{2594,9644,0,1,0}-{2597,9604,0,1,0}-{2607,9615,0,1,0}-{2608,9628,0,1,0}-{2614,9651,0,1,0}-{2614,9656,0,1,0}-{2615,9647,0,1,0}-{2615,9661,0,1,0}-{2616,9633,0,1,0}-{2618,9630,0,1,0}-{3108,9754,0,1,5}-{3110,9754,0,1,5}-{3108,9750,0,1,5}-{2592,9831,0,1,3}-{2588,9825,0,1,6}-{2583,9829,0,1,4}-{2581,9841,0,1,0}-{2597,9823,0,1,2}-{2579,9805,0,1,3}-{2576,9804,0,1,0}-{2573,9805,0,1,5}-{2571,9808,0,1,3}-{2576,9810,0,1,2}-{2587,9802,0,1,2}-{2592,9800,0,1,4}-{2596,9805,0,1,6}-{2601,9802,0,1,5}-{2585,9801,0,1,7}-{2594,9803,0,1,0}-{2590,9806,0,1,3}-{2612,9808,0,1,6}-{2604,9810,0,1,6}-{2579,9821,0,1,2}-{2576,9812,0,1,6}-{2580,9813,0,1,6}-{2600,9813,0,1,4}-{2599,9809,0,1,4}-{3158,3226,0,1,5}-{3160,3202,0,1,4}-{3192,3203,0,1,0}-{3194,3204,0,1,0}-{3196,3206,0,1,0}-{3197,3204,0,1,0}-{2654,9640,0,1,6}-{2655,9637,0,1,4}-{2656,9639,0,1,7}-{2651,9636,0,1,5}-{2648,9637,0,1,4}-{2651,9642,0,1,1}-{2654,9640,0,1,0}-{2654,9635,0,1,6}-{2655,9635,0,1,3}-{2664,9626,0,1,6}-{2664,9624,0,1,1}-{2661,9623,0,1,1}-{2663,9623,0,1,3}-{2664,9626,0,1,6}-{2930,9699,0,1,0}-{2933,9697,0,1,0}-{2932,9685,0,1,0}-{2930,9693,0,1,0}-{3235,3224,0,1,3}-{3229,3220,0,1,4}-{3211,3211,0,1,3}-{3225,3220,0,1,1}-{3237,3215,0,1,5}-{3211,3210,0,1,7}-{3227,3220,0,1,7}-{3233,3227,0,1,5}-{3227,3210,0,1,6}-{3228,3222,0,1,4}-{3229,3226,0,1,0}-{3236,3217,0,1,4}-{3259,3230,0,1,4}-{3233,3237,0,1,7}-{3205,3204,0,1,0}-{3206,3204,0,1,0}-{3205,3203,0,1,0}-{3206,3202,0,1,0}-{3207,3202,0,1,0}-{3208,3203,0,1,0}-{3001,3202,0,1,5}-{3243,3687,0,1,5}-{3249,3669,0,1,3}-{3252,3675,0,1,4}-{3252,3680,0,1,3}-{3259,3683,0,1,0}-{3475,9840,0,1,6}-{3481,9842,0,1,1}-{3486,9843,0,1,7}-{3483,9824,0,1,4}-{3496,9808,0,0,5}-{3490,9815,0,1,1}-{3478,9834,0,0,3}-{3490,9824,0,1,4}-{3225,9862,0,1,4}-{3222,9861,0,1,6}-{3220,9860,0,1,6}-{3219,9865,0,1,6}-{3237,9862,0,1,4}-{2536,2982,0,1,3}-{2531,2980,0,1,0}-{2522,2981,0,1,4}-{2545,2989,0,1,4}-{2523,2970,0,1,2}-{3026,3174,0,1,5}-{3019,3176,0,1,7}-{2801,3158,0,1,2}-{2514,3193,0,1,6}-{2518,3192,0,1,3}-{2507,3181,0,1,3}-{2508,3178,0,1,6}-{2511,3183,0,1,3}-{2515,3182,0,1,1}-{3021,3205,0,1,6}-{3019,3292,0,1,7}-{3018,3295,0,1,7}-{2531,3325,0,1,3}-{2530,3327,0,1,5}-{2521,3331,0,1,3}-{2526,3328,0,1,3}-{2523,3331,0,1,4}-{2523,3334,0,1,1}-{2531,3329,0,1,5}-{2532,3333,0,1,5}-{3276,9871,0,1,1}-{3277,9871,0,1,3}-" }, { "npc_id": "48", @@ -1221,7 +1221,7 @@ }, { "npc_id": "412", - "loc_data": "{3341,3478,0,1,0}-{3343,3484,0,1,0}-{3345,3484,0,1,0}-{3350,3493,0,1,0}-{3353,3494,0,1,0}-{3361,3484,0,1,0}-{3364,3489,0,1,0}-{3370,3497,0,1,0}-{3379,3478,0,1,0}-{3379,3484,0,1,0}-{3387,3483,0,1,0}-{3388,3494,0,1,0}-{3389,3483,0,1,0}-{3588,3472,0,1,0}-{3598,3509,0,1,0}-{3599,3486,0,1,0}-{3607,3462,0,1,0}-{3611,3499,0,1,0}-{3613,3482,0,1,0}-{3627,3511,0,1,0}-{3628,3473,0,1,0}-{3636,3466,0,1,0}-{3639,3510,0,1,0}-{3411,3536,0,1,0}-{3418,3522,0,1,0}-{3425,3525,0,1,0}-{3429,3522,0,1,0}-{3432,3527,0,1,0}-{3434,3521,0,1,0}-{3445,3526,0,1,0}-{2728,10122,0,1,1}-{2735,10123,0,1,3}-{2733,10129,0,1,1}-{2728,10133,0,1,6}-{2722,10133,0,1,6}-{2736,10137,0,1,1}-{2732,10142,0,1,0}-{2726,10142,0,1,6}-{2729,10140,0,1,3}-{2720,10144,0,1,6}-{2712,10142,0,1,3}-{3565,3503,0,1,0}-{3567,3481,0,1,0}-{3580,3491,0,1,0}-" + "loc_data": "{3341,3478,0,1,0}-{3343,3484,0,1,0}-{3345,3484,0,1,0}-{3350,3493,0,1,0}-{3353,3494,0,1,0}-{3361,3484,0,1,0}-{3364,3489,0,1,0}-{3370,3497,0,1,0}-{3379,3478,0,1,0}-{3379,3484,0,1,0}-{3387,3483,0,1,0}-{3388,3494,0,1,0}-{3389,3483,0,1,0}-{3588,3472,0,1,0}-{3598,3509,0,1,0}-{3599,3486,0,1,0}-{3607,3462,0,1,0}-{3611,3499,0,1,0}-{3613,3482,0,1,0}-{3627,3511,0,1,0}-{3628,3473,0,1,0}-{3636,3466,0,1,0}-{3639,3510,0,1,0}-{3411,3536,0,1,0}-{3418,3522,0,1,0}-{3425,3525,0,1,0}-{3429,3522,0,1,0}-{3432,3527,0,1,0}-{3434,3521,0,1,0}-{3445,3526,0,1,0}-{3419,9646,0,1,0}-{3418,9642,0,1,0}-{3414,9643,0,1,0}-{3411,9644,0,1,0}-{3410,9641,0,1,0}-{3409,9638,0,1,0}-{3419,9630,0,1,0}-{3421,9629,0,1,0}-{3433,9638,0,1,0}-{3434,9636,0,1,0}-{3436,9636,0,1,0}-{3423,9625,0,1,0}-{2728,10122,0,1,1}-{2735,10123,0,1,3}-{2733,10129,0,1,1}-{2728,10133,0,1,6}-{2722,10133,0,1,6}-{2736,10137,0,1,1}-{2732,10142,0,1,0}-{2726,10142,0,1,6}-{2729,10140,0,1,3}-{2720,10144,0,1,6}-{2712,10142,0,1,3}-{3565,3503,0,1,0}-{3567,3481,0,1,0}-{3580,3491,0,1,0}-" }, { "npc_id": "419", @@ -3385,7 +3385,7 @@ }, { "npc_id": "1223", - "loc_data": "{3585,3478,0,1,0}-{3586,3480,0,1,0}-{3586,3496,0,1,0}-{3592,3477,0,1,0}-{3593,3458,0,1,0}-{3593,3508,0,1,0}-{3595,3491,0,1,0}-{3597,3479,0,1,0}-{3607,3466,0,1,0}-{3617,3477,0,1,0}-{3618,3514,0,1,0}-{3631,3471,0,1,0}-{3631,3499,0,1,0}-{3632,3459,0,1,0}-{3632,3475,0,1,0}-{3638,3472,0,1,0}-{3646,3467,0,1,0}-" + "loc_data": "{3585,3478,0,1,0}-{3586,3480,0,1,0}-{3586,3496,0,1,0}-{3592,3477,0,1,0}-{3593,3458,0,1,0}-{3593,3508,0,1,0}-{3595,3491,0,1,0}-{3597,3479,0,1,0}-{3607,3466,0,1,0}-{3617,3477,0,1,0}-{3618,3514,0,1,0}-{3631,3471,0,1,0}-{3631,3499,0,1,0}-{3632,3459,0,1,0}-{3632,3475,0,1,0}-{3638,3472,0,1,0}-{3646,3467,0,1,0}-{3460,3241,0,1,0}-{3459,3237,0,1,0}-{3456,3234,0,1,0}-{3458,3230,0,1,0}-{3457,3227,0,1,0}-{3456,3223,0,1,0}-" }, { "npc_id": "1227", @@ -3855,6 +3855,10 @@ "npc_id": "1526", "loc_data": "{2443,3089,0,0,0}-" }, + { + "npc_id": "1528", + "loc_data": "{3443,3256,0,1,0}-" + }, { "npc_id": "1544", "loc_data": "{2911,10175,0,0,4}-{2912,10175,0,0,4}-{2913,10175,0,0,4}-{2914,10175,0,0,4}-{2909,10173,0,0,4}-{2910,10173,0,0,4}-{2911,10173,0,0,4}-{2912,10173,0,0,4}-{2913,10173,0,0,4}-{2909,10171,0,0,4}-{2910,10171,0,0,4}-{2911,10169,0,0,4}-{2912,10169,0,0,4}-{2913,10169,0,0,4}-" diff --git a/Server/data/configs/object_configs.json b/Server/data/configs/object_configs.json index ae364fd37..3c0478db1 100644 --- a/Server/data/configs/object_configs.json +++ b/Server/data/configs/object_configs.json @@ -7625,7 +7625,7 @@ }, { "examine": "It looks cramped and dark.", - "ids": "4920,4921,4922" + "ids": "4920,4921,4922,20524" }, { "examine": "These stairs seem to have been hewn out of the rock itself.", @@ -20730,5 +20730,13 @@ { "examine": "Rough but adequate.", "ids": "14918" + }, + { + "examine": "This door is blocked by a huge slab of stone.", + "ids": "20528" + }, + { + "examine": "A door leading somewhere.", + "ids": "20527" } ] \ No newline at end of file diff --git a/Server/src/main/content/region/morytania/handlers/AbandonedMineListeners.kt b/Server/src/main/content/region/morytania/handlers/AbandonedMineListeners.kt new file mode 100644 index 000000000..3c6a2cddc --- /dev/null +++ b/Server/src/main/content/region/morytania/handlers/AbandonedMineListeners.kt @@ -0,0 +1,150 @@ +package content.region.morytania.handlers + +import core.api.animate +import core.api.forceMove +import core.api.forceWalk +import core.api.location +import core.api.teleport +import core.game.interaction.IntType +import core.game.interaction.InteractionListener +import core.game.world.map.Location +import org.rs09.consts.Scenery + +/* + * This covers general listeners for the Abandoned Mine that aren't part of the Haunted Mine quest. + * + * Outside mine: Region 13618 - 3442 3254 0 + * Mine level 1: Region 13718 - 3426 9636 0 + * Mine level 2: Region 11079 - 2792 4584 0 + * Mine level 3: Region 10822 - 2717 4502 0 + * Mine level 4: Region 11078 - 2761 4500 0 + * Mine level 5: Region 10821 - 2723 4550 0 + * Mine level 6: Region 11077 - 2805 4455 0 + * + * */ + +class AbandonedMineListeners : InteractionListener { + + override fun defineListeners() { + + // stairs that go to level 2. the doors down there require the crystal mine key to unlock. + on(Scenery.STAIRS_4919, IntType.SCENERY, "Walk-down") { player, node -> + teleport(player, Location.create(2792, 4592, 0)) + } + + // stairs that go from level 2 to outside. the doors on level 2 require the crystal mine key to unlock. + on(Scenery.STAIRS_4923, IntType.SCENERY, "Walk-up") { player, node -> + teleport(player, Location.create(3453, 3242, 0)) + } + + // minecart to climb over to get to mine entrance + on(Scenery.MINE_CART_4918, IntType.SCENERY, "Climb-over") { player, node -> + //todo check agility + //todo fix the animation + if (player.location == node.location.transform(-1, 0, 0)) { + forceMove(player, node.location.transform(-1, 0, 0), node.location.transform(1, 0, 0), 1, 1, null, 839) + } else if (player.location == node.location.transform(1, 0, 0)) { + forceMove(player, node.location.transform(1, 0, 0), node.location.transform(-1, 0, 0), 1, 1, null, 839) + } + return@on true + } + + // entrance to Tarn's Lair + // ::setvarp 382 0 11 to finish haunted mine and activate entrance. + // ::setvarp 382 0 0 to reset haunted mine. + on(Scenery.ENTRANCE_20527, IntType.SCENERY, "Enter") { player, node -> + teleport(player, Location.create(3166, 4547, 0)) + } + + // from tarn's lair back to mine + on(Scenery.PASSAGEWAY_20814, IntType.SCENERY, "Enter") { player, node -> + teleport(player, Location.create(3424, 9660, 0)) + } + + // entrance from outside (main) to mine level 1 + on(Scenery.CART_TUNNEL_4913, IntType.SCENERY, "Crawl-down") { player, node -> + animate(player, 844) + teleport(player, Location.create(3436, 9637, 0)) + } + + // mine level 1 back to entrance + on(Scenery.CART_TUNNEL_4920, IntType.SCENERY, "Crawl-through") { player, node -> + animate(player, 844) + teleport(player, Location.create(3441, 3232, 0)) + } + + // mine level 1 to outside (west) + on(Scenery.CART_TUNNEL_4921, IntType.SCENERY, "Crawl-through") { player, node -> + animate(player, 844) + teleport(player, Location.create(3429, 3233, 0)) + } + + // mine level 1 to outside (west) + on(Scenery.CART_TUNNEL_20524, IntType.SCENERY, "Crawl-through") { player, node -> + animate(player, 844) + teleport(player, Location.create(3428, 3225, 0)) + } + + // outside (west) to mine level 1 + on(Scenery.CART_TUNNEL_4914, IntType.SCENERY, "Crawl-down") { player, node -> + animate(player, 844) + teleport(player, Location.create(3405, 9631, 0)) + } + + // outside (west) to mine level 1 + on(Scenery.CART_TUNNEL_4915, IntType.SCENERY, "Crawl-down") { player, node -> + animate(player, 844) + teleport(player, Location.create(3409, 9623, 0)) + } + + // mine level 1 to mine level 2 + on(Scenery.LADDER_4965, IntType.SCENERY, "Climb-down") { player, node -> + // ladder 4965 is reused in two locations, so we have to see which one the player is interacting with + val loc = player.location + + // Check around a 1-tile radius of the north ladder + if (loc.z == 0 && + loc.x in 3412..3414 && + loc.y in 9632..9634) { + + animate(player, 828) + teleport(player, Location.create(2774, 4577, 0)) + + // Check around a 1-tile radius of the south ladder + } else if (loc.z == 0 && + loc.x in 3421..3423 && + loc.y in 9624..9626) { + + animate(player, 828) + teleport(player, Location.create(2783, 4569, 0)) + } + + return@on true + } + + // mine level 2 to mine level 1 + on(Scenery.LADDER_4966, IntType.SCENERY, "Climb-up") { player, node -> + // ladder 4965 is reused in two locations, so we have to see which one the player is interacting with + val loc = player.location + + // Check around a 1-tile radius of the north ladder + if (loc.z == 0 && + loc.x in 2772..2774 && + loc.y in 4576..4578) { + + animate(player, 828) + teleport(player, Location.create(3412, 9633, 0)) + + // Check around a 1-tile radius of the south ladder + } else if (loc.z == 0 && + loc.x in 2781..2783 && + loc.y in 4568..4570) { + + animate(player, 828) + teleport(player, Location.create(3422, 9624, 0)) + } + + return@on true + } + } +} \ No newline at end of file diff --git a/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMine.kt b/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMine.kt new file mode 100644 index 000000000..b01d64190 --- /dev/null +++ b/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMine.kt @@ -0,0 +1,139 @@ +package content.region.morytania.quest.hauntedmine + +import content.data.Quests +import core.api.* +import core.game.node.entity.player.link.quest.Quest +import core.game.node.entity.player.Player +import core.game.node.entity.skill.Skills +import core.plugin.Initializable +import org.rs09.consts.Items + +/* + * Haunted Mine Quest + * + * Some of the sources used: + * https://www.youtube.com/watch?v=g3F4tC1KOck (primary) + * https://www.youtube.com/watch?v=CD77NeKz1J4 (secondary) + * https://web.archive.org/web/20081216051045/http://runescape.wikia.com/wiki/Haunted_Mine + * + */ + +// todo re-add terror dogs (and wall beasts?) to slayer tasks once done with this quest and tarns' lair. + +// todo check meleeswinghandler to verify salve att bonus, salve damage bonus, and salve undead targets. + +// Output of ./get-varp.sh 72 +// if (VARP[382] == 11) return 2; if (VARP[382] == 0) return 0; return 1; }; if (arg0 == 41) + +@Initializable +class HauntedMine : Quest(Quests.HAUNTED_MINE,73 ,72 ,2 ,382, 0, 1, 11) { + + companion object { + const val questName = "Haunted Mine" + + const val attributeKilledTreusDayth = "/save:quest:hauntedmine-killedtreusdayth" // True after you've killed Treus Dayth. + const val attributeKeyMentioned = "/save:quest:hauntedmine-keymentioned" // True after the player asks about a way into the mines. + } + + // Quest Journal ref: https://youtu.be/CD77NeKz1J4?si=AxNEg5YZU5oJ3T11&t=231 + // The video fragment matches the current RS3 journal: https://runescape.wiki/w/Transcript:Haunted_Mine/Journal + override fun drawJournal(player: Player, stage: Int) { + super.drawJournal(player, stage) + var line = 12 + var stage = getStage(player) + + var started = getQuestStage(player, Quests.HAUNTED_MINE) > 0 + + if(!started){ + line(player, "I can start this quest by speaking to the !!Zealot?? at the", line++, false) + line(player, "entrance of the Abandoned Mine in south !!Morytania??.", line++, false) + line(player, "I must be able to defeat a !!level 95 monster??, and need the", line++, false) // git gud + line(player, "following skill levels:", line++, false) + line(player, "Level 35 Crafting", line++, hasLevelStat(player, Skills.CRAFTING, 35)) // to cut a salve shard from the crystal outcrop + line(player, "Level 15 Agility", line++, hasLevelStat(player, Skills.AGILITY, 15)) // to go over a minecart at the entrance to the mine + line(player, "I also need to have completed the following quests:", line++, false) + line(player, "Priest in Peril", line++, isQuestComplete(player, Quests.PRIEST_IN_PERIL)) // to be able to access Morytania + limitScrolling(player, line, true) + } + if(stage >= 1) { // set stage 1 after talking to Zealot. + line(player, "I met a fanatic Saradominist just outside the Morytanian", line++, stage > 1) + line(player, "mines. He told me that the mines had been sealed, but", line++, stage > 1) + line(player, "contained within them !!crystals?? of a great power over evil.", line++, stage > 1) + } + if (stage >= 2) { // set stage 2 after first entering the mine. + line(player, "I managed to get into the mines via a thin tunnel high up in", line++, stage > 2) + line(player, "the mountains.", line++, stage > 2) + } + if (stage >= 3) { // set stage 3 after entering level 4 (fungus and cart level) + line(player, "Now I must reach the !!lower levels?? where apparently the", line++, stage > 3) + line(player, "!!crystals?? can be found.", line++, stage > 3) + } + if (stage >= 4) { // set stage 4 after going down the lift to level 5 + line(player, "I managed to start the !!lift?? which allowed me to get to", line++, stage > 4) + line(player, "the !!lower levels??.", line++, stage > 4) + line(player, "Now I can continue my search for the !!crystals??.", line++, stage > 4) + } + if (stage >= 5) { // set stage 5 if you go down to level 6 without a fungus. + line(player, "The !!lower levels?? of the mine were too !!dark?? to navigate.", line++, stage > 5) + } + if (stage >= 6) { // set stage 6 if you go down to level 6 with a fungus. + line(player, "I had to use a !!glowing fungus?? from the upper levels", line++, stage > 6) + line(player, "to !!Light?? the way.", line++, stage > 6) + } + if (stage >= 7) { // set stage 7 after you've killed dayth. + line(player, "I found a !!key?? in the !!lower levels??. I had to fight a", line++, stage > 7) + line(player, "powerful !!ghost?? who tried to prevent me taking it.", line++, stage > 7) + } + if (stage >= 8) { // set stage 8 after you cut a shard. + line(player, "I used this !!key?? to reach the legendary !!crystals??, from", line++, stage > 8) + line(player, "which I cut a !!salve shard?? to aid in fighting the undead.", line++, stage > 8) + } + if (stage >= 100) { // complete quest after you've cut a shard. + line++ + line(player,"QUEST COMPLETE!", line++, false) + } + limitScrolling(player, line, false) + } + + override fun reset(player: Player) { + removeAttribute(player, attributeKilledTreusDayth) + + setVarbit(player, 382, 0, true) // resets the quest and closes tarn's door. + } + + override fun setStage(player: Player, stage: Int) { + super.setStage(player, stage) + this.updateVarps(player) + } + + override fun updateVarps(player: Player) { + + // Stage Varbits + if(getQuestStage(player, Quests.HAUNTED_MINE) == 0) { + setVarbit(player, 382, 0, true) // marks quest as red + } + if(getQuestStage(player, Quests.HAUNTED_MINE) >= 100) { + setVarbit(player, 382, 1, true) // marks quest as yellow + } + if(getQuestStage(player, Quests.HAUNTED_MINE) >= 100) { + setVarbit(player, 382, 11, true) // marks quest as green and opens tarn's door + } + } + + override fun finish(player: Player) { + var ln = 10 + super.finish(player) + player.packetDispatch.sendString("You have completed the Haunted Mine Quest!", 277, 4) + player.packetDispatch.sendItemZoomOnInterface(Items.SALVE_AMULET_4081,230,277,5) + + drawReward(player, "2 quest points", ln++) + drawReward(player, "22,000 Strength XP", ln++) + drawReward(player, "Access to Tarn's Lair", ln++) + + rewardXP(player, Skills.STRENGTH, 22000.0) + } + + override fun newInstance(`object`: Any?): Quest { + return this + } +} \ No newline at end of file diff --git a/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMineListeners.kt b/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMineListeners.kt new file mode 100644 index 000000000..7b8ae397c --- /dev/null +++ b/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMineListeners.kt @@ -0,0 +1,19 @@ +package content.region.morytania.quest.hauntedmine + +import core.api.* +import core.game.interaction.InteractionListener +import org.rs09.consts.Items + +class HauntedMineListeners : InteractionListener { + + override fun defineListeners() { + + onUseWith(ITEM, Items.SALVE_SHARD_4082, Items.BALL_OF_WOOL_1759) { player, used, _ -> + removeItem(player, Items.SALVE_SHARD_4082) + removeItem(player, Items.BALL_OF_WOOL_1759) + addItem(player, Items.SALVE_AMULET_4081) + sendMessage(player, "You string the salve amulet.") + return@onUseWith true + } + } +} \ No newline at end of file diff --git a/Server/src/main/content/region/morytania/quest/hauntedmine/ZealotDialogue.kt b/Server/src/main/content/region/morytania/quest/hauntedmine/ZealotDialogue.kt new file mode 100644 index 000000000..a1237ca1c --- /dev/null +++ b/Server/src/main/content/region/morytania/quest/hauntedmine/ZealotDialogue.kt @@ -0,0 +1,108 @@ +package content.region.morytania.quest.hauntedmine + +import content.data.Quests +import core.api.* +import core.game.dialogue.* +import core.game.node.entity.player.Player +import core.plugin.Initializable +import core.tools.END_DIALOGUE +import org.rs09.consts.Items +import org.rs09.consts.NPCs + +@Initializable +class ZealotDialogue (player: Player? = null) : DialoguePlugin(player) { + override fun handle(interfaceId: Int, buttonId: Int): Boolean { + openDialogue(player, ZealotDialogueFile(), npc) + return true + } + override fun newInstance(player: Player): DialoguePlugin { + return ZealotDialogue(player) + } + override fun getIds(): IntArray { + return intArrayOf(NPCs.ZEALOT_1528) + } +} + +// Dialogue formatted mostly by ovenbread's scriptConvert.html +class ZealotDialogueFile : DialogueFile() { + override fun handle(componentID: Int, buttonID: Int) { + when (getQuestStage(player!!, Quests.HAUNTED_MINE)){ + + // dialogue before starting the quest + 0 -> when (stage) { + 0 -> playerl(FacialExpression.FRIENDLY, "Hello there.").also { stage++ } + 1 -> npcl(FacialExpression.FRIENDLY, "State thy allegiance stranger.").also { stage++ } + 2 -> showTopics( + Topic(FacialExpression.FRIENDLY, "I follow the path of Saradomin.", 3), + Topic(FacialExpression.FRIENDLY, "I serve only Zamorak.", 11), + Topic(FacialExpression.FRIENDLY, "My beliefs are in accord with the teachings of Guthix.", 21), + Topic(FacialExpression.FRIENDLY, "I have no particular allegiance.", 27), + ) + 3 -> npcl(FacialExpression.FRIENDLY, "Ah, a wise choice my friend. But if you truly follow Saradomin, what brings you to these evil lands?").also { stage++ } + 4 -> showTopics( + ) + 5 -> npcl(FacialExpression.FRIENDLY, "A noble cause indeed. One that I can sympathise with, for I myself am upon a quest. One that will allow Saradomin to be glorified even in these dark lands.").also { stage++ } + 6 -> npcl(FacialExpression.FRIENDLY, "Then leave me, I have no time to listen to your poisonous tongue.").also { stage++ } + 7 -> npcl(FacialExpression.FRIENDLY, "Saradomin has granted you wisdom. The evil creatures of this land are cunning and you are right to question anyone's purposes here. I am upon a quest. One that will allow Saradomin to be glorified even in these dark lands.").also { stage++ } + 8 -> npcl(FacialExpression.FRIENDLY, "A noble cause indeed. One that I can sympathise with, for I myself am upon a quest. One that will allow Saradomin to be glorified even in these dark lands.").also { stage++ } + 9 -> npcl(FacialExpression.FRIENDLY, "Then leave me, I have no time to listen to your poisonous tongue.").also { stage++ } + 10 -> npcl(FacialExpression.FRIENDLY, "Saradomin has granted you wisdom. The evil creatures of this land are cunning and you are right to question anyone's purposes here. I am upon a quest. One that will allow Saradomin to be glorified even in these dark lands.").also { + stage = END_DIALOGUE + } + 11 -> npcl(FacialExpression.FRIENDLY, "Then begone. Normally I would strike you down in an instant, but for now I have no time. I am on a quest of the utmost importance.").also { stage++ } + 12 -> showTopics( + Topic(FacialExpression.FRIENDLY, "What is this quest of which you speak?", 13), + Topic(FacialExpression.FRIENDLY, "Fine, I didn't want to talk to you either.", 16), + ) + 13 -> npcl(FacialExpression.FRIENDLY, "It is no concern of yours, but rest assured it will help in crushing you and those others who serve your vile master.").also { stage++ } + 14 -> playerl(FacialExpression.FRIENDLY, "I doubt that.").also { stage++ } + 15 -> npcl(FacialExpression.FRIENDLY, "I would expect nothing less of you, misguided as you already are.").also { + stage = END_DIALOGUE + } + 16 -> npcl(FacialExpression.FRIENDLY, "Fear not fiend, even though I may leave you be, you shall not escape justice at the hands of the righteous.").also { stage++ } + 17 -> npcl(FacialExpression.FRIENDLY, "It is no concern of yours, but rest assured it will help in crushing you and those others who serve your vile master.").also { stage++ } + 18 -> playerl(FacialExpression.FRIENDLY, "I doubt that.").also { stage++ } + 19 -> npcl(FacialExpression.FRIENDLY, "I would expect nothing less of you, misguided as you already are.").also { stage++ } + 20 -> npcl(FacialExpression.FRIENDLY, "Fear not fiend, even though I may leave you be, you shall not escape justice at the hands of the righteous.").also { + stage = END_DIALOGUE + } + 21 -> npcl(FacialExpression.FRIENDLY, "A wishy washy set of beliefs. You should follow Saradomin and find a real purpose in your life.").also { stage++ } + 22 -> showTopics( + Topic(FacialExpression.FRIENDLY, "And what sort of purpose would that be?", 23), + Topic(FacialExpression.FRIENDLY, "I can make my own choices.", 24), + ) + 23 -> npcl(FacialExpression.FRIENDLY, "To further the glory of Saradomin of course. Take myself, I am upon a quest that will allow Saradomin to be glorified even in these dark lands.").also { + stage = END_DIALOGUE + } + 24 -> npcl(FacialExpression.FRIENDLY, "I look only to help those who are misguided.").also { stage++ } + 25 -> npcl(FacialExpression.FRIENDLY, "To further the glory of Saradomin of course. Take myself, I am upon a quest that will allow Saradomin to be glorified even in these dark lands.").also { stage++ } + 26 -> npcl(FacialExpression.FRIENDLY, "I look only to help those who are misguided.").also { + stage = END_DIALOGUE + } + 27 -> npcl(FacialExpression.FRIENDLY, "Then your life is without reason or direction. I would talk to you further on this matter, but for now my attentions must be elsewhere.").also { stage++ } + 28 -> showTopics( + Topic(FacialExpression.FRIENDLY, "Then I shall leave you to your business.", 29), + Topic(FacialExpression.FRIENDLY, "Why, what are you doing?", 30), + ) + 29 -> npcl(FacialExpression.FRIENDLY, "I shall pray that Saradomin grants you the wisdom to see through your folly.").also { + stage = END_DIALOGUE + } + 30 -> npcl(FacialExpression.FRIENDLY, "I am upon a quest. One that will allow Saradomin to be glorified even in these dark lands.").also { stage++ } + 31 -> npcl(FacialExpression.FRIENDLY, "I shall pray that Saradomin grants you the wisdom to see through your folly.").also { stage++ } + 32 -> npcl(FacialExpression.FRIENDLY, "I am upon a quest. One that will allow Saradomin to be glorified even in these dark lands.").also { + stage = END_DIALOGUE + } + } + + // dialogue when quest is in progress + in 1..99 -> when (stage) { + 0 -> sendDialogue(player!!, "where crystal").also { stage = END_DIALOGUE } + } + + // dialogue after completing quest + 100 -> when (stage) { + 0 -> sendDialogue(player!!, "gz on the necklace").also { stage = END_DIALOGUE } + } + } + } +} \ No newline at end of file diff --git a/Server/src/main/core/game/requirement/Requirement.kt b/Server/src/main/core/game/requirement/Requirement.kt index d43b68dac..5937d3dbd 100644 --- a/Server/src/main/core/game/requirement/Requirement.kt +++ b/Server/src/main/core/game/requirement/Requirement.kt @@ -126,7 +126,7 @@ enum class QuestRequirements(val quest: Quests, vararg val requirements: Require HORROR_DEEP (Quests.HORROR_FROM_THE_DEEP, SkillReq(Skills.AGILITY, 35, true)), THRONE (Quests.THRONE_OF_MISCELLANIA, QuestReq(HERO), QuestReq(FREM_TRIALS)), MONKEY (Quests.MONKEY_MADNESS, QuestReq(GRAND_TREE), QuestReq(GNOME_VILLAGE)), - MINE (Quests.HAUNTED_MINE, QuestReq(PRIEST), SkillReq(Skills.CRAFTING, 35, true)), + MINE (Quests.HAUNTED_MINE, QuestReq(PRIEST), SkillReq(Skills.CRAFTING, 35, true), SkillReq(Skills.AGILITY, 15, true)), TROLL_ROMANCE (Quests.TROLL_ROMANCE, QuestReq(TROLL_STRONGHOLD), SkillReq(Skills.AGILITY, 28, true)), SEARCH_MYREQUE (Quests.IN_SEARCH_OF_THE_MYREQUE, QuestReq(NATURE_SPIRIT), SkillReq(Skills.AGILITY, 25, true)), FENKENSTRAIN (Quests.CREATURE_OF_FENKENSTRAIN, QuestReq(PRIEST), QuestReq(RESTLESS_GHOST), SkillReq(Skills.THIEVING, 25, true), SkillReq(Skills.CRAFTING, 20, true)), From a8becdf020e5aa6433faca591f062ca7c54cecde Mon Sep 17 00:00:00 2001 From: aidan Date: Tue, 2 Dec 2025 11:49:48 -0600 Subject: [PATCH 2/7] zealot start of quest dialogue is done --- .../handlers/AbandonedMineListeners.kt | 21 +- .../quest/hauntedmine/HauntedMine.kt | 21 +- .../quest/hauntedmine/HauntedMineListeners.kt | 34 ++ .../quest/hauntedmine/ZealotDialogue.kt | 474 ++++++++++++++++-- 4 files changed, 481 insertions(+), 69 deletions(-) diff --git a/Server/src/main/content/region/morytania/handlers/AbandonedMineListeners.kt b/Server/src/main/content/region/morytania/handlers/AbandonedMineListeners.kt index 3c6a2cddc..9c35dfdf0 100644 --- a/Server/src/main/content/region/morytania/handlers/AbandonedMineListeners.kt +++ b/Server/src/main/content/region/morytania/handlers/AbandonedMineListeners.kt @@ -63,37 +63,38 @@ class AbandonedMineListeners : InteractionListener { // entrance from outside (main) to mine level 1 on(Scenery.CART_TUNNEL_4913, IntType.SCENERY, "Crawl-down") { player, node -> - animate(player, 844) + //todo fix all these animations and make them play before teleporting + animate(player, 844, true) teleport(player, Location.create(3436, 9637, 0)) } // mine level 1 back to entrance on(Scenery.CART_TUNNEL_4920, IntType.SCENERY, "Crawl-through") { player, node -> - animate(player, 844) + animate(player, 844, true) teleport(player, Location.create(3441, 3232, 0)) } // mine level 1 to outside (west) on(Scenery.CART_TUNNEL_4921, IntType.SCENERY, "Crawl-through") { player, node -> - animate(player, 844) + animate(player, 844, true) teleport(player, Location.create(3429, 3233, 0)) } // mine level 1 to outside (west) on(Scenery.CART_TUNNEL_20524, IntType.SCENERY, "Crawl-through") { player, node -> - animate(player, 844) + animate(player, 844, true) teleport(player, Location.create(3428, 3225, 0)) } // outside (west) to mine level 1 on(Scenery.CART_TUNNEL_4914, IntType.SCENERY, "Crawl-down") { player, node -> - animate(player, 844) + animate(player, 844, true) teleport(player, Location.create(3405, 9631, 0)) } // outside (west) to mine level 1 on(Scenery.CART_TUNNEL_4915, IntType.SCENERY, "Crawl-down") { player, node -> - animate(player, 844) + animate(player, 844, true) teleport(player, Location.create(3409, 9623, 0)) } @@ -107,7 +108,7 @@ class AbandonedMineListeners : InteractionListener { loc.x in 3412..3414 && loc.y in 9632..9634) { - animate(player, 828) + animate(player, 828, true) teleport(player, Location.create(2774, 4577, 0)) // Check around a 1-tile radius of the south ladder @@ -115,7 +116,7 @@ class AbandonedMineListeners : InteractionListener { loc.x in 3421..3423 && loc.y in 9624..9626) { - animate(player, 828) + animate(player, 828, true) teleport(player, Location.create(2783, 4569, 0)) } @@ -132,7 +133,7 @@ class AbandonedMineListeners : InteractionListener { loc.x in 2772..2774 && loc.y in 4576..4578) { - animate(player, 828) + animate(player, 828, true) teleport(player, Location.create(3412, 9633, 0)) // Check around a 1-tile radius of the south ladder @@ -140,7 +141,7 @@ class AbandonedMineListeners : InteractionListener { loc.x in 2781..2783 && loc.y in 4568..4570) { - animate(player, 828) + animate(player, 828, true) teleport(player, Location.create(3422, 9624, 0)) } diff --git a/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMine.kt b/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMine.kt index b01d64190..e217953a7 100644 --- a/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMine.kt +++ b/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMine.kt @@ -12,8 +12,9 @@ import org.rs09.consts.Items * Haunted Mine Quest * * Some of the sources used: - * https://www.youtube.com/watch?v=g3F4tC1KOck (primary) - * https://www.youtube.com/watch?v=CD77NeKz1J4 (secondary) + * Primary Source (March 2008): https://www.youtube.com/watch?v=g3F4tC1KOck + * Secondary source (May 2009): https://www.youtube.com/watch?v=CD77NeKz1J4 + * Secondary source (Feb 2009): https://www.youtube.com/watch?v=PMn0LRo4MCo * https://web.archive.org/web/20081216051045/http://runescape.wikia.com/wiki/Haunted_Mine * */ @@ -36,6 +37,7 @@ class HauntedMine : Quest(Quests.HAUNTED_MINE,73 ,72 ,2 ,382, 0, 1, 11) { } // Quest Journal ref: https://youtu.be/CD77NeKz1J4?si=AxNEg5YZU5oJ3T11&t=231 + // Contains pre-starting journal entry: https://www.youtube.com/watch?v=PMn0LRo4MCo // The video fragment matches the current RS3 journal: https://runescape.wiki/w/Transcript:Haunted_Mine/Journal override fun drawJournal(player: Player, stage: Int) { super.drawJournal(player, stage) @@ -45,14 +47,13 @@ class HauntedMine : Quest(Quests.HAUNTED_MINE,73 ,72 ,2 ,382, 0, 1, 11) { var started = getQuestStage(player, Quests.HAUNTED_MINE) > 0 if(!started){ - line(player, "I can start this quest by speaking to the !!Zealot?? at the", line++, false) - line(player, "entrance of the Abandoned Mine in south !!Morytania??.", line++, false) - line(player, "I must be able to defeat a !!level 95 monster??, and need the", line++, false) // git gud - line(player, "following skill levels:", line++, false) - line(player, "Level 35 Crafting", line++, hasLevelStat(player, Skills.CRAFTING, 35)) // to cut a salve shard from the crystal outcrop - line(player, "Level 15 Agility", line++, hasLevelStat(player, Skills.AGILITY, 15)) // to go over a minecart at the entrance to the mine - line(player, "I also need to have completed the following quests:", line++, false) - line(player, "Priest in Peril", line++, isQuestComplete(player, Quests.PRIEST_IN_PERIL)) // to be able to access Morytania + line(player, "I can start this quest by speaking to the !!Saradominist??", line++, false) + line(player, "!!Zealot?? outside the !!mines of Morytania??.", line++, false) + line(player, "To complete this quest I need:", line++, false) + line(player, "Level 15 Agility.", line++, hasLevelStat(player, Skills.AGILITY, 15)) // to go over a minecart at the entrance to the mine + line(player, "Level 35 Crafting.", line++, hasLevelStat(player, Skills.CRAFTING, 35)) // to cut a salve shard from the crystal outcrop + line(player, "Access to Morytania.", line++, isQuestComplete(player, Quests.PRIEST_IN_PERIL)) // to be able to access Morytania + line(player, "I must be able to !!defeat a level 95 enemy.??", line++, false) // git gud limitScrolling(player, line, true) } if(stage >= 1) { // set stage 1 after talking to Zealot. diff --git a/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMineListeners.kt b/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMineListeners.kt index 7b8ae397c..829c956f2 100644 --- a/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMineListeners.kt +++ b/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMineListeners.kt @@ -1,8 +1,15 @@ package content.region.morytania.quest.hauntedmine +import content.region.morytania.quest.hauntedmine.HauntedMine.Companion.attributeKeyMentioned import core.api.* +import core.game.interaction.IntType import core.game.interaction.InteractionListener +import core.game.node.item.Item +import core.game.system.task.Pulse +import core.game.world.GameWorld +import core.game.world.update.flag.context.Animation import org.rs09.consts.Items +import org.rs09.consts.NPCs class HauntedMineListeners : InteractionListener { @@ -15,5 +22,32 @@ class HauntedMineListeners : InteractionListener { sendMessage(player, "You string the salve amulet.") return@onUseWith true } + + on(NPCs.ZEALOT_1528, IntType.NPC, "pickpocket"){ player, node -> + if(getAttribute(player, attributeKeyMentioned, false) && !player.inventory.containsItem(Item(Items.ZEALOTS_KEY_4078))){ + player.lock() + GameWorld.Pulser.submit(object : Pulse(){ + var counter = 0 + override fun pulse(): Boolean { + when(counter++){ + 0 -> player.animator.animate(Animation(881)) + 3 -> { + + player.unlock() + return true + } + } + return false + } + }) + addItemOrDrop(player, Items.ZEALOTS_KEY_4078) + sendMessage(player, "You pick the zealot's pocket and retrieve a small silvery key.") + } else if(getAttribute(player, attributeKeyMentioned, false) && player.inventory.containsItem(Item(Items.ZEALOTS_KEY_4078))) { + sendMessage(player, "I've already picked his pockets.") + } else { + sendMessage(player, "I doubt he's got much of value on him.") + } + return@on true + } } } \ No newline at end of file diff --git a/Server/src/main/content/region/morytania/quest/hauntedmine/ZealotDialogue.kt b/Server/src/main/content/region/morytania/quest/hauntedmine/ZealotDialogue.kt index a1237ca1c..876757fd7 100644 --- a/Server/src/main/content/region/morytania/quest/hauntedmine/ZealotDialogue.kt +++ b/Server/src/main/content/region/morytania/quest/hauntedmine/ZealotDialogue.kt @@ -1,6 +1,9 @@ package content.region.morytania.quest.hauntedmine import content.data.Quests +import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributeAskPoisonAnna +import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributePoisonClue +import content.region.morytania.quest.hauntedmine.HauntedMine.Companion.attributeKeyMentioned import core.api.* import core.game.dialogue.* import core.game.node.entity.player.Player @@ -23,85 +26,458 @@ class ZealotDialogue (player: Player? = null) : DialoguePlugin(player) { } } -// Dialogue formatted mostly by ovenbread's scriptConvert.html +// If you ask "Where is the plugin for space to skip dialogue?" I will send you a sternly-worded +// message on why you should appreciate this bespoke, small-batch, hand-crafted dialogue. >:( class ZealotDialogueFile : DialogueFile() { override fun handle(componentID: Int, buttonID: Int) { - when (getQuestStage(player!!, Quests.HAUNTED_MINE)){ + when (getQuestStage(player!!, Quests.MURDER_MYSTERY)) { // dialogue before starting the quest 0 -> when (stage) { - 0 -> playerl(FacialExpression.FRIENDLY, "Hello there.").also { stage++ } - 1 -> npcl(FacialExpression.FRIENDLY, "State thy allegiance stranger.").also { stage++ } + 0 -> playerl(FacialExpression.NEUTRAL, "Hello there.").also { stage++ } + 1 -> npcl(FacialExpression.NEUTRAL, "State thy allegiance stranger.").also { stage++ } 2 -> showTopics( - Topic(FacialExpression.FRIENDLY, "I follow the path of Saradomin.", 3), - Topic(FacialExpression.FRIENDLY, "I serve only Zamorak.", 11), - Topic(FacialExpression.FRIENDLY, "My beliefs are in accord with the teachings of Guthix.", 21), - Topic(FacialExpression.FRIENDLY, "I have no particular allegiance.", 27), + Topic("I follow the path of Saradomin.", 3, true), + Topic("I serve only Zamorak.", 12, true), + Topic("My beliefs are in accord with the teachings of Guthix.", 19, true), + Topic("I have no particular allegiance.", 26, true), ) - 3 -> npcl(FacialExpression.FRIENDLY, "Ah, a wise choice my friend. But if you truly follow Saradomin, what brings you to these evil lands?").also { stage++ } - 4 -> showTopics( + + 3 -> playerl( + FacialExpression.NEUTRAL, + "I follow the path of Saradomin. Strength through wisdom." + ).also { stage++ } + + 4 -> npcl( + FacialExpression.NEUTRAL, + "Ah, a wise choice my friend. But if you truly follow Saradomin, what brings you to these evil lands?" + ).also { stage++ } + + 5 -> showTopics( + Topic("I come seeking challenges and quests.", 6, true), + Topic("Ok I lied.", 8, true), + Topic("I could ask the same of you.", 10, true), ) - 5 -> npcl(FacialExpression.FRIENDLY, "A noble cause indeed. One that I can sympathise with, for I myself am upon a quest. One that will allow Saradomin to be glorified even in these dark lands.").also { stage++ } - 6 -> npcl(FacialExpression.FRIENDLY, "Then leave me, I have no time to listen to your poisonous tongue.").also { stage++ } - 7 -> npcl(FacialExpression.FRIENDLY, "Saradomin has granted you wisdom. The evil creatures of this land are cunning and you are right to question anyone's purposes here. I am upon a quest. One that will allow Saradomin to be glorified even in these dark lands.").also { stage++ } - 8 -> npcl(FacialExpression.FRIENDLY, "A noble cause indeed. One that I can sympathise with, for I myself am upon a quest. One that will allow Saradomin to be glorified even in these dark lands.").also { stage++ } - 9 -> npcl(FacialExpression.FRIENDLY, "Then leave me, I have no time to listen to your poisonous tongue.").also { stage++ } - 10 -> npcl(FacialExpression.FRIENDLY, "Saradomin has granted you wisdom. The evil creatures of this land are cunning and you are right to question anyone's purposes here. I am upon a quest. One that will allow Saradomin to be glorified even in these dark lands.").also { + + 6 -> playerl(FacialExpression.NEUTRAL, "I come seeking challenges and quests.").also { stage++ } + 7 -> npcl( + FacialExpression.NEUTRAL, + "A noble cause indeed. One that I can sympathise with, for I myself am upon a quest. One that will allow Saradomin to be glorified even in these dark lands." + ).also { + stage = 31 + } + + 8 -> playerl( + FacialExpression.NEUTRAL, + "Ok I lied, I don't support Saradomin. I'm only here for dastardly evil purposes." + ).also { stage++ } + + 9 -> npcl( + FacialExpression.NEUTRAL, + "Then leave me, I have no time to listen to your poisonous tongue." + ).also { stage = END_DIALOGUE } - 11 -> npcl(FacialExpression.FRIENDLY, "Then begone. Normally I would strike you down in an instant, but for now I have no time. I am on a quest of the utmost importance.").also { stage++ } - 12 -> showTopics( - Topic(FacialExpression.FRIENDLY, "What is this quest of which you speak?", 13), - Topic(FacialExpression.FRIENDLY, "Fine, I didn't want to talk to you either.", 16), + + 10 -> playerl(FacialExpression.NEUTRAL, "I could ask the same of you.").also { stage++ } + 11 -> npcl( + FacialExpression.NEUTRAL, + "Saradomin has granted you wisdom. The evil creatures of this land are cunning and you are right to question anyone's purposes here. I am upon a quest. One that will allow Saradomin to be glorified even in these dark lands." + ).also { + stage = 31 + } + + 12 -> playerl( + FacialExpression.NEUTRAL, + "I serve only Zamorak. Strength through chaos." + ).also { stage++ } + + 13 -> npcl( + FacialExpression.NEUTRAL, + "Then begone. Normally I would strike you down in an instant, but for now I have no time. I am on a quest of the utmost importance." + ).also { stage++ } + + 14 -> showTopics( + Topic(FacialExpression.NEUTRAL, "What is this quest of which you speak?", 15), + Topic(FacialExpression.NEUTRAL, "Fine, I didn't want to talk to you either.", 18), ) - 13 -> npcl(FacialExpression.FRIENDLY, "It is no concern of yours, but rest assured it will help in crushing you and those others who serve your vile master.").also { stage++ } - 14 -> playerl(FacialExpression.FRIENDLY, "I doubt that.").also { stage++ } - 15 -> npcl(FacialExpression.FRIENDLY, "I would expect nothing less of you, misguided as you already are.").also { + + 15 -> npcl( + FacialExpression.NEUTRAL, + "It is no concern of yours, but rest assured it will help in crushing you and those others who serve your vile master." + ).also { stage++ } + + 16 -> playerl(FacialExpression.NEUTRAL, "I doubt that.").also { stage++ } + 17 -> npcl( + FacialExpression.NEUTRAL, + "I would expect nothing less of you, misguided as you already are." + ).also { stage = END_DIALOGUE } - 16 -> npcl(FacialExpression.FRIENDLY, "Fear not fiend, even though I may leave you be, you shall not escape justice at the hands of the righteous.").also { stage++ } - 17 -> npcl(FacialExpression.FRIENDLY, "It is no concern of yours, but rest assured it will help in crushing you and those others who serve your vile master.").also { stage++ } - 18 -> playerl(FacialExpression.FRIENDLY, "I doubt that.").also { stage++ } - 19 -> npcl(FacialExpression.FRIENDLY, "I would expect nothing less of you, misguided as you already are.").also { stage++ } - 20 -> npcl(FacialExpression.FRIENDLY, "Fear not fiend, even though I may leave you be, you shall not escape justice at the hands of the righteous.").also { + + 18 -> npcl( + FacialExpression.NEUTRAL, + "Fear not fiend, even though I may leave you be, you shall not escape justice at the hands of the righteous." + ).also { stage = END_DIALOGUE } - 21 -> npcl(FacialExpression.FRIENDLY, "A wishy washy set of beliefs. You should follow Saradomin and find a real purpose in your life.").also { stage++ } - 22 -> showTopics( - Topic(FacialExpression.FRIENDLY, "And what sort of purpose would that be?", 23), - Topic(FacialExpression.FRIENDLY, "I can make my own choices.", 24), + + 19 -> playerl( + FacialExpression.NEUTRAL, + "My beliefs are in accord with the teachings of Guthix. Balance is power." + ).also { stage++ } + + 20 -> npcl( + FacialExpression.NEUTRAL, + "A wishy washy set of beliefs. You should follow Saradomin and find a real purpose in your life." + ).also { stage++ } + + 21 -> showTopics( + Topic("And what sort of purpose would that be?", 22, true), + Topic("I can make my own choices.", 24, true), ) - 23 -> npcl(FacialExpression.FRIENDLY, "To further the glory of Saradomin of course. Take myself, I am upon a quest that will allow Saradomin to be glorified even in these dark lands.").also { + + 22 -> playerl(FacialExpression.NEUTRAL, "And what sort of purpose would that be?").also { stage++ } + 23 -> npcl( + FacialExpression.NEUTRAL, + "To further the glory of Saradomin of course. Take myself, I am upon a quest that will allow Saradomin to be glorified even in these dark lands." + ).also { + stage = 31 + } + + 24 -> playerl( + FacialExpression.NEUTRAL, + "I can make my own choices, who are you to dispute them?" + ).also { stage++ } + + 25 -> npcl(FacialExpression.NEUTRAL, "I look only to help those who are misguided.").also { stage = END_DIALOGUE } - 24 -> npcl(FacialExpression.FRIENDLY, "I look only to help those who are misguided.").also { stage++ } - 25 -> npcl(FacialExpression.FRIENDLY, "To further the glory of Saradomin of course. Take myself, I am upon a quest that will allow Saradomin to be glorified even in these dark lands.").also { stage++ } - 26 -> npcl(FacialExpression.FRIENDLY, "I look only to help those who are misguided.").also { - stage = END_DIALOGUE - } - 27 -> npcl(FacialExpression.FRIENDLY, "Then your life is without reason or direction. I would talk to you further on this matter, but for now my attentions must be elsewhere.").also { stage++ } + + 26 -> playerl(FacialExpression.NEUTRAL, "I have no particular allegiance.").also { stage++ } + 27 -> npcl( + FacialExpression.NEUTRAL, + "Then your life is without reason or direction. I would talk to you further on this matter, but for now my attentions must be elsewhere." + ).also { stage++ } + 28 -> showTopics( - Topic(FacialExpression.FRIENDLY, "Then I shall leave you to your business.", 29), - Topic(FacialExpression.FRIENDLY, "Why, what are you doing?", 30), + Topic(FacialExpression.NEUTRAL, "Then I shall leave you to your business.", 29), + Topic(FacialExpression.NEUTRAL, "Why, what are you doing?", 30), ) - 29 -> npcl(FacialExpression.FRIENDLY, "I shall pray that Saradomin grants you the wisdom to see through your folly.").also { + + 29 -> npcl( + FacialExpression.NEUTRAL, + "I shall pray that Saradomin grants you the wisdom to see through your folly." + ).also { stage = END_DIALOGUE } - 30 -> npcl(FacialExpression.FRIENDLY, "I am upon a quest. One that will allow Saradomin to be glorified even in these dark lands.").also { stage++ } - 31 -> npcl(FacialExpression.FRIENDLY, "I shall pray that Saradomin grants you the wisdom to see through your folly.").also { stage++ } - 32 -> npcl(FacialExpression.FRIENDLY, "I am upon a quest. One that will allow Saradomin to be glorified even in these dark lands.").also { + + 30 -> npcl( + FacialExpression.NEUTRAL, + "I am upon a quest. One that will allow Saradomin to be glorified even in these dark lands." + ).also { stage++ } + + // first breakpoint. + 31 -> showTopics( + Topic(FacialExpression.NEUTRAL, "What quest is that then?", 32), + Topic(FacialExpression.NEUTRAL, "I hope it goes well. Goodbye.", 88), + ) + + 32 -> npcl( + FacialExpression.NEUTRAL, + "Well, below the very ground you stand upon lies an intricate network of tunnels that make up the abandoned Mort Ridge mines. These mines used to be a valuable resource to the inhabitants of Morytania." + ).also { stage++ } + + 33 -> npcl( + FacialExpression.NEUTRAL, + "As with many things, this changed when Misthalin was finally able to push the minions of Morytania back, and Saradomin himself blessed the river Salve." + ).also { stage++ } + + 34 -> npcl( + FacialExpression.NEUTRAL, + "The mines are also the site where the legendary artefact, the salve amulet, was thought to have been carved from the crystals that grow in the lower levels of the mine." + ).also { stage++ } + + 35 -> npcl( + FacialExpression.NEUTRAL, + "These crystals are thought to be formed by the blessed water of the river Salve as it percolates through the rocks to the lower levels of the mine." + ).also { stage++ } + + 36 -> npcl( + FacialExpression.NEUTRAL, + "It is not know what happened to the salve amulet, but it is generally believed that by encapsulating within it some of the goodness of Saradomin himself, it afforded the bearer power over evil." + ).also { stage++ } + + 37 -> npcl( + FacialExpression.NEUTRAL, + "Saradomin has entrusted me alone with the task of regaining access to the mines, whatever the dangers." + ).also { stage++ } + + 38 -> playerl(FacialExpression.NEUTRAL, "How can an abandoned mine be dangerous?").also { stage++ } + 39 -> npcl( + FacialExpression.NEUTRAL, + "Because the mines are said to be haunted. The crystals and the ridge used to be protected by Zamorak's mage, Treus Dayth." + ).also { stage++ } + + 40 -> npcl( + FacialExpression.NEUTRAL, + "Dayth failed and fell during and incursion by Saradominists, who then made it into the mines and were able to remove a shard of crystal." + ).also { stage++ } + + 41 -> npcl( + FacialExpression.NEUTRAL, + "Zamorak, furious at his mage, condemned Dayth's soul indefinitely to an existence of turmoil in the mines. Dayth's soul is bound to prevent the crystals from ever being reached again." + ).also { stage++ } + + 42 -> npcl( + FacialExpression.NEUTRAL, + "Further, Zamorak's then ruler upon the land ordered the slaughter of anyone within the mines and that the mines be sealed." + ).also { stage++ }.also { + setQuestStage(player!!, Quests.HAUNTED_MINE, 1) + } + // Haunted mine quest is now activated (stage 1) + + 43 -> showTopics( + Topic("Is there any other way into the mines?", 44, true), + Topic("How does a lost artefact that was only legendary help?", 77, true), + Topic("Why was everyone in the mines slaughtered?", 80, true), + Topic("I must be going now.", 86, true), + ) + + 44 -> playerl(FacialExpression.NEUTRAL, "Is there any other way into the mines?").also { stage++ } + 45 -> npcl( + FacialExpression.NEUTRAL, + "Indeed I have found hope that this may be so. By making discreet inquiries I have been led to believe that a second entrance may exist into the mines." + ).also { stage++ } + + 46 -> npcl( + FacialExpression.NEUTRAL, + "Further, I have come into possession of a key that will apparently afford entrance to the lower levels of the mines once inside." + ).also { stage++ }.also { + setAttribute(player!!, attributeKeyMentioned, true) + } + // the key has been mentioned, so you can pickpocket it now. + 47 -> showTopics( + Topic("Where is the second entrance to the mines?", 48, true), + Topic("How can you be discreet with THAT star emblazoned on your robes?", 51, true), + Topic("Can I borrow your key?", 63, true), + Topic("How does a lost artefact that was only legendary help?", 77, true), + Topic("Why was everyone in the mines slaughtered?", 80, true), + ) + + 48 -> playerl(FacialExpression.NEUTRAL, "Where is the second entrance to the mines?").also { stage++ } + 49 -> npcl( + FacialExpression.NEUTRAL, + "Of this I am not yet sure. From what I have been able to gather, it was not originally built for humans to enter by. Where it may be, I am still endeavoring to find out." + ).also { stage++ } + + 50 -> showTopics( + Topic("Can I borrow your key?", 63, true), + Topic("How does a lost artefact that was only legendary help?", 77, true), + Topic("Why was everyone in the mines slaughtered?", 80, true), + Topic("I must be going now.", 86, true), + ) + + 51 -> playerl( + FacialExpression.NEUTRAL, + "How can you be discreet with THAT star emblazoned on your robes?" + ).also { stage++ } + + 52 -> npcl( + FacialExpression.NEUTRAL, + "Saradomin watches over me, I am not troubled by those who are not meant to notice." + ).also { stage++ } + + 53 -> playerl( + FacialExpression.NEUTRAL, + "Even so, you're not exactly keeping quiet about your allegiance are you?" + ).also { stage++ } + + 54 -> npcl( + FacialExpression.NEUTRAL, + "Saradomin will protect me. Even if I should fall there are many behind me who would stand in my place." + ).also { stage++ } + + 55 -> showTopics( + Topic("Is that much consolation?", 56, true), + Topic("I can't see anyone behind you.", 58, true), + Topic("And I would be one of them. So, can I borrow that key?", 63, true), + Topic("You're right, I was wrong to doubt Saradomin.", 60, true), + Topic("You're nuts, goodbye.", 62, true), + + ) + + 56 -> playerl( + FacialExpression.NEUTRAL, + "Is that much consolation when you get chopped up into little pieces?" + ).also { stage++ } + + 57 -> npcl( + FacialExpression.NEUTRAL, + "I would rather be cut into little pieces whilst proclaiming the goodness of Saradomin than hiding my faith." + ).also { stage = END_DIALOGUE } + + 58 -> playerl(FacialExpression.NEUTRAL, "I can't see anyone behind you.").also { stage++ } + 59 -> npcl( + FacialExpression.NEUTRAL, + "Although you may not realise it, Saradomin works quietly in many people, such is the folly of looking with your eyes and not your heart." + ).also { stage = END_DIALOGUE } + + 60 -> playerl( + FacialExpression.NEUTRAL, + "You're right, I was wrong to doubt Saradomin." + ).also { stage++ } + + 61 -> npcl( + FacialExpression.NEUTRAL, + "Let not your faith in Saradomin falter, for all else is insignificant." + ).also { stage = END_DIALOGUE } + + 62 -> playerl(FacialExpression.NEUTRAL, "You're nuts, goodbye.").also { stage = END_DIALOGUE } + + 63 -> playerl(FacialExpression.NEUTRAL, "Can I borrow your key?").also { stage++ } + 64 -> npcl( + FacialExpression.NEUTRAL, + "I am afraid my task can be entrusted to nobody else. Saradomin has asked me alone to do this. I cannot take the slightest risk of losing this key. The stakes are too high." + ).also { stage++ } + + 65 -> showTopics( + Topic("Please? I'll be very careful with it.", 66, true), + Topic("I didn't want that key anyway.", 75, true), + ) + + 66 -> playerl(FacialExpression.NEUTRAL, "Please? I'll be very careful with it.").also { stage++ } + 67 -> npcl( + FacialExpression.NEUTRAL, + "You know not what you deal with. There is evil in that mine and, whatever your assurances, I cannot risk you falling to the creatures within." + ).also { stage++ } + + 68 -> showTopics( + Topic("And you think you'll be safer in the mine than me?", 69, true), + Topic("I'll trade for it.", 71, true), + Topic("Pretty pretty please?", 73, true), + Topic("I didn't want that key anyway.", 75, true), + ) + + 69 -> playerl( + FacialExpression.NEUTRAL, + "And you think you'll be safer in the mine than me?" + ).also { stage++ } + + 70 -> npcl( + FacialExpression.NEUTRAL, + "Of course I'll be safe, my faith in Saradomin protects me." + ).also { stage = END_DIALOGUE } + + 71 -> playerl(FacialExpression.NEUTRAL, "I'll trade for it.").also { stage++ } + 72 -> npcl( + FacialExpression.NEUTRAL, + "Saradomin provides for my every need. There is nothing you could offer me." + ).also { stage = END_DIALOGUE } + + 73 -> playerl(FacialExpression.NEUTRAL, "Pretty pretty please?").also { stage++ } + 74 -> npcl(FacialExpression.NEUTRAL, "Saradomin grant me patience. The answer is no.").also { stage = END_DIALOGUE } + + 75 -> playerl(FacialExpression.NEUTRAL, "I didn't want that key anyway.").also { stage++ } + 76 -> npcl( + FacialExpression.NEUTRAL, + "Witness the goodness of Saradomin, that he has granted you the wisdom to see our positions in perspective." + ).also { stage = END_DIALOGUE } + + 77 -> playerl( + FacialExpression.NEUTRAL, + "How does a lost artefact that was only legendary help?" + ).also { stage++ } + + 78 -> npcl( + FacialExpression.NEUTRAL, + "Although the amulet was lost, it is my hope that if I can make into the mines I can craft another." + ).also { stage++ } + + 79 -> showTopics( + Topic("Is there any other way into the mines?", 44, true), + Topic("Why was everyone in the mines slaughtered?", 80, true), + Topic("I must be going now.", 86, true), + ) + + 80 -> playerl( + FacialExpression.NEUTRAL, + "Why was everyone in the mines slaughtered? Surely it wasn't their fault that the crystals formed?" + ).also { stage++ } + + 81 -> npcl( + FacialExpression.NEUTRAL, + "It is said that some of the workers in the mines, merely from being in the presence of these crystals, found themselves bestowed with the love of Saradomin." + ).also { stage++ } + + 82 -> npcl( + FacialExpression.NEUTRAL, + "The advantage to our cause was considered too great by some within Morytania. They set about mercilessly and brutally killing everyone in the mines rather than risk losing them to us." + ).also { stage++ } + + 83 -> npcl( + FacialExpression.NEUTRAL, + "Such is the treachery of the servants of evil, that they even destroy their own kind without a moments [sic] thought." + ).also { stage++ } + + 84 -> npcl( + FacialExpression.NEUTRAL, + "The mines are now rumored to be haunted by the souls of all those brutally and needlessly killed." + ).also { stage++ } + + 85 -> showTopics( + Topic("Is there any other way into the mines?", 44, true), + Topic("How does a lost artefact that was only legendary help?", 77, true), + Topic("I must be going now.", 86, true), + ) + + 86 -> playerl( + FacialExpression.NEUTRAL, + "I must be going now, good luck on your quest." + ).also { stage++ } + + 87 -> npcl( + FacialExpression.NEUTRAL, + "You should believe not in luck, but in the protection of Saradomin. Farewell." + ).also { stage = END_DIALOGUE } + + 88 -> playerl(FacialExpression.NEUTRAL, "I hope it goes well. Goodbye.").also { stage = END_DIALOGUE } } - // dialogue when quest is in progress + // dialogue after the quest is in progress in 1..99 -> when (stage) { - 0 -> sendDialogue(player!!, "where crystal").also { stage = END_DIALOGUE } + 0 -> playerl(FacialExpression.NEUTRAL, "Quest in progress").also { stage = END_DIALOGUE } +/* + // these are here so i can copy them + 0 -> playerl(FacialExpression.NEUTRAL, "").also { stage++ } + 0 -> npcl(FacialExpression.NEUTRAL, "").also { stage++ } + 0 -> showTopics( + Topic("", 0, true), + Topic("", 0, true), + Topic("", 0, true), + Topic("", 0, true), + ) + + */ } - // dialogue after completing quest + // dialogue after the quest is completed 100 -> when (stage) { - 0 -> sendDialogue(player!!, "gz on the necklace").also { stage = END_DIALOGUE } + 0 -> playerl(FacialExpression.NEUTRAL, "Quest complete").also { stage = END_DIALOGUE } +/* + // these are here so i can copy them + 0 -> playerl(FacialExpression.NEUTRAL, "").also { stage++ } + 0 -> npcl(FacialExpression.NEUTRAL, "").also { stage++ } + 0 -> showTopics( + Topic("", 0, true), + Topic("", 0, true), + Topic("", 0, true), + Topic("", 0, true), + ) + + */ } } } From 6f728cbef88545df3d96ec0d74728d1c042482a8 Mon Sep 17 00:00:00 2001 From: aidan Date: Tue, 2 Dec 2025 16:06:45 -0600 Subject: [PATCH 3/7] finished zealot dialogue --- .../quest/hauntedmine/HauntedMine.kt | 1 + .../quest/hauntedmine/HauntedMineListeners.kt | 1 + .../quest/hauntedmine/ZealotDialogue.kt | 156 ++++++++++++++---- 3 files changed, 128 insertions(+), 30 deletions(-) diff --git a/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMine.kt b/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMine.kt index e217953a7..4daced756 100644 --- a/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMine.kt +++ b/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMine.kt @@ -34,6 +34,7 @@ class HauntedMine : Quest(Quests.HAUNTED_MINE,73 ,72 ,2 ,382, 0, 1, 11) { const val attributeKilledTreusDayth = "/save:quest:hauntedmine-killedtreusdayth" // True after you've killed Treus Dayth. const val attributeKeyMentioned = "/save:quest:hauntedmine-keymentioned" // True after the player asks about a way into the mines. + const val attributeZealotKeyReturned = "/save:quest:hauntedmine-zealotkeyreturned" // True after you return the zealot's key after the quest. Note that this should not reset after quest completion } // Quest Journal ref: https://youtu.be/CD77NeKz1J4?si=AxNEg5YZU5oJ3T11&t=231 diff --git a/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMineListeners.kt b/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMineListeners.kt index 829c956f2..97a644071 100644 --- a/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMineListeners.kt +++ b/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMineListeners.kt @@ -23,6 +23,7 @@ class HauntedMineListeners : InteractionListener { return@onUseWith true } + // you should not be able to pickpocket the key after the quest, but that should be taken care of by clearing the attributeKeyMentioned when the quest finishes. on(NPCs.ZEALOT_1528, IntType.NPC, "pickpocket"){ player, node -> if(getAttribute(player, attributeKeyMentioned, false) && !player.inventory.containsItem(Item(Items.ZEALOTS_KEY_4078))){ player.lock() diff --git a/Server/src/main/content/region/morytania/quest/hauntedmine/ZealotDialogue.kt b/Server/src/main/content/region/morytania/quest/hauntedmine/ZealotDialogue.kt index 876757fd7..54044ec61 100644 --- a/Server/src/main/content/region/morytania/quest/hauntedmine/ZealotDialogue.kt +++ b/Server/src/main/content/region/morytania/quest/hauntedmine/ZealotDialogue.kt @@ -1,9 +1,8 @@ package content.region.morytania.quest.hauntedmine import content.data.Quests -import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributeAskPoisonAnna -import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributePoisonClue import content.region.morytania.quest.hauntedmine.HauntedMine.Companion.attributeKeyMentioned +import content.region.morytania.quest.hauntedmine.HauntedMine.Companion.attributeZealotKeyReturned import core.api.* import core.game.dialogue.* import core.game.node.entity.player.Player @@ -30,11 +29,18 @@ class ZealotDialogue (player: Player? = null) : DialoguePlugin(player) { // message on why you should appreciate this bespoke, small-batch, hand-crafted dialogue. >:( class ZealotDialogueFile : DialogueFile() { override fun handle(componentID: Int, buttonID: Int) { - when (getQuestStage(player!!, Quests.MURDER_MYSTERY)) { + when (getQuestStage(player!!, Quests.HAUNTED_MINE)) { + + // dialogue before/during the quest + in 0..99 -> when (stage) { + 0 -> playerl( + FacialExpression.NEUTRAL, "Hello there." + ).also { + if (getQuestStage(player!!, Quests.HAUNTED_MINE) == 0) { + stage = 1 + } else stage = 89 + } - // dialogue before starting the quest - 0 -> when (stage) { - 0 -> playerl(FacialExpression.NEUTRAL, "Hello there.").also { stage++ } 1 -> npcl(FacialExpression.NEUTRAL, "State thy allegiance stranger.").also { stage++ } 2 -> showTopics( Topic("I follow the path of Saradomin.", 3, true), @@ -444,40 +450,130 @@ class ZealotDialogueFile : DialogueFile() { ).also { stage = END_DIALOGUE } 88 -> playerl(FacialExpression.NEUTRAL, "I hope it goes well. Goodbye.").also { stage = END_DIALOGUE } - } - // dialogue after the quest is in progress - in 1..99 -> when (stage) { - 0 -> playerl(FacialExpression.NEUTRAL, "Quest in progress").also { stage = END_DIALOGUE } -/* - // these are here so i can copy them - 0 -> playerl(FacialExpression.NEUTRAL, "").also { stage++ } - 0 -> npcl(FacialExpression.NEUTRAL, "").also { stage++ } - 0 -> showTopics( - Topic("", 0, true), - Topic("", 0, true), - Topic("", 0, true), - Topic("", 0, true), + // break point where if we've already started the quest + 89 -> npcl( + FacialExpression.NEUTRAL, + "Hello again. I'm afraid I'm rather preoccupied. What was it you wanted?" + ).also { + stage = if (getAttribute(player!!, attributeKeyMentioned, false)) { + 90 + } else 91 + } + + 90 -> showTopics( + Topic(FacialExpression.NEUTRAL, "Can you explain the history of these mines again?", 32), + Topic("Is there any other way into the mines?", 44, true), + Topic("How does a lost artefact that was only legendary help?", 77, true), + Topic("Why was everyone in the mines slaughtered?", 80, true), ) - */ + 91 -> showTopics( + Topic(FacialExpression.NEUTRAL, "Can you explain the history of these mines again?", 32), + Topic("Where is the second entrance to the mines?", 48, true), + Topic("Can I borrow your key?", 63, true), + Topic("How does a lost artefact that was only legendary help?", 77, true), + Topic("Why was everyone in the mines slaughtered?", 80, true), + ) } // dialogue after the quest is completed 100 -> when (stage) { - 0 -> playerl(FacialExpression.NEUTRAL, "Quest complete").also { stage = END_DIALOGUE } -/* - // these are here so i can copy them - 0 -> playerl(FacialExpression.NEUTRAL, "").also { stage++ } - 0 -> npcl(FacialExpression.NEUTRAL, "").also { stage++ } 0 -> showTopics( - Topic("", 0, true), - Topic("", 0, true), - Topic("", 0, true), - Topic("", 0, true), + Topic("I've done it, I've managed to recreate the salve amulet!", 1, true), + Topic(FacialExpression.NEUTRAL, "What powers does the salve amulet have?", 23), + ) + // check if the zealot's key has been returned. + 1 -> playerl( + FacialExpression.NEUTRAL, + "I've done it, I've managed to recreate the salve amulet!" + ).also { + stage = if (!getAttribute(player!!, attributeZealotKeyReturned, false)) { + 2 + } else 19 + } + + 2 -> npcl( + FacialExpression.NEUTRAL, + "That hardly seems likely. There is no way you could have made it to the bottom of the mines without the key which is in my possession." + ).also { stage++ } + + 3 -> showTopics( + Topic("I found another way down.", 4, true), + Topic("Correction, the key that was in your possession.", 6, true), + Topic("Fine, don't believe me.", 18, true), ) - */ + 4 -> playerl(FacialExpression.NEUTRAL, "I, er... found another way down.").also { stage++ } + 5 -> npcl( + FacialExpression.NEUTRAL, + "Mock me not, this is a serious task I am undertaking. I don't have the time for your halfwitted attempt at humour." + ).also { stage = END_DIALOGUE } + + 6 -> playerl( + FacialExpression.NEUTRAL, + "Correction, the key that was in your possession." + ).also { stage++ } + + 7 -> npcl(FacialExpression.NEUTRAL, "My key, where is it? You stole it?").also { stage++ } + 8 -> npcl(FacialExpression.NEUTRAL, "Return that key to me now!").also { + stage = if (player!!.inventory.contains(Items.ZEALOTS_KEY_4078, 1)) { + 10 + } else 16 + } + + 10 -> showTopics( + Topic("Ok, I've finished with it now anyway.", 11, true), + Topic("Actually maybe I'll just keep hold of it for now.", 14, true), + ) + + 11 -> playerl(FacialExpression.NEUTRAL, "Ok, I've finished with it now anyway.").also { stage++ } + 12 -> npcl( + FacialExpression.NEUTRAL, + "Good, maybe all is not lost, despite your apparent lack of common sense." + ).also { stage++ } + // remove the key and set an attribute that it's been returned. + 13 -> playerl(FacialExpression.NEUTRAL, "Er... you're welcome?").also { stage = END_DIALOGUE }.also { + removeItem( + player!!, Items.ZEALOTS_KEY_4078 + ) + }.also { setAttribute(player!!, attributeZealotKeyReturned, true) } + + 14 -> playerl( + FacialExpression.NEUTRAL, + "Actually maybe I'll just keep hold of it for now." + ).also { stage++ } + + 15 -> npcl( + FacialExpression.NEUTRAL, + "Meddling fool, there are bigger things at stake here than you and your petty thieving intellect can understand." + ).also { stage = END_DIALOGUE } + + 16 -> playerl(FacialExpression.NEUTRAL, "I seem to have misplaced it, sorry.").also { stage++ } + 17 -> npcl( + FacialExpression.NEUTRAL, + "Arrrrrrrgh, you're unbelievable. Get out of my sight." + ).also { stage++ } + + 18 -> playerl(FacialExpression.NEUTRAL, "Fine, don't believe me.").also { stage = END_DIALOGUE } + 19 -> npcl( + FacialExpression.NEUTRAL, + "Then it is fortunate for us that Saradomin has guided you. Success certainly doesn't seem likely to have stemmed from rational behaviour on your part." + ).also { stage++ } + + 20 -> playerl( + FacialExpression.NEUTRAL, + "You still haven't forgiven me for borrowing your key have you?" + ).also { stage++ } + + 21 -> npcl(FacialExpression.NEUTRAL, "Borrowed!? You stole it!").also { stage++ } + 22 -> playerl(FacialExpression.NEUTRAL, "I'd better be going now.").also { stage = END_DIALOGUE } + 23 -> npcl( + FacialExpression.NEUTRAL, + "From what I have heard they would be put to best use in the slaying of the evil undead, the zombies and skeletons that walk this land." + ).also { stage++ } + + 24 -> playerl(FacialExpression.NEUTRAL, "Thanks for the tip.").also { stage = END_DIALOGUE } } } } From e5af17760ccf6272ac46a54026de4573c415be41 Mon Sep 17 00:00:00 2001 From: aidan Date: Thu, 4 Dec 2025 09:45:42 -0600 Subject: [PATCH 4/7] getting all the ladder listeners and populating levels. --- Server/data/configs/drop_tables.json | 14 ++ Server/data/configs/ground_spawns.json | 14 +- Server/data/configs/npc_configs.json | 8 + Server/data/configs/npc_spawns.json | 48 +++- .../handlers/AbandonedMineListeners.kt | 221 ++++++++++++++++-- .../quest/hauntedmine/HauntedMine.kt | 2 + .../quest/hauntedmine/HauntedMineListeners.kt | 15 ++ .../quest/hauntedmine/ZealotDialogue.kt | 5 +- 8 files changed, 300 insertions(+), 27 deletions(-) diff --git a/Server/data/configs/drop_tables.json b/Server/data/configs/drop_tables.json index 474c5bbe7..2be0c87c8 100644 --- a/Server/data/configs/drop_tables.json +++ b/Server/data/configs/drop_tables.json @@ -58773,5 +58773,19 @@ "ids": "8127", "description": "Dark energy core", "main": [] + }, + { + "default": [ + { + "minAmount": "1", + "weight": "1.0", + "id": "1267", + "maxAmount": "1" + } + ], + "charm": [], + "ids": "1536", + "description": "", + "main": [] } ] \ No newline at end of file diff --git a/Server/data/configs/ground_spawns.json b/Server/data/configs/ground_spawns.json index 7ddcf821d..2ec02ce2c 100644 --- a/Server/data/configs/ground_spawns.json +++ b/Server/data/configs/ground_spawns.json @@ -323,9 +323,17 @@ "item_id": "1217", "loc_data": "{1,3180,3821,0,60}-" }, + { + "item_id": "1237", + "loc_data": "{60,2808,4572,0,1}-" + }, { "item_id": "1265", - "loc_data": "{1,3229,3218,2,100}-{1,2963,3216,0,30}-{1,3081,3429,0,50}-{1,3288,9442,0,90}-{1,3288,9431,0,90}-" + "loc_data": "{1,3229,3218,2,100}-{1,2963,3216,0,30}-{1,3081,3429,0,50}-{60,2795,4579,0,1}-{60,2812,4572,0,1}-{1,3288,9442,0,90}-{1,3288,9431,0,90}-" + }, + { + "item_id": "1269", + "loc_data": "{60,2812,4571,0,1}-" }, { "item_id": "1321", @@ -421,11 +429,11 @@ }, { "item_id": "1812", - "loc_data": "{1,2747,3579,0,100}" + "loc_data": "{1,2747,3579,0,100}-" }, { "item_id": "1813", - "loc_data": "{1,2746,3578,0,100}" + "loc_data": "{1,2746,3578,0,100}-" }, { "item_id": "1856", diff --git a/Server/data/configs/npc_configs.json b/Server/data/configs/npc_configs.json index d4efc299f..45b7bc508 100644 --- a/Server/data/configs/npc_configs.json +++ b/Server/data/configs/npc_configs.json @@ -10563,6 +10563,7 @@ "examine": "Useful for hitting rocks.", "melee_animation": "0", "range_animation": "0", + "respawn_delay": "60", "defence_animation": "0", "weakness": "7", "magic_animation": "0", @@ -15938,6 +15939,7 @@ "attack_level": "5" }, { + "examine": "The ghost looks like he's up to something.", "name": "Mischievous ghost", "defence_level": "1", "safespot": null, @@ -74976,6 +74978,7 @@ "id": "1530" }, { + "examine": "Those are some of the biggest teeth I've ever seen.", "name": "Loading crane", "id": "1542" }, @@ -74984,22 +74987,27 @@ "id": "1543" }, { + "examine": "Big, metal and wheeled.", "name": "Mine cart", "id": "1544" }, { + "examine": "Big, metal and wheeled.", "name": "Mine cart", "id": "1545" }, { + "examine": "Big, metal and wheeled.", "name": "Mine cart", "id": "1546" }, { + "examine": "Big, metal and wheeled.", "name": "Mine cart", "id": "1547" }, { + "examine": "Big, metal and wheeled.", "name": "Mine cart", "id": "1548" }, diff --git a/Server/data/configs/npc_spawns.json b/Server/data/configs/npc_spawns.json index e5e5395ae..7e3546b5a 100644 --- a/Server/data/configs/npc_spawns.json +++ b/Server/data/configs/npc_spawns.json @@ -157,7 +157,7 @@ }, { "npc_id": "47", - "loc_data": "{2821,3170,0,1,1}-{3076,3282,0,1,5}-{3089,3266,0,1,4}-{3091,3266,0,1,4}-{3341,3267,0,1,5}-{3097,3364,0,1,3}-{3102,3363,0,1,5}-{3127,3487,0,1,4}-{3125,3486,0,1,6}-{3127,3486,0,1,4}-{2339,9356,0,1,0}-{2354,9390,0,1,0}-{2361,9403,0,1,0}-{2362,9347,0,1,0}-{2603,9480,0,1,1}-{2600,9477,0,1,0}-{2579,9496,0,1,4}-{2580,9508,0,1,0}-{2571,9522,0,1,4}-{2565,9505,0,1,1}-{2566,9510,0,1,6}-{2594,9497,0,1,4}-{2852,9642,0,1,6}-{2858,9632,0,1,3}-{2568,9620,0,1,0}-{2573,9612,0,1,0}-{2579,9631,0,1,0}-{2580,9600,0,1,0}-{2580,9614,0,1,0}-{2580,9620,0,1,0}-{2580,9626,0,1,0}-{2583,9632,0,1,0}-{2584,9625,0,1,0}-{2584,9637,0,1,0}-{2589,9644,0,1,0}-{2590,9601,0,1,0}-{2590,9638,0,1,0}-{2591,9601,0,1,0}-{2591,9621,0,1,0}-{2594,9636,0,1,0}-{2594,9644,0,1,0}-{2597,9604,0,1,0}-{2607,9615,0,1,0}-{2608,9628,0,1,0}-{2614,9651,0,1,0}-{2614,9656,0,1,0}-{2615,9647,0,1,0}-{2615,9661,0,1,0}-{2616,9633,0,1,0}-{2618,9630,0,1,0}-{3108,9754,0,1,5}-{3110,9754,0,1,5}-{3108,9750,0,1,5}-{2592,9831,0,1,3}-{2588,9825,0,1,6}-{2583,9829,0,1,4}-{2581,9841,0,1,0}-{2597,9823,0,1,2}-{2579,9805,0,1,3}-{2576,9804,0,1,0}-{2573,9805,0,1,5}-{2571,9808,0,1,3}-{2576,9810,0,1,2}-{2587,9802,0,1,2}-{2592,9800,0,1,4}-{2596,9805,0,1,6}-{2601,9802,0,1,5}-{2585,9801,0,1,7}-{2594,9803,0,1,0}-{2590,9806,0,1,3}-{2612,9808,0,1,6}-{2604,9810,0,1,6}-{2579,9821,0,1,2}-{2576,9812,0,1,6}-{2580,9813,0,1,6}-{2600,9813,0,1,4}-{2599,9809,0,1,4}-{3158,3226,0,1,5}-{3160,3202,0,1,4}-{3192,3203,0,1,0}-{3194,3204,0,1,0}-{3196,3206,0,1,0}-{3197,3204,0,1,0}-{2654,9640,0,1,6}-{2655,9637,0,1,4}-{2656,9639,0,1,7}-{2651,9636,0,1,5}-{2648,9637,0,1,4}-{2651,9642,0,1,1}-{2654,9640,0,1,0}-{2654,9635,0,1,6}-{2655,9635,0,1,3}-{2664,9626,0,1,6}-{2664,9624,0,1,1}-{2661,9623,0,1,1}-{2663,9623,0,1,3}-{2664,9626,0,1,6}-{2930,9699,0,1,0}-{2933,9697,0,1,0}-{2932,9685,0,1,0}-{2930,9693,0,1,0}-{3235,3224,0,1,3}-{3229,3220,0,1,4}-{3211,3211,0,1,3}-{3225,3220,0,1,1}-{3237,3215,0,1,5}-{3211,3210,0,1,7}-{3227,3220,0,1,7}-{3233,3227,0,1,5}-{3227,3210,0,1,6}-{3228,3222,0,1,4}-{3229,3226,0,1,0}-{3236,3217,0,1,4}-{3259,3230,0,1,4}-{3233,3237,0,1,7}-{3205,3204,0,1,0}-{3206,3204,0,1,0}-{3205,3203,0,1,0}-{3206,3202,0,1,0}-{3207,3202,0,1,0}-{3208,3203,0,1,0}-{3001,3202,0,1,5}-{3243,3687,0,1,5}-{3249,3669,0,1,3}-{3252,3675,0,1,4}-{3252,3680,0,1,3}-{3259,3683,0,1,0}-{3475,9840,0,1,6}-{3481,9842,0,1,1}-{3486,9843,0,1,7}-{3483,9824,0,1,4}-{3496,9808,0,0,5}-{3490,9815,0,1,1}-{3478,9834,0,0,3}-{3490,9824,0,1,4}-{3225,9862,0,1,4}-{3222,9861,0,1,6}-{3220,9860,0,1,6}-{3219,9865,0,1,6}-{3237,9862,0,1,4}-{2536,2982,0,1,3}-{2531,2980,0,1,0}-{2522,2981,0,1,4}-{2545,2989,0,1,4}-{2523,2970,0,1,2}-{3026,3174,0,1,5}-{3019,3176,0,1,7}-{2801,3158,0,1,2}-{2514,3193,0,1,6}-{2518,3192,0,1,3}-{2507,3181,0,1,3}-{2508,3178,0,1,6}-{2511,3183,0,1,3}-{2515,3182,0,1,1}-{3021,3205,0,1,6}-{3019,3292,0,1,7}-{3018,3295,0,1,7}-{2531,3325,0,1,3}-{2530,3327,0,1,5}-{2521,3331,0,1,3}-{2526,3328,0,1,3}-{2523,3331,0,1,4}-{2523,3334,0,1,1}-{2531,3329,0,1,5}-{2532,3333,0,1,5}-{3276,9871,0,1,1}-{3277,9871,0,1,3}-" + "loc_data": "{2821,3170,0,1,1}-{3341,3267,0,1,5}-{3076,3282,0,1,5}-{3089,3266,0,1,4}-{3091,3266,0,1,4}-{3097,3364,0,1,3}-{3102,3363,0,1,5}-{3127,3487,0,1,4}-{3125,3486,0,1,6}-{3127,3486,0,1,4}-{2339,9356,0,1,0}-{2354,9390,0,1,0}-{2361,9403,0,1,0}-{2362,9347,0,1,0}-{2603,9480,0,1,1}-{2600,9477,0,1,0}-{2579,9496,0,1,4}-{2580,9508,0,1,0}-{2571,9522,0,1,4}-{2565,9505,0,1,1}-{2566,9510,0,1,6}-{2594,9497,0,1,4}-{2852,9642,0,1,6}-{2858,9632,0,1,3}-{2568,9620,0,1,0}-{2573,9612,0,1,0}-{2579,9631,0,1,0}-{2580,9600,0,1,0}-{2580,9614,0,1,0}-{2580,9620,0,1,0}-{2580,9626,0,1,0}-{2583,9632,0,1,0}-{2584,9625,0,1,0}-{2584,9637,0,1,0}-{2589,9644,0,1,0}-{2590,9601,0,1,0}-{2590,9638,0,1,0}-{2591,9601,0,1,0}-{2591,9621,0,1,0}-{2594,9636,0,1,0}-{2594,9644,0,1,0}-{2597,9604,0,1,0}-{2607,9615,0,1,0}-{2608,9628,0,1,0}-{2614,9651,0,1,0}-{2614,9656,0,1,0}-{2615,9647,0,1,0}-{2615,9661,0,1,0}-{2616,9633,0,1,0}-{2618,9630,0,1,0}-{3108,9754,0,1,5}-{3110,9754,0,1,5}-{3108,9750,0,1,5}-{2592,9831,0,1,3}-{2588,9825,0,1,6}-{2583,9829,0,1,4}-{2581,9841,0,1,0}-{2597,9823,0,1,2}-{2579,9805,0,1,3}-{2576,9804,0,1,0}-{2573,9805,0,1,5}-{2571,9808,0,1,3}-{2576,9810,0,1,2}-{2587,9802,0,1,2}-{2592,9800,0,1,4}-{2596,9805,0,1,6}-{2601,9802,0,1,5}-{2585,9801,0,1,7}-{2594,9803,0,1,0}-{2590,9806,0,1,3}-{2612,9808,0,1,6}-{2604,9810,0,1,6}-{2579,9821,0,1,2}-{2576,9812,0,1,6}-{2580,9813,0,1,6}-{2600,9813,0,1,4}-{2599,9809,0,1,4}-{3158,3226,0,1,5}-{3160,3202,0,1,4}-{3192,3203,0,1,0}-{3194,3204,0,1,0}-{3196,3206,0,1,0}-{3197,3204,0,1,0}-{2654,9640,0,1,6}-{2655,9637,0,1,4}-{2656,9639,0,1,7}-{2651,9636,0,1,5}-{2648,9637,0,1,4}-{2651,9642,0,1,1}-{2654,9640,0,1,0}-{2654,9635,0,1,6}-{2655,9635,0,1,3}-{2664,9626,0,1,6}-{2664,9624,0,1,1}-{2661,9623,0,1,1}-{2663,9623,0,1,3}-{2664,9626,0,1,6}-{2930,9699,0,1,0}-{2933,9697,0,1,0}-{2932,9685,0,1,0}-{2930,9693,0,1,0}-{3001,3202,0,1,5}-{3235,3224,0,1,3}-{3229,3220,0,1,4}-{3211,3211,0,1,3}-{3225,3220,0,1,1}-{3237,3215,0,1,5}-{3211,3210,0,1,7}-{3227,3220,0,1,7}-{3233,3227,0,1,5}-{3227,3210,0,1,6}-{3228,3222,0,1,4}-{3229,3226,0,1,0}-{3236,3217,0,1,4}-{3259,3230,0,1,4}-{3233,3237,0,1,7}-{3205,3204,0,1,0}-{3206,3204,0,1,0}-{3205,3203,0,1,0}-{3206,3202,0,1,0}-{3207,3202,0,1,0}-{3208,3203,0,1,0}-{3243,3687,0,1,5}-{3249,3669,0,1,3}-{3252,3675,0,1,4}-{3252,3680,0,1,3}-{3259,3683,0,1,0}-{3475,9840,0,1,6}-{3481,9842,0,1,1}-{3486,9843,0,1,7}-{3483,9824,0,1,4}-{3496,9808,0,0,5}-{3490,9815,0,1,1}-{3478,9834,0,0,3}-{3490,9824,0,1,4}-{3225,9862,0,1,4}-{3222,9861,0,1,6}-{3220,9860,0,1,6}-{3219,9865,0,1,6}-{3237,9862,0,1,4}-{2536,2982,0,1,3}-{2531,2980,0,1,0}-{2522,2981,0,1,4}-{2545,2989,0,1,4}-{2523,2970,0,1,2}-{3026,3174,0,1,5}-{3019,3176,0,1,7}-{2801,3158,0,1,2}-{2514,3193,0,1,6}-{2518,3192,0,1,3}-{2507,3181,0,1,3}-{2508,3178,0,1,6}-{2511,3183,0,1,3}-{2515,3182,0,1,1}-{3021,3205,0,1,6}-{3019,3292,0,1,7}-{3018,3295,0,1,7}-{2531,3325,0,1,3}-{2530,3327,0,1,5}-{2521,3331,0,1,3}-{2526,3328,0,1,3}-{2523,3331,0,1,4}-{2523,3334,0,1,1}-{2531,3329,0,1,5}-{2532,3333,0,1,5}-{2780,4592,0,1,0}-{2783,4593,0,1,0}-{2777,4582,0,1,0}-{2785,4580,0,1,0}-{2786,4578,0,1,0}-{2787,4579,0,1,0}-{2812,4577,0,1,0}-{2802,4599,0,1,0}-{3276,9871,0,1,1}-{3277,9871,0,1,3}-" }, { "npc_id": "48", @@ -2097,7 +2097,7 @@ }, { "npc_id": "708", - "loc_data": "{2595,3125,0,1,1}-{2601,3135,0,1,3}-{2598,3120,0,1,6}-{2615,3120,0,1,4}-{2598,3108,0,1,4}-{2865,3175,0,1,0}-{2855,3188,0,1,1}-{2838,3194,0,1,3}-{2827,3170,0,1,5}-{2598,3145,0,1,1}-{2588,3145,0,1,7}-{2603,3221,0,1,7}-{2604,3212,0,1,3}-{2612,3230,0,1,0}-{2611,3204,0,1,7}-{2942,3247,0,1,7}-{2627,3231,0,1,4}-{2932,3322,0,0,5}-{2934,3301,0,1,5}-{2934,3301,0,1,3}-{2935,3343,0,1,1}-{2941,3356,0,0,7}-{3162,3410,0,1,2}-{3189,3503,0,1,6}-{3219,3221,0,1,4}-{2977,3202,0,1,7}-{2997,3300,0,1,3}-{2957,3308,0,1,0}-{2973,3274,0,1,3}-{2994,3270,0,1,0}-{3215,3282,0,1,1}-{3242,3306,0,1,1}-{2980,3337,0,1,6}-{2977,3377,0,0,3}-{3208,3357,0,1,3}-{2962,3424,0,1,6}-{3240,3393,0,1,3}-{2715,3451,0,1,4}-{2715,3436,0,1,3}-{2733,3459,0,1,3}-{2732,3457,0,1,6}-{3239,3523,0,1,4}-{3262,3523,0,1,2}-{2806,3181,0,1,3}-{2788,3179,0,1,3}-{2753,3178,0,1,3}-{2759,3155,0,1,0}-{2544,3184,0,1,3}-{3068,3251,0,1,6}-{3031,3322,0,1,1}-{3010,3271,0,1,6}-{3011,3513,0,1,1}-" + "loc_data": "{2595,3125,0,1,1}-{2601,3135,0,1,3}-{2598,3120,0,1,6}-{2615,3120,0,1,4}-{2598,3108,0,1,4}-{2865,3175,0,1,0}-{2855,3188,0,1,1}-{2838,3194,0,1,3}-{2827,3170,0,1,5}-{2598,3145,0,1,1}-{2588,3145,0,1,7}-{2603,3221,0,1,7}-{2604,3212,0,1,3}-{2612,3230,0,1,0}-{2611,3204,0,1,7}-{2942,3247,0,1,7}-{2627,3231,0,1,4}-{2932,3322,0,0,5}-{2934,3301,0,1,5}-{2934,3301,0,1,3}-{2935,3343,0,1,1}-{2941,3356,0,0,7}-{3162,3410,0,1,2}-{3189,3503,0,1,6}-{2977,3202,0,1,7}-{3219,3221,0,1,4}-{2997,3300,0,1,3}-{2957,3308,0,1,0}-{2973,3274,0,1,3}-{2994,3270,0,1,0}-{3215,3282,0,1,1}-{3242,3306,0,1,1}-{2980,3337,0,1,6}-{2977,3377,0,0,3}-{3208,3357,0,1,3}-{2962,3424,0,1,6}-{3240,3393,0,1,3}-{2715,3451,0,1,4}-{2715,3436,0,1,3}-{2733,3459,0,1,3}-{2732,3457,0,1,6}-{3239,3523,0,1,4}-{3262,3523,0,1,2}-{2806,3181,0,1,3}-{2788,3179,0,1,3}-{2753,3178,0,1,3}-{2759,3155,0,1,0}-{2544,3184,0,1,3}-{3068,3251,0,1,6}-{3031,3322,0,1,1}-{3010,3271,0,1,6}-{3011,3513,0,1,1}-" }, { "npc_id": "710", @@ -2779,6 +2779,10 @@ "npc_id": "1013", "loc_data": "{2593,2971,0,1,0}-{2594,2971,0,1,0}-{2596,2961,0,1,0}-{2598,2971,0,1,0}-{2599,2960,0,1,0}-{2598,2960,0,1,0}-{2603,2966,0,1,0}-{2603,2970,0,1,0}-{2598,2960,0,1,0}-{2596,2963,0,1,0}-{2595,2964,0,1,0}-{2594,2964,0,1,0}-{2601,2964,0,1,0}-{2598,2969,0,1,0}-{2604,2971,0,1,0}-{2601,2972,0,1,0}-{2392,3057,0,1,0}-{2395,3056,0,1,0}-{2395,3052,0,1,0}-{2397,3048,0,1,0}-{2400,3050,0,1,0}-{2400,3053,0,1,0}-{2391,3052,0,1,0}-{2393,3047,0,1,0}-{2399,3046,0,1,0}-{2402,3044,0,1,0}-{2399,3040,0,1,0}-{2395,3042,0,1,0}-{2391,3045,0,1,0}-{2464,2912,0,1,0}-{2544,2904,0,1,0}-{2544,2988,0,1,0}-{2532,2983,0,1,0}-{2549,2983,0,1,0}-{2545,2983,0,1,0}-{2528,2986,0,1,0}-{2550,2979,0,1,0}-{2522,2978,0,1,0}-{2523,2976,0,1,0}-{2526,2974,0,1,0}-{2548,2990,0,1,0}-{2552,2988,0,1,0}-{2548,2979,0,1,0}-{2547,2991,0,1,0}-{2525,2975,0,1,0}-" }, + { + "npc_id": "1015", + "loc_data": "{2792,4597,0,0,0}-{2785,4594,0,0,0}-{2783,4591,0,0,0}-{2774,4592,0,0,0}-{2770,4591,0,0,0}-{2769,4593,0,0,0}-" + }, { "npc_id": "1017", "loc_data": "{3191,3277,0,1,0}-{3188,3279,0,1,0}-{3187,3277,0,1,0}-{3190,3278,0,1,0}-{3187,3277,0,1,0}-{3189,3278,0,1,3}-{3198,3359,0,1,0}-{2677,3656,0,1,2}-{2672,3654,0,1,2}-{2676,3652,0,1,4}-{2681,3652,0,1,4}-{2675,3652,0,1,3}-{3231,3296,0,1,6}-{3233,3300,0,1,4}-{3235,3293,0,1,3}-{3232,3288,0,1,0}-{3234,3298,0,1,6}-{3234,3297,0,1,3}-{3234,3292,0,1,4}-{3235,3289,0,1,1}-{2693,3271,0,1,3}-{2692,3272,0,1,3}-{2785,3069,0,1,4}-{2800,3072,0,1,6}-" @@ -3859,9 +3863,41 @@ "npc_id": "1528", "loc_data": "{3443,3256,0,1,0}-" }, + { + "npc_id": "1537", + "loc_data": "{2803,4595,0,0,0}-{2786,4571,0,1,0}-{2792,4567,0,1,0}-{2791,4560,0,1,0}-{2796,4587,0,1,0}-{2798,4592,0,1,0}-{2802,4591,0,1,0}-{2798,4597,0,1,0}-{2808,4598,0,1,0}-{2808,4601,0,1,0}-" + }, + { + "npc_id": "1538", + "loc_data": "{2801,4580,0,0,0}-{2802,4580,0,0,0}-{2800,4573,0,0,0}-{2807,4572,0,0,0}-{2810,4573,0,0,0}-{2813,4571,0,0,0}-{2811,4567,0,0,0}-" + }, + { + "npc_id": "1542", + "loc_data": "{2793,4458,0,0,7}-{2782,4458,0,0,2}-{2787,4451,0,0,1}-{2787,4446,0,0,2}-" + }, + { + "npc_id": "1543", + "loc_data": "{2788,4455,0,0,0}-" + }, { "npc_id": "1544", - "loc_data": "{2911,10175,0,0,4}-{2912,10175,0,0,4}-{2913,10175,0,0,4}-{2914,10175,0,0,4}-{2909,10173,0,0,4}-{2910,10173,0,0,4}-{2911,10173,0,0,4}-{2912,10173,0,0,4}-{2913,10173,0,0,4}-{2909,10171,0,0,4}-{2910,10171,0,0,4}-{2911,10169,0,0,4}-{2912,10169,0,0,4}-{2913,10169,0,0,4}-" + "loc_data": "{2911,10175,0,0,4}-{2912,10175,0,0,4}-{2913,10175,0,0,4}-{2914,10175,0,0,4}-{2909,10173,0,0,4}-{2910,10173,0,0,4}-{2911,10173,0,0,4}-{2912,10173,0,0,4}-{2913,10173,0,0,4}-{2909,10171,0,0,4}-{2910,10171,0,0,4}-{2911,10169,0,0,4}-{2912,10169,0,0,4}-{2913,10169,0,0,4}-{2781,4462,0,0,4}-{2785,4456,0,0,4}-{2791,4456,0,0,4}-{2783,4446,0,0,1}-{2785,4447,0,0,1}-{2791,4447,0,0,1}-{2793,4446,0,0,1}-" + }, + { + "npc_id": "1545", + "loc_data": "{2727,4509,0,0,1}-" + }, + { + "npc_id": "1546", + "loc_data": "{2697,4498,0,0,4}-" + }, + { + "npc_id": "1547", + "loc_data": "{2715,4517,0,0,1}-" + }, + { + "npc_id": "1548", + "loc_data": "{2739,4528,0,0,1}-" }, { "npc_id": "1553", @@ -4317,7 +4353,7 @@ }, { "npc_id": "1770", - "loc_data": "{2595,9826,0,1,1}-{3189,3246,0,1,0}-{3143,3231,0,1,0}-{3140,3263,0,1,0}-{3262,3253,0,1,6}-{3259,3254,0,1,3}-{2999,3212,0,1,1}-" + "loc_data": "{2595,9826,0,1,1}-{3189,3246,0,1,0}-{3143,3231,0,1,0}-{3140,3263,0,1,0}-{2999,3212,0,1,1}-{3262,3253,0,1,6}-{3259,3254,0,1,3}-" }, { "npc_id": "1771", @@ -4325,11 +4361,11 @@ }, { "npc_id": "1772", - "loc_data": "{3194,3255,0,1,0}-{3143,3234,0,1,0}-{3251,3231,0,1,1}-{3260,3241,0,1,0}-{3259,3222,0,0,4}-{2993,3203,0,1,0}-" + "loc_data": "{3194,3255,0,1,0}-{3143,3234,0,1,0}-{2993,3203,0,1,0}-{3251,3231,0,1,1}-{3260,3241,0,1,0}-{3259,3222,0,0,4}-" }, { "npc_id": "1773", - "loc_data": "{3252,3227,0,1,1}-{3263,3219,0,1,0}-{2991,3219,0,1,1}-" + "loc_data": "{2991,3219,0,1,1}-{3252,3227,0,1,1}-{3263,3219,0,1,0}-" }, { "npc_id": "1774", diff --git a/Server/src/main/content/region/morytania/handlers/AbandonedMineListeners.kt b/Server/src/main/content/region/morytania/handlers/AbandonedMineListeners.kt index 9c35dfdf0..927ac053e 100644 --- a/Server/src/main/content/region/morytania/handlers/AbandonedMineListeners.kt +++ b/Server/src/main/content/region/morytania/handlers/AbandonedMineListeners.kt @@ -1,13 +1,17 @@ package content.region.morytania.handlers -import core.api.animate -import core.api.forceMove -import core.api.forceWalk -import core.api.location -import core.api.teleport +import content.global.skill.slayer.dungeon.AncientCavern +import core.api.* +import core.game.global.action.DoorActionHandler import core.game.interaction.IntType import core.game.interaction.InteractionListener +import core.game.node.entity.combat.ImpactHandler.HitsplatType +import core.game.node.entity.npc.NPC +import core.game.node.entity.player.Player import core.game.world.map.Location +import core.tools.RandomFunction +import org.rs09.consts.Items +import org.rs09.consts.NPCs import org.rs09.consts.Scenery /* @@ -63,38 +67,37 @@ class AbandonedMineListeners : InteractionListener { // entrance from outside (main) to mine level 1 on(Scenery.CART_TUNNEL_4913, IntType.SCENERY, "Crawl-down") { player, node -> - //todo fix all these animations and make them play before teleporting - animate(player, 844, true) + animate(player, 844) teleport(player, Location.create(3436, 9637, 0)) } // mine level 1 back to entrance on(Scenery.CART_TUNNEL_4920, IntType.SCENERY, "Crawl-through") { player, node -> - animate(player, 844, true) + animate(player, 844) teleport(player, Location.create(3441, 3232, 0)) } // mine level 1 to outside (west) on(Scenery.CART_TUNNEL_4921, IntType.SCENERY, "Crawl-through") { player, node -> - animate(player, 844, true) + animate(player, 844) teleport(player, Location.create(3429, 3233, 0)) } // mine level 1 to outside (west) on(Scenery.CART_TUNNEL_20524, IntType.SCENERY, "Crawl-through") { player, node -> - animate(player, 844, true) + animate(player, 844) teleport(player, Location.create(3428, 3225, 0)) } // outside (west) to mine level 1 on(Scenery.CART_TUNNEL_4914, IntType.SCENERY, "Crawl-down") { player, node -> - animate(player, 844, true) + animate(player, 844) teleport(player, Location.create(3405, 9631, 0)) } // outside (west) to mine level 1 on(Scenery.CART_TUNNEL_4915, IntType.SCENERY, "Crawl-down") { player, node -> - animate(player, 844, true) + animate(player, 844) teleport(player, Location.create(3409, 9623, 0)) } @@ -108,7 +111,7 @@ class AbandonedMineListeners : InteractionListener { loc.x in 3412..3414 && loc.y in 9632..9634) { - animate(player, 828, true) + animate(player, 828) teleport(player, Location.create(2774, 4577, 0)) // Check around a 1-tile radius of the south ladder @@ -116,7 +119,7 @@ class AbandonedMineListeners : InteractionListener { loc.x in 3421..3423 && loc.y in 9624..9626) { - animate(player, 828, true) + animate(player, 828) teleport(player, Location.create(2783, 4569, 0)) } @@ -133,19 +136,203 @@ class AbandonedMineListeners : InteractionListener { loc.x in 2772..2774 && loc.y in 4576..4578) { - animate(player, 828, true) + animate(player, 828) teleport(player, Location.create(3412, 9633, 0)) - // Check around a 1-tile radius of the south ladder + // Check around a 1-tile radius of the south ladder } else if (loc.z == 0 && loc.x in 2781..2783 && loc.y in 4568..4570) { - animate(player, 828, true) + animate(player, 828) teleport(player, Location.create(3422, 9624, 0)) } return@on true } + + on(Scenery.LARGE_DOOR_4963, IntType.SCENERY, "Open") { player, node -> + if (player.inventory.contains(Items.CRYSTAL_MINE_KEY_4077, 1)) { + DoorActionHandler.handleAutowalkDoor(player, node.asScenery()) + } else { + sendMessage(player, "This door is locked.") + } + return@on true + } + + on(Scenery.LARGE_DOOR_4964, IntType.SCENERY, "Open") { player, node -> + if (player.inventory.contains(Items.CRYSTAL_MINE_KEY_4077, 1)) { + DoorActionHandler.handleAutowalkDoor(player, node.asScenery()) + } else { + sendMessage(player, "This door is locked.") + } + return@on true + } + + // mine level 2 to 3 + on(Scenery.LADDER_4969, IntType.SCENERY, "Climb-down") { player, node -> + // ladder 4969 is reused in two locations, so we have to see which one the player is interacting with + val loc = player.location + + // Check around a 1-tile radius of the north ladder + if (loc.z == 0 && + loc.x in 2796..2798 && + loc.y in 4598..4600 + ) { + + animate(player, 828) + teleport(player, Location.create(2733, 4534, 0)) + + // Check around a 1-tile radius of the south ladder + } else if (loc.z == 0 && + loc.x in 2797..2799 && + loc.y in 4566..4568 + ) { + + animate(player, 828) + teleport(player, Location.create(2735, 4503, 0)) + } + + return@on true + } + + // mine level 3 to 2 + on(Scenery.LADDER_4970, IntType.SCENERY, "Climb-up") { player, node -> + // ladder 4970 is reused in two locations, so we have to see which one the player is interacting with + val loc = player.location + + // Check around a 1-tile radius of the north ladder + if (loc.z == 0 && + loc.x in 2732..2734 && + loc.y in 4534..4536 + ) { + + animate(player, 828) + teleport(player, Location.create(2796, 4599, 0)) + + // Check around a 1-tile radius of the south ladder + } else if (loc.z == 0 && + loc.x in 2733..2735 && + loc.y in 4502..4504 + ) { + + animate(player, 828) + teleport(player, Location.create(2797, 4567, 0)) + } + + return@on true + } + + // mine level 3 to 4 + on(Scenery.LADDER_4967, IntType.SCENERY, "Climb-down") { player, node -> + // ladder 4967 is reused in four locations, so we have to see which one the player is interacting with + val loc = player.location + + // north-east ladder + if (loc.z == 0 && + loc.x in 2731..2733 && + loc.y in 4528..4530 + ) { + + animate(player, 828) + teleport(player, Location.create(2797, 4529, 0)) + + // north-west ladder + } else if (loc.z == 0 && + loc.x in 2709..2711 && + loc.y in 4539..4541 + ) { + + animate(player, 828, true) + teleport(player, Location.create(2775, 4540, 0)) + + //south-east ladder + } else if (loc.z == 0 && + loc.x in 2724..2726 && + loc.y in 4485..4487 + ) { + + animate(player, 828) + teleport(player, Location.create(2790, 4486, 0)) + + // south-west ladder + } else if (loc.z == 0 && + loc.x in 2695..2697 && + loc.y in 4496..4498 + ) { + + animate(player, 828) + teleport(player, Location.create(2760, 4498, 0)) + } + + return@on true + } + + // mine level 4 to 3 + on(Scenery.LADDER_4968, IntType.SCENERY, "Climb-up") { player, node -> + // ladder 4968 is reused in two locations, so we have to see which one the player is interacting with + val loc = player.location + + // north-east ladder + if (loc.z == 0 && + loc.x in 2795..2797 && + loc.y in 4528..4530 + ) { + + animate(player, 828) + teleport(player, Location.create(2733, 4529, 0)) + + // north-west ladder + } else if (loc.z == 0 && + loc.x in 2773..2775 && + loc.y in 4539..4541 + ) { + + animate(player, 828) + teleport(player, Location.create(2711, 4540, 0)) + + //south-east ladder + } else if (loc.z == 0 && + loc.x in 2788..2790 && + loc.y in 4485..4487 + ) { + + animate(player, 828) + teleport(player, Location.create(2726, 4486, 0)) + + // south-west ladder + } else if (loc.z == 0 && + loc.x in 2759..2761 && + loc.y in 4496..4498 + ) { + + animate(player, 828) + teleport(player, Location.create(2697, 4497, 0)) + } + + return@on true + } + + // todo Make the picks respawn. + on(NPCs.IRON_PICKAXE_1015, IntType.NPC, "Take") { player, node -> + takePickaxe(player, node as NPC) + + return@on true + } + } + + +} + +// handles spawning the possessed pickaxe +private fun takePickaxe(player: Player, npc: NPC) { + val spawn: NPC = NPC.create( + NPCs.POSSESSED_PICKAXE_1536, + npc.getLocation() + ) + spawn.init() + spawn.isRespawn = false + spawn.properties.combatPulse.attack(player) + npc.clear() } \ No newline at end of file diff --git a/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMine.kt b/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMine.kt index 4daced756..f69d39520 100644 --- a/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMine.kt +++ b/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMine.kt @@ -26,6 +26,8 @@ import org.rs09.consts.Items // Output of ./get-varp.sh 72 // if (VARP[382] == 11) return 2; if (VARP[382] == 0) return 0; return 1; }; if (arg0 == 41) +// ::setqueststage 73 0 to reset quest + @Initializable class HauntedMine : Quest(Quests.HAUNTED_MINE,73 ,72 ,2 ,382, 0, 1, 11) { diff --git a/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMineListeners.kt b/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMineListeners.kt index 97a644071..9870acf6b 100644 --- a/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMineListeners.kt +++ b/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMineListeners.kt @@ -2,6 +2,7 @@ package content.region.morytania.quest.hauntedmine import content.region.morytania.quest.hauntedmine.HauntedMine.Companion.attributeKeyMentioned import core.api.* +import core.game.global.action.DoorActionHandler import core.game.interaction.IntType import core.game.interaction.InteractionListener import core.game.node.item.Item @@ -10,6 +11,7 @@ import core.game.world.GameWorld import core.game.world.update.flag.context.Animation import org.rs09.consts.Items import org.rs09.consts.NPCs +import org.rs09.consts.Scenery class HauntedMineListeners : InteractionListener { @@ -50,5 +52,18 @@ class HauntedMineListeners : InteractionListener { } return@on true } + + // mine cart you are supposed to put the fungus into (south) and take the fungus out of (north). + // note that it appears this mine cart exists in both the start and end spots simultaneously. + on(Scenery.MINE_CART_4974, IntType.SCENERY, "Search") { player, node -> + + return@on true + } + + // points settings + on(Scenery.POINTS_SETTINGS_4949, IntType.SCENERY, "Check") { player, node -> + + return@on true + } } } \ No newline at end of file diff --git a/Server/src/main/content/region/morytania/quest/hauntedmine/ZealotDialogue.kt b/Server/src/main/content/region/morytania/quest/hauntedmine/ZealotDialogue.kt index 54044ec61..eece6c7be 100644 --- a/Server/src/main/content/region/morytania/quest/hauntedmine/ZealotDialogue.kt +++ b/Server/src/main/content/region/morytania/quest/hauntedmine/ZealotDialogue.kt @@ -28,6 +28,9 @@ class ZealotDialogue (player: Player? = null) : DialoguePlugin(player) { // If you ask "Where is the plugin for space to skip dialogue?" I will send you a sternly-worded // message on why you should appreciate this bespoke, small-batch, hand-crafted dialogue. >:( class ZealotDialogueFile : DialogueFile() { + + // Note to future humans: DialogueFile is ok to use, but DialogueLabeller is the preferred system now. + // Don't make the same mistake I did. override fun handle(componentID: Int, buttonID: Int) { when (getQuestStage(player!!, Quests.HAUNTED_MINE)) { @@ -425,7 +428,7 @@ class ZealotDialogueFile : DialogueFile() { 83 -> npcl( FacialExpression.NEUTRAL, - "Such is the treachery of the servants of evil, that they even destroy their own kind without a moments [sic] thought." + "Such is the treachery of the servants of evil, that they even destroy their own kind without a moments thought." //note the "moments" with no apostrophe is authentic typo ).also { stage++ } 84 -> npcl( From c63654ea126f9f3b85f2de47ea250cd1fbd376b2 Mon Sep 17 00:00:00 2001 From: aidan Date: Thu, 4 Dec 2025 14:47:07 -0600 Subject: [PATCH 5/7] minecarts push you, but they are wacky. --- .../hauntedmine}/AbandonedMineListeners.kt | 11 +- .../quest/hauntedmine/AbandonedMineZone.kt | 100 ++++++++++++++++++ .../quest/hauntedmine/HauntedMineListeners.kt | 10 ++ .../quest/hauntedmine/MinecartNPC.kt | 73 +++++++++++++ 4 files changed, 190 insertions(+), 4 deletions(-) rename Server/src/main/content/region/morytania/{handlers => quest/hauntedmine}/AbandonedMineListeners.kt (97%) create mode 100644 Server/src/main/content/region/morytania/quest/hauntedmine/AbandonedMineZone.kt create mode 100644 Server/src/main/content/region/morytania/quest/hauntedmine/MinecartNPC.kt diff --git a/Server/src/main/content/region/morytania/handlers/AbandonedMineListeners.kt b/Server/src/main/content/region/morytania/quest/hauntedmine/AbandonedMineListeners.kt similarity index 97% rename from Server/src/main/content/region/morytania/handlers/AbandonedMineListeners.kt rename to Server/src/main/content/region/morytania/quest/hauntedmine/AbandonedMineListeners.kt index 927ac053e..21eb6a259 100644 --- a/Server/src/main/content/region/morytania/handlers/AbandonedMineListeners.kt +++ b/Server/src/main/content/region/morytania/quest/hauntedmine/AbandonedMineListeners.kt @@ -1,15 +1,14 @@ -package content.region.morytania.handlers +package content.region.morytania.quest.hauntedmine -import content.global.skill.slayer.dungeon.AncientCavern +import content.data.tables.BirdNest import core.api.* import core.game.global.action.DoorActionHandler import core.game.interaction.IntType import core.game.interaction.InteractionListener -import core.game.node.entity.combat.ImpactHandler.HitsplatType import core.game.node.entity.npc.NPC import core.game.node.entity.player.Player +import core.game.node.item.Item import core.game.world.map.Location -import core.tools.RandomFunction import org.rs09.consts.Items import org.rs09.consts.NPCs import org.rs09.consts.Scenery @@ -327,6 +326,10 @@ class AbandonedMineListeners : InteractionListener { // handles spawning the possessed pickaxe private fun takePickaxe(player: Player, npc: NPC) { + + // todo try this later instead of spawning and removing to fix the pick not respawning issue. + // transformNpc(npc, NPCs.POSSESSED_PICKAXE_1536, 400) + val spawn: NPC = NPC.create( NPCs.POSSESSED_PICKAXE_1536, npc.getLocation() diff --git a/Server/src/main/content/region/morytania/quest/hauntedmine/AbandonedMineZone.kt b/Server/src/main/content/region/morytania/quest/hauntedmine/AbandonedMineZone.kt new file mode 100644 index 000000000..bda02d442 --- /dev/null +++ b/Server/src/main/content/region/morytania/quest/hauntedmine/AbandonedMineZone.kt @@ -0,0 +1,100 @@ +package content.region.morytania.quest.hauntedmine + +import core.api.Container +import core.api.addItem +import core.api.addItemOrDrop +import core.api.amountInInventory +import core.api.inInventory +import core.api.removeItem +import core.api.sendMessage +import core.game.node.entity.Entity +import core.game.node.entity.player.Player +import core.game.node.item.Item +import core.game.world.map.zone.MapZone +import core.game.world.map.zone.ZoneBorders +import core.game.world.map.zone.ZoneBuilder +import core.plugin.Initializable +import core.plugin.Plugin +import org.rs09.consts.Items + +@Initializable + +// if you leave the abandoned mine, any instances of Glowing Fungus in your inventory should be removed and replaced with ashes. +class AbandonedMineZone : MapZone("Abandoned Mine", true), Plugin { + + override fun newInstance(arg: Any?): Plugin { + ZoneBuilder.configure(this) + return this + } + + override fun fireEvent(identifier: String?, vararg args: Any?): Any { + return Unit + } + + override fun leave(e: Entity?, logout: Boolean): Boolean { + + //todo come back to this and fix it the leave logic. + // Right now if you go from floor 2 to 1 it gets rid of the fungus. + // I could also just leave as-is. It doesn't impact the quest and still accomplishes the correct goal. + if (e!!.isPlayer){ + // remove any glowing fungus the player is carrying. + val fungi = amountInInventory(e as Player, Items.GLOWING_FUNGUS_4075) + if(removeItem(e, Item(Items.GLOWING_FUNGUS_4075, fungi), Container.INVENTORY)){ + addItemOrDrop(e, Items.ASHES_592, fungi) + sendMessage(e, "The strange fungus you are carrying crumbles to dust.") + } + } + return super.leave(e, logout) + } + + override fun configure() { + // mine floor 1 + register(ZoneBorders(3395, 9609, 3448, 9664)) + + // mine floors 2-6 + register(ZoneBorders(2680, 4415, 2820, 4609)) + } +} + +// If you enter level 5 of the abandoned mine, any tinderboxes with you should become damp tinderboxes. +// Light sources should also be extinguished. This is so that when you try to go to mine level 5 and the +// player says "i need a light source", it'll force you to get a glowing fungus. +class AbandonedMineL5Zone : MapZone("Abandoned Mine Level 5", true), Plugin { + + override fun newInstance(arg: Any?): Plugin { + ZoneBuilder.configure(this) + return this + } + + override fun fireEvent(identifier: String?, vararg args: Any?): Any { + return Unit + } + + override fun enter(e: Entity?): Boolean { + if (e!!.isPlayer){ + val tindies = amountInInventory(e as Player, Items.TINDERBOX_1553) + if(removeItem(e, Item(Items.TINDERBOX_1553, tindies), Container.INVENTORY)){ + addItemOrDrop(e, Items.DAMP_TINDERBOX_4073, tindies) + } + //todo extinguish light sources. + } + + return super.enter(e) + } + + override fun leave(e: Entity?, logout: Boolean): Boolean { + + if (e!!.isPlayer){ + val tindies = amountInInventory(e as Player, Items.DAMP_TINDERBOX_4073) + if(removeItem(e, Item(Items.DAMP_TINDERBOX_4073, tindies), Container.INVENTORY)){ + addItemOrDrop(e, Items.TINDERBOX_1553, tindies) + } + } + + return super.leave(e, logout) + } + + override fun configure() { + register(ZoneBorders(2680, 4415, 2755, 4480)) + } +} diff --git a/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMineListeners.kt b/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMineListeners.kt index 9870acf6b..51e4ffbcb 100644 --- a/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMineListeners.kt +++ b/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMineListeners.kt @@ -62,6 +62,16 @@ class HauntedMineListeners : InteractionListener { // points settings on(Scenery.POINTS_SETTINGS_4949, IntType.SCENERY, "Check") { player, node -> + // open iface 144 + + return@on true + } + + // you can't drop the fungus + on(Items.GLOWING_FUNGUS_4075, IntType.ITEM, "Drop") { player, node -> + removeItem(player,node) + produceGroundItem(player, Items.ASHES_592) + sendMessage(player,"When you drop the fungus it crumbles mysteriously to dust.") return@on true } diff --git a/Server/src/main/content/region/morytania/quest/hauntedmine/MinecartNPC.kt b/Server/src/main/content/region/morytania/quest/hauntedmine/MinecartNPC.kt new file mode 100644 index 000000000..0c8b25177 --- /dev/null +++ b/Server/src/main/content/region/morytania/quest/hauntedmine/MinecartNPC.kt @@ -0,0 +1,73 @@ +package content.region.morytania.quest.hauntedmine + +import core.api.* +import core.game.node.entity.npc.NPC +import core.game.node.entity.npc.NPCBehavior +import core.game.node.entity.player.Player +import core.game.world.map.Location +import core.tools.RandomFunction.random +import org.rs09.consts.NPCs + +// covers the behavior of the animated minecarts. They move back and forth along set paths, +// and if the player runs into one they push the player back with them while causing continuous 0-2 damage. + +// mine cart 1544 is used on level 6 during the Trayus Dayth fight. + +/* +@Initializable +class MinecartNPC(id: Int = 0, location: Location? = null) : AbstractNPC(id, location) { + + override fun construct(id: Int, location: Location, vararg objects: Any): AbstractNPC { + return MinecartNPC(id, location) + } + + override fun getIds(): IntArray { + return intArrayOf(NPCs.MINE_CART_1544, NPCs.MINE_CART_1545, NPCs.MINE_CART_1546, NPCs.MINE_CART_1547, NPCs.MINE_CART_1548) + } + +} + */ + +class MinecartNPCBehavior : NPCBehavior(NPCs.MINE_CART_1544, NPCs.MINE_CART_1545, NPCs.MINE_CART_1546, NPCs.MINE_CART_1547, NPCs.MINE_CART_1548) { + + override fun onCreation(self: NPC) { + + if (self.id == NPCs.MINE_CART_1545 && self.properties.spawnLocation == location(2727,4509,0)) { + val movementPath = arrayOf(Location.create(2727, 4517, 0), Location.create(2727, 4489, 0)) + self.configureMovementPath(*movementPath) + self.isWalks = true + } + + if (self.id == NPCs.MINE_CART_1546 && self.properties.spawnLocation == location(2697,4498,0)) { + val movementPath = arrayOf(Location.create(2696, 4498, 0), Location.create(2711, 4498, 0)) + self.configureMovementPath(*movementPath) + self.isWalks = true + } + + if (self.id == NPCs.MINE_CART_1547 && self.properties.spawnLocation == location(2715,4517,0)) { + val movementPath = arrayOf(Location.create(2696, 4498, 0), Location.create(2711, 4498, 0)) + self.configureMovementPath(*movementPath) + self.isWalks = true + } + + if (self.id == NPCs.MINE_CART_1548 && self.properties.spawnLocation == location(2739,4528,0)) { + val movementPath = arrayOf(Location.create(2739, 4531, 0), Location.create(2739, 4528, 0)) + self.configureMovementPath(*movementPath) + self.isWalks = true + } + } + + // logic to check for, push, and damage players. + override fun tick(self: NPC): Boolean { + for (p in self.viewport.currentPlane.players) { + // todo come back and refine the pushing, it doesn't work very well. + if (p.location == self.location /*|| p.location == self.location.transform(self.direction,1)*/) { + forceMove(p, p.location,self.location.transform(self.direction,1),0,0) + impact(p,random(0,2)) + } + } + + return true + } + +} \ No newline at end of file From 9f75ba700d6294d37c4422b66ce48d2cf54d3e3a Mon Sep 17 00:00:00 2001 From: aidan Date: Fri, 5 Dec 2025 16:47:27 -0600 Subject: [PATCH 6/7] points settings! --- Server/data/configs/ground_spawns.json | 14 ++- Server/data/configs/interface_configs.json | 6 ++ Server/data/configs/npc_spawns.json | 10 +- .../hauntedmine/AbandonedMineListeners.kt | 5 + .../quest/hauntedmine/HauntedMine.kt | 14 ++- .../quest/hauntedmine/HauntedMineListeners.kt | 98 +++++++++++++++++-- .../hauntedmine/PointsSettingsInterface.kt | 92 +++++++++++++++++ 7 files changed, 215 insertions(+), 24 deletions(-) create mode 100644 Server/src/main/content/region/morytania/quest/hauntedmine/PointsSettingsInterface.kt diff --git a/Server/data/configs/ground_spawns.json b/Server/data/configs/ground_spawns.json index 2ec02ce2c..a53dac279 100644 --- a/Server/data/configs/ground_spawns.json +++ b/Server/data/configs/ground_spawns.json @@ -265,7 +265,7 @@ }, { "item_id": "995", - "loc_data": "{2,3234,3560,0,100}-{2,3106,3547,0,100}-{1,3104,3558,0,100}-{1,3106,3534,0,100}-{2,3101,3564,0,100}-{4,3103,3579,0,100}-{384,3224,3830,0,50}-{384,3220,3824,0,50}-{1,2909,9800,0,150}-{4,2912,9801,0,150}-{8,2910,9803,0,150}-{5,2907,9807,0,150}-{6,2913,9806,0,150}-{1,2922,9820,0,150}-{1,2934,9834,0,150}-{1,2917,9850,0,150}-{1,2914,9849,0,150}-{3,3195,9834,0,150}-{4,3195,9820,0,150}-{66,3191,9821,0,150}-{56,3190,9819,0,150}-{26,3188,9819,0,150}-{26,3188,9820,0,150}-{35,3189,9819,0,150}-{4,3088,9898,0,150}-{1,3088,9899,0,150}-{1,3091,9899,0,150}-" + "loc_data": "{2,3234,3560,0,100}-{2,3106,3547,0,100}-{1,3104,3558,0,100}-{1,3106,3534,0,100}-{2,3101,3564,0,100}-{4,3103,3579,0,100}-{384,3224,3830,0,50}-{384,3220,3824,0,50}-{2,2772,4517,0,60}-{3,2770,4516,0,60}-{4,2771,4516,0,60}-{4,2772,4515,0,60}-{1,2909,9800,0,150}-{4,2912,9801,0,150}-{8,2910,9803,0,150}-{5,2907,9807,0,150}-{6,2913,9806,0,150}-{1,2922,9820,0,150}-{1,2934,9834,0,150}-{1,2917,9850,0,150}-{1,2914,9849,0,150}-{3,3195,9834,0,150}-{4,3195,9820,0,150}-{66,3191,9821,0,150}-{56,3190,9819,0,150}-{26,3188,9819,0,150}-{26,3188,9820,0,150}-{35,3189,9819,0,150}-{4,3088,9898,0,150}-{1,3088,9899,0,150}-{1,3091,9899,0,150}-" }, { "item_id": "1005", @@ -325,15 +325,19 @@ }, { "item_id": "1237", - "loc_data": "{60,2808,4572,0,1}-" + "loc_data": "{1,2808,4572,0,60}-" }, { "item_id": "1265", - "loc_data": "{1,3229,3218,2,100}-{1,2963,3216,0,30}-{1,3081,3429,0,50}-{60,2795,4579,0,1}-{60,2812,4572,0,1}-{1,3288,9442,0,90}-{1,3288,9431,0,90}-" + "loc_data": "{1,3229,3218,2,100}-{1,2963,3216,0,30}-{1,3081,3429,0,50}-{1,2801,4513,0,60}-{1,2801,4493,0,60}-{1,2795,4579,0,60}-{1,2812,4572,0,60}-{1,3288,9442,0,90}-{1,3288,9431,0,90}-" + }, + { + "item_id": "1267", + "loc_data": "{1,2770,4515,0,60}-" }, { "item_id": "1269", - "loc_data": "{60,2812,4571,0,1}-" + "loc_data": "{1,2812,4571,0,60}-" }, { "item_id": "1321", @@ -421,7 +425,7 @@ }, { "item_id": "1755", - "loc_data": "{1,2935,3286,0,90}-" + "loc_data": "{1,2935,3286,0,90}-{1,2800,4500,0,60}-{1,2803,4491,0,60}-" }, { "item_id": "1785", diff --git a/Server/data/configs/interface_configs.json b/Server/data/configs/interface_configs.json index 95087003a..39f883313 100644 --- a/Server/data/configs/interface_configs.json +++ b/Server/data/configs/interface_configs.json @@ -203,6 +203,12 @@ "walkable": "false", "tabIndex": "-1" }, + { + "id": "144", + "interfaceType": "1", + "walkable": "false", + "tabIndex": "-1" + }, { "id": "149", "interfaceType": "2", diff --git a/Server/data/configs/npc_spawns.json b/Server/data/configs/npc_spawns.json index 7e3546b5a..c24375ff8 100644 --- a/Server/data/configs/npc_spawns.json +++ b/Server/data/configs/npc_spawns.json @@ -157,7 +157,7 @@ }, { "npc_id": "47", - "loc_data": "{2821,3170,0,1,1}-{3341,3267,0,1,5}-{3076,3282,0,1,5}-{3089,3266,0,1,4}-{3091,3266,0,1,4}-{3097,3364,0,1,3}-{3102,3363,0,1,5}-{3127,3487,0,1,4}-{3125,3486,0,1,6}-{3127,3486,0,1,4}-{2339,9356,0,1,0}-{2354,9390,0,1,0}-{2361,9403,0,1,0}-{2362,9347,0,1,0}-{2603,9480,0,1,1}-{2600,9477,0,1,0}-{2579,9496,0,1,4}-{2580,9508,0,1,0}-{2571,9522,0,1,4}-{2565,9505,0,1,1}-{2566,9510,0,1,6}-{2594,9497,0,1,4}-{2852,9642,0,1,6}-{2858,9632,0,1,3}-{2568,9620,0,1,0}-{2573,9612,0,1,0}-{2579,9631,0,1,0}-{2580,9600,0,1,0}-{2580,9614,0,1,0}-{2580,9620,0,1,0}-{2580,9626,0,1,0}-{2583,9632,0,1,0}-{2584,9625,0,1,0}-{2584,9637,0,1,0}-{2589,9644,0,1,0}-{2590,9601,0,1,0}-{2590,9638,0,1,0}-{2591,9601,0,1,0}-{2591,9621,0,1,0}-{2594,9636,0,1,0}-{2594,9644,0,1,0}-{2597,9604,0,1,0}-{2607,9615,0,1,0}-{2608,9628,0,1,0}-{2614,9651,0,1,0}-{2614,9656,0,1,0}-{2615,9647,0,1,0}-{2615,9661,0,1,0}-{2616,9633,0,1,0}-{2618,9630,0,1,0}-{3108,9754,0,1,5}-{3110,9754,0,1,5}-{3108,9750,0,1,5}-{2592,9831,0,1,3}-{2588,9825,0,1,6}-{2583,9829,0,1,4}-{2581,9841,0,1,0}-{2597,9823,0,1,2}-{2579,9805,0,1,3}-{2576,9804,0,1,0}-{2573,9805,0,1,5}-{2571,9808,0,1,3}-{2576,9810,0,1,2}-{2587,9802,0,1,2}-{2592,9800,0,1,4}-{2596,9805,0,1,6}-{2601,9802,0,1,5}-{2585,9801,0,1,7}-{2594,9803,0,1,0}-{2590,9806,0,1,3}-{2612,9808,0,1,6}-{2604,9810,0,1,6}-{2579,9821,0,1,2}-{2576,9812,0,1,6}-{2580,9813,0,1,6}-{2600,9813,0,1,4}-{2599,9809,0,1,4}-{3158,3226,0,1,5}-{3160,3202,0,1,4}-{3192,3203,0,1,0}-{3194,3204,0,1,0}-{3196,3206,0,1,0}-{3197,3204,0,1,0}-{2654,9640,0,1,6}-{2655,9637,0,1,4}-{2656,9639,0,1,7}-{2651,9636,0,1,5}-{2648,9637,0,1,4}-{2651,9642,0,1,1}-{2654,9640,0,1,0}-{2654,9635,0,1,6}-{2655,9635,0,1,3}-{2664,9626,0,1,6}-{2664,9624,0,1,1}-{2661,9623,0,1,1}-{2663,9623,0,1,3}-{2664,9626,0,1,6}-{2930,9699,0,1,0}-{2933,9697,0,1,0}-{2932,9685,0,1,0}-{2930,9693,0,1,0}-{3001,3202,0,1,5}-{3235,3224,0,1,3}-{3229,3220,0,1,4}-{3211,3211,0,1,3}-{3225,3220,0,1,1}-{3237,3215,0,1,5}-{3211,3210,0,1,7}-{3227,3220,0,1,7}-{3233,3227,0,1,5}-{3227,3210,0,1,6}-{3228,3222,0,1,4}-{3229,3226,0,1,0}-{3236,3217,0,1,4}-{3259,3230,0,1,4}-{3233,3237,0,1,7}-{3205,3204,0,1,0}-{3206,3204,0,1,0}-{3205,3203,0,1,0}-{3206,3202,0,1,0}-{3207,3202,0,1,0}-{3208,3203,0,1,0}-{3243,3687,0,1,5}-{3249,3669,0,1,3}-{3252,3675,0,1,4}-{3252,3680,0,1,3}-{3259,3683,0,1,0}-{3475,9840,0,1,6}-{3481,9842,0,1,1}-{3486,9843,0,1,7}-{3483,9824,0,1,4}-{3496,9808,0,0,5}-{3490,9815,0,1,1}-{3478,9834,0,0,3}-{3490,9824,0,1,4}-{3225,9862,0,1,4}-{3222,9861,0,1,6}-{3220,9860,0,1,6}-{3219,9865,0,1,6}-{3237,9862,0,1,4}-{2536,2982,0,1,3}-{2531,2980,0,1,0}-{2522,2981,0,1,4}-{2545,2989,0,1,4}-{2523,2970,0,1,2}-{3026,3174,0,1,5}-{3019,3176,0,1,7}-{2801,3158,0,1,2}-{2514,3193,0,1,6}-{2518,3192,0,1,3}-{2507,3181,0,1,3}-{2508,3178,0,1,6}-{2511,3183,0,1,3}-{2515,3182,0,1,1}-{3021,3205,0,1,6}-{3019,3292,0,1,7}-{3018,3295,0,1,7}-{2531,3325,0,1,3}-{2530,3327,0,1,5}-{2521,3331,0,1,3}-{2526,3328,0,1,3}-{2523,3331,0,1,4}-{2523,3334,0,1,1}-{2531,3329,0,1,5}-{2532,3333,0,1,5}-{2780,4592,0,1,0}-{2783,4593,0,1,0}-{2777,4582,0,1,0}-{2785,4580,0,1,0}-{2786,4578,0,1,0}-{2787,4579,0,1,0}-{2812,4577,0,1,0}-{2802,4599,0,1,0}-{3276,9871,0,1,1}-{3277,9871,0,1,3}-" + "loc_data": "{2821,3170,0,1,1}-{3341,3267,0,1,5}-{3076,3282,0,1,5}-{3089,3266,0,1,4}-{3091,3266,0,1,4}-{3097,3364,0,1,3}-{3102,3363,0,1,5}-{3127,3487,0,1,4}-{3125,3486,0,1,6}-{3127,3486,0,1,4}-{2339,9356,0,1,0}-{2354,9390,0,1,0}-{2361,9403,0,1,0}-{2362,9347,0,1,0}-{2603,9480,0,1,1}-{2600,9477,0,1,0}-{2579,9496,0,1,4}-{2580,9508,0,1,0}-{2571,9522,0,1,4}-{2565,9505,0,1,1}-{2566,9510,0,1,6}-{2594,9497,0,1,4}-{2852,9642,0,1,6}-{2858,9632,0,1,3}-{2568,9620,0,1,0}-{2573,9612,0,1,0}-{2579,9631,0,1,0}-{2580,9600,0,1,0}-{2580,9614,0,1,0}-{2580,9620,0,1,0}-{2580,9626,0,1,0}-{2583,9632,0,1,0}-{2584,9625,0,1,0}-{2584,9637,0,1,0}-{2589,9644,0,1,0}-{2590,9601,0,1,0}-{2590,9638,0,1,0}-{2591,9601,0,1,0}-{2591,9621,0,1,0}-{2594,9636,0,1,0}-{2594,9644,0,1,0}-{2597,9604,0,1,0}-{2607,9615,0,1,0}-{2608,9628,0,1,0}-{2614,9651,0,1,0}-{2614,9656,0,1,0}-{2615,9647,0,1,0}-{2615,9661,0,1,0}-{2616,9633,0,1,0}-{2618,9630,0,1,0}-{3108,9754,0,1,5}-{3110,9754,0,1,5}-{3108,9750,0,1,5}-{2592,9831,0,1,3}-{2588,9825,0,1,6}-{2583,9829,0,1,4}-{2581,9841,0,1,0}-{2597,9823,0,1,2}-{2579,9805,0,1,3}-{2576,9804,0,1,0}-{2573,9805,0,1,5}-{2571,9808,0,1,3}-{2576,9810,0,1,2}-{2587,9802,0,1,2}-{2592,9800,0,1,4}-{2596,9805,0,1,6}-{2601,9802,0,1,5}-{2585,9801,0,1,7}-{2594,9803,0,1,0}-{2590,9806,0,1,3}-{2612,9808,0,1,6}-{2604,9810,0,1,6}-{2579,9821,0,1,2}-{2576,9812,0,1,6}-{2580,9813,0,1,6}-{2600,9813,0,1,4}-{2599,9809,0,1,4}-{3158,3226,0,1,5}-{3160,3202,0,1,4}-{3192,3203,0,1,0}-{3194,3204,0,1,0}-{3196,3206,0,1,0}-{3197,3204,0,1,0}-{2654,9640,0,1,6}-{2655,9637,0,1,4}-{2656,9639,0,1,7}-{2651,9636,0,1,5}-{2648,9637,0,1,4}-{2651,9642,0,1,1}-{2654,9640,0,1,0}-{2654,9635,0,1,6}-{2655,9635,0,1,3}-{2664,9626,0,1,6}-{2664,9624,0,1,1}-{2661,9623,0,1,1}-{2663,9623,0,1,3}-{2664,9626,0,1,6}-{2930,9699,0,1,0}-{2933,9697,0,1,0}-{2932,9685,0,1,0}-{2930,9693,0,1,0}-{3001,3202,0,1,5}-{3235,3224,0,1,3}-{3229,3220,0,1,4}-{3211,3211,0,1,3}-{3225,3220,0,1,1}-{3237,3215,0,1,5}-{3211,3210,0,1,7}-{3227,3220,0,1,7}-{3233,3227,0,1,5}-{3227,3210,0,1,6}-{3228,3222,0,1,4}-{3229,3226,0,1,0}-{3236,3217,0,1,4}-{3259,3230,0,1,4}-{3233,3237,0,1,7}-{3205,3204,0,1,0}-{3206,3204,0,1,0}-{3205,3203,0,1,0}-{3206,3202,0,1,0}-{3207,3202,0,1,0}-{3208,3203,0,1,0}-{3243,3687,0,1,5}-{3249,3669,0,1,3}-{3252,3675,0,1,4}-{3252,3680,0,1,3}-{3259,3683,0,1,0}-{3475,9840,0,1,6}-{3481,9842,0,1,1}-{3486,9843,0,1,7}-{3483,9824,0,1,4}-{3496,9808,0,0,5}-{3490,9815,0,1,1}-{3478,9834,0,0,3}-{3490,9824,0,1,4}-{3225,9862,0,1,4}-{3222,9861,0,1,6}-{3220,9860,0,1,6}-{3219,9865,0,1,6}-{3237,9862,0,1,4}-{2536,2982,0,1,3}-{2531,2980,0,1,0}-{2522,2981,0,1,4}-{2545,2989,0,1,4}-{2523,2970,0,1,2}-{3026,3174,0,1,5}-{3019,3176,0,1,7}-{2801,3158,0,1,2}-{2514,3193,0,1,6}-{2518,3192,0,1,3}-{2507,3181,0,1,3}-{2508,3178,0,1,6}-{2511,3183,0,1,3}-{2515,3182,0,1,1}-{3021,3205,0,1,6}-{3019,3292,0,1,7}-{3018,3295,0,1,7}-{2531,3325,0,1,3}-{2530,3327,0,1,5}-{2521,3331,0,1,3}-{2526,3328,0,1,3}-{2523,3331,0,1,4}-{2523,3334,0,1,1}-{2531,3329,0,1,5}-{2532,3333,0,1,5}-{2798,4531,0,1,0}-{2800,4526,0,1,0}-{2803,4526,0,1,0}-{2780,4592,0,1,0}-{2783,4593,0,1,0}-{2777,4582,0,1,0}-{2785,4580,0,1,0}-{2786,4578,0,1,0}-{2787,4579,0,1,0}-{2812,4577,0,1,0}-{2802,4599,0,1,0}-{3276,9871,0,1,1}-{3277,9871,0,1,3}-" }, { "npc_id": "48", @@ -245,7 +245,7 @@ }, { "npc_id": "78", - "loc_data": "{2585,3479,0,1,1}-{2589,3480,0,1,2}-{2582,3476,0,1,3}-{2588,3485,0,1,4}-{2580,3490,0,1,5}-{2577,3482,0,1,6}-{2583,3484,0,1,7}-{3073,3961,0,1,0}-{3074,3952,0,1,0}-{3075,3955,0,1,0}-{3076,3961,0,1,0}-{3077,3949,0,1,0}-{3079,3957,0,1,0}-{3080,3961,0,1,0}-{2568,9528,0,1,5}-{2573,9530,0,1,3}-{2575,9525,0,1,6}-{2571,9528,0,1,7}-{2862,9569,0,1,4}-{2857,9571,0,1,7}-{2837,9561,0,1,1}-{2608,9818,0,1,7}-{2609,9825,0,1,5}-{2607,9830,0,1,1}-{2605,9837,0,1,1}-{2607,9833,0,1,6}-{2905,9832,0,1,0}-{2907,9831,0,1,0}-{2913,9828,0,1,0}-{2921,9826,0,1,0}-{2924,9831,0,1,0}-{2921,9834,0,1,0}-{2918,9831,0,1,0}-{2908,9838,0,1,0}-{2913,9841,0,1,0}-{2672,9805,0,1,3}-{2663,9804,0,1,4}-{2658,9809,0,1,5}-{3725,9369,0,1,1}-{3737,9390,0,1,4}-{3738,9399,0,1,0}-{3740,9407,0,1,1}-{3765,9407,0,1,1}-{3762,9395,0,1,3}-{3725,9390,0,1,3}-{3753,9387,0,1,0}-{3728,9382,0,1,3}-{3729,9360,0,1,6}-{3755,9424,0,1,0}-{3760,9440,0,1,4}-{3737,9425,0,1,7}-{3720,9430,0,1,4}-{3736,9451,0,1,3}-{3728,9463,0,1,2}-{3740,9462,0,1,4}-{3770,9463,0,1,1}-{3752,9450,0,1,6}-{3762,9432,0,1,1}-{3733,9421,0,1,7}-{2759,3402,0,1,2}-{2756,3400,0,1,0}-{3787,9459,0,1,1}-{3803,9447,0,1,4}-{3778,9438,0,1,1}-{3786,9422,0,1,4}-{3800,9419,0,1,3}-{3797,9427,0,1,4}-{3820,9432,0,1,5}-{3825,9414,0,1,3}-{3833,9415,0,1,0}-{3825,9449,0,1,3}-{3827,9459,0,1,1}-{3818,9466,0,1,4}-{3799,9460,0,1,1}-{3794,9451,0,1,1}-{2543,9564,0,1,1}-{2543,9562,0,1,1}-{2542,9557,0,1,1}-{2542,9569,0,1,4}-{2540,9566,0,1,0}-{2549,9568,0,1,6}-{2538,9568,0,1,3}-" + "loc_data": "{2585,3479,0,1,1}-{2589,3480,0,1,2}-{2582,3476,0,1,3}-{2588,3485,0,1,4}-{2580,3490,0,1,5}-{2577,3482,0,1,6}-{2583,3484,0,1,7}-{3073,3961,0,1,0}-{3074,3952,0,1,0}-{3075,3955,0,1,0}-{3076,3961,0,1,0}-{3077,3949,0,1,0}-{3079,3957,0,1,0}-{3080,3961,0,1,0}-{2568,9528,0,1,5}-{2573,9530,0,1,3}-{2575,9525,0,1,6}-{2571,9528,0,1,7}-{2862,9569,0,1,4}-{2857,9571,0,1,7}-{2837,9561,0,1,1}-{2608,9818,0,1,7}-{2609,9825,0,1,5}-{2607,9830,0,1,1}-{2605,9837,0,1,1}-{2607,9833,0,1,6}-{2905,9832,0,1,0}-{2907,9831,0,1,0}-{2913,9828,0,1,0}-{2921,9826,0,1,0}-{2924,9831,0,1,0}-{2921,9834,0,1,0}-{2918,9831,0,1,0}-{2908,9838,0,1,0}-{2913,9841,0,1,0}-{2672,9805,0,1,3}-{2663,9804,0,1,4}-{2658,9809,0,1,5}-{3725,9369,0,1,1}-{3737,9390,0,1,4}-{3738,9399,0,1,0}-{3740,9407,0,1,1}-{3765,9407,0,1,1}-{3762,9395,0,1,3}-{3725,9390,0,1,3}-{3753,9387,0,1,0}-{3728,9382,0,1,3}-{3729,9360,0,1,6}-{3755,9424,0,1,0}-{3760,9440,0,1,4}-{3737,9425,0,1,7}-{3720,9430,0,1,4}-{3736,9451,0,1,3}-{3728,9463,0,1,2}-{3740,9462,0,1,4}-{3770,9463,0,1,1}-{3752,9450,0,1,6}-{3762,9432,0,1,1}-{3733,9421,0,1,7}-{2759,3402,0,1,2}-{2756,3400,0,1,0}-{2788,4503,0,1,0}-{2789,4499,0,1,0}-{3787,9459,0,1,1}-{3803,9447,0,1,4}-{3778,9438,0,1,1}-{3786,9422,0,1,4}-{3800,9419,0,1,3}-{3797,9427,0,1,4}-{3820,9432,0,1,5}-{3825,9414,0,1,3}-{3833,9415,0,1,0}-{3825,9449,0,1,3}-{3827,9459,0,1,1}-{3818,9466,0,1,4}-{3799,9460,0,1,1}-{3794,9451,0,1,1}-{2543,9564,0,1,1}-{2543,9562,0,1,1}-{2542,9557,0,1,1}-{2542,9569,0,1,4}-{2540,9566,0,1,0}-{2549,9568,0,1,6}-{2538,9568,0,1,3}-" }, { "npc_id": "80", @@ -1221,7 +1221,7 @@ }, { "npc_id": "412", - "loc_data": "{3341,3478,0,1,0}-{3343,3484,0,1,0}-{3345,3484,0,1,0}-{3350,3493,0,1,0}-{3353,3494,0,1,0}-{3361,3484,0,1,0}-{3364,3489,0,1,0}-{3370,3497,0,1,0}-{3379,3478,0,1,0}-{3379,3484,0,1,0}-{3387,3483,0,1,0}-{3388,3494,0,1,0}-{3389,3483,0,1,0}-{3588,3472,0,1,0}-{3598,3509,0,1,0}-{3599,3486,0,1,0}-{3607,3462,0,1,0}-{3611,3499,0,1,0}-{3613,3482,0,1,0}-{3627,3511,0,1,0}-{3628,3473,0,1,0}-{3636,3466,0,1,0}-{3639,3510,0,1,0}-{3411,3536,0,1,0}-{3418,3522,0,1,0}-{3425,3525,0,1,0}-{3429,3522,0,1,0}-{3432,3527,0,1,0}-{3434,3521,0,1,0}-{3445,3526,0,1,0}-{3419,9646,0,1,0}-{3418,9642,0,1,0}-{3414,9643,0,1,0}-{3411,9644,0,1,0}-{3410,9641,0,1,0}-{3409,9638,0,1,0}-{3419,9630,0,1,0}-{3421,9629,0,1,0}-{3433,9638,0,1,0}-{3434,9636,0,1,0}-{3436,9636,0,1,0}-{3423,9625,0,1,0}-{2728,10122,0,1,1}-{2735,10123,0,1,3}-{2733,10129,0,1,1}-{2728,10133,0,1,6}-{2722,10133,0,1,6}-{2736,10137,0,1,1}-{2732,10142,0,1,0}-{2726,10142,0,1,6}-{2729,10140,0,1,3}-{2720,10144,0,1,6}-{2712,10142,0,1,3}-{3565,3503,0,1,0}-{3567,3481,0,1,0}-{3580,3491,0,1,0}-" + "loc_data": "{3341,3478,0,1,0}-{3343,3484,0,1,0}-{3345,3484,0,1,0}-{3350,3493,0,1,0}-{3353,3494,0,1,0}-{3361,3484,0,1,0}-{3364,3489,0,1,0}-{3370,3497,0,1,0}-{3379,3478,0,1,0}-{3379,3484,0,1,0}-{3387,3483,0,1,0}-{3388,3494,0,1,0}-{3389,3483,0,1,0}-{3588,3472,0,1,0}-{3598,3509,0,1,0}-{3599,3486,0,1,0}-{3607,3462,0,1,0}-{3611,3499,0,1,0}-{3613,3482,0,1,0}-{3627,3511,0,1,0}-{3628,3473,0,1,0}-{3636,3466,0,1,0}-{3639,3510,0,1,0}-{3411,3536,0,1,0}-{3418,3522,0,1,0}-{3425,3525,0,1,0}-{3429,3522,0,1,0}-{3432,3527,0,1,0}-{3434,3521,0,1,0}-{3445,3526,0,1,0}-{3419,9646,0,1,0}-{3418,9642,0,1,0}-{3414,9643,0,1,0}-{3411,9644,0,1,0}-{3410,9641,0,1,0}-{3409,9638,0,1,0}-{3419,9630,0,1,0}-{3421,9629,0,1,0}-{3433,9638,0,1,0}-{3434,9636,0,1,0}-{3436,9636,0,1,0}-{3423,9625,0,1,0}-{2728,10122,0,1,1}-{2735,10123,0,1,3}-{2733,10129,0,1,1}-{2728,10133,0,1,6}-{2722,10133,0,1,6}-{2736,10137,0,1,1}-{2732,10142,0,1,0}-{2726,10142,0,1,6}-{2729,10140,0,1,3}-{2720,10144,0,1,6}-{2712,10142,0,1,3}-{3565,3503,0,1,0}-{3567,3481,0,1,0}-{3580,3491,0,1,0}-{2761,4500,0,1,0}-{2759,4498,0,1,0}-{2761,4496,0,1,0}-{2783,4490,0,1,0}-{2784,4487,0,1,0}-{2792,4488,0,1,0}-" }, { "npc_id": "419", @@ -2781,7 +2781,7 @@ }, { "npc_id": "1015", - "loc_data": "{2792,4597,0,0,0}-{2785,4594,0,0,0}-{2783,4591,0,0,0}-{2774,4592,0,0,0}-{2770,4591,0,0,0}-{2769,4593,0,0,0}-" + "loc_data": "{2716,4443,0,0,0}-{2719,4442,0,0,0}-{2724,4442,0,0,0}-{2729,4447,0,0,0}-{2728,4445,0,0,0}-{2735,4435,0,0,0}-{2738,4439,0,0,0}-{2713,4438,0,0,0}-{2792,4597,0,0,0}-{2785,4594,0,0,0}-{2783,4591,0,0,0}-{2774,4592,0,0,0}-{2770,4591,0,0,0}-{2769,4593,0,0,0}-" }, { "npc_id": "1017", @@ -3869,7 +3869,7 @@ }, { "npc_id": "1538", - "loc_data": "{2801,4580,0,0,0}-{2802,4580,0,0,0}-{2800,4573,0,0,0}-{2807,4572,0,0,0}-{2810,4573,0,0,0}-{2813,4571,0,0,0}-{2811,4567,0,0,0}-" + "loc_data": "{2804,4525,0,0,0}-{2772,4516,0,0,0}-{2773,4515,0,0,0}-{2801,4580,0,0,0}-{2802,4580,0,0,0}-{2800,4573,0,0,0}-{2807,4572,0,0,0}-{2810,4573,0,0,0}-{2813,4571,0,0,0}-{2811,4567,0,0,0}-" }, { "npc_id": "1542", diff --git a/Server/src/main/content/region/morytania/quest/hauntedmine/AbandonedMineListeners.kt b/Server/src/main/content/region/morytania/quest/hauntedmine/AbandonedMineListeners.kt index 21eb6a259..2c5244ea6 100644 --- a/Server/src/main/content/region/morytania/quest/hauntedmine/AbandonedMineListeners.kt +++ b/Server/src/main/content/region/morytania/quest/hauntedmine/AbandonedMineListeners.kt @@ -251,6 +251,11 @@ class AbandonedMineListeners : InteractionListener { loc.y in 4485..4487 ) { + setVarp(player, HauntedMine.pointsSettingsVarp, (0..511).random()) + + player.debug("points varp is:") + player.debug(getVarp(player,HauntedMine.pointsSettingsVarp).toString()) + animate(player, 828) teleport(player, Location.create(2790, 4486, 0)) diff --git a/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMine.kt b/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMine.kt index f69d39520..636810629 100644 --- a/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMine.kt +++ b/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMine.kt @@ -29,14 +29,20 @@ import org.rs09.consts.Items // ::setqueststage 73 0 to reset quest @Initializable -class HauntedMine : Quest(Quests.HAUNTED_MINE,73 ,72 ,2 ,382, 0, 1, 11) { +class HauntedMine : Quest(Quests.HAUNTED_MINE,73 ,72 ,2 ,hauntedMineVarp, 0, 1, 11) { companion object { const val questName = "Haunted Mine" - const val attributeKilledTreusDayth = "/save:quest:hauntedmine-killedtreusdayth" // True after you've killed Treus Dayth. - const val attributeKeyMentioned = "/save:quest:hauntedmine-keymentioned" // True after the player asks about a way into the mines. - const val attributeZealotKeyReturned = "/save:quest:hauntedmine-zealotkeyreturned" // True after you return the zealot's key after the quest. Note that this should not reset after quest completion + const val hauntedMineVarp = 382 + const val pointsSettingsVarp = 383 + const val pointsSettingsInterface = 144 + + const val attributeFungusPlaced = "/save:quest:hauntedmine-fungusplaced" // True after you put a fungus in the minecart + const val attributeCartSent = "/save:quest:hauntedmine-cartsent" // True after you solve the cart puzzle + const val attributeKilledTreusDayth = "/save:quest:hauntedmine-killedtreusdayth" // True after you've killed Treus Dayth. + const val attributeKeyMentioned = "/save:quest:hauntedmine-keymentioned" // True after the player asks about a way into the mines. + const val attributeZealotKeyReturned = "/save:quest:hauntedmine-zealotkeyreturned" // True after you return the zealot's key after the quest. Note that this should not reset after quest completion } // Quest Journal ref: https://youtu.be/CD77NeKz1J4?si=AxNEg5YZU5oJ3T11&t=231 diff --git a/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMineListeners.kt b/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMineListeners.kt index 51e4ffbcb..aad98c546 100644 --- a/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMineListeners.kt +++ b/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMineListeners.kt @@ -1,8 +1,6 @@ package content.region.morytania.quest.hauntedmine -import content.region.morytania.quest.hauntedmine.HauntedMine.Companion.attributeKeyMentioned import core.api.* -import core.game.global.action.DoorActionHandler import core.game.interaction.IntType import core.game.interaction.InteractionListener import core.game.node.item.Item @@ -17,17 +15,17 @@ class HauntedMineListeners : InteractionListener { override fun defineListeners() { - onUseWith(ITEM, Items.SALVE_SHARD_4082, Items.BALL_OF_WOOL_1759) { player, used, _ -> - removeItem(player, Items.SALVE_SHARD_4082) - removeItem(player, Items.BALL_OF_WOOL_1759) + onUseWith(ITEM, Items.SALVE_SHARD_4082, Items.BALL_OF_WOOL_1759) { player, used, with -> + removeItem(player, used) + removeItem(player, with) addItem(player, Items.SALVE_AMULET_4081) sendMessage(player, "You string the salve amulet.") return@onUseWith true } // you should not be able to pickpocket the key after the quest, but that should be taken care of by clearing the attributeKeyMentioned when the quest finishes. - on(NPCs.ZEALOT_1528, IntType.NPC, "pickpocket"){ player, node -> - if(getAttribute(player, attributeKeyMentioned, false) && !player.inventory.containsItem(Item(Items.ZEALOTS_KEY_4078))){ + on(NPCs.ZEALOT_1528, IntType.NPC, "pickpocket"){ player, _ -> + if(getAttribute(player, HauntedMine.attributeKeyMentioned, false) && !player.inventory.containsItem(Item(Items.ZEALOTS_KEY_4078))){ player.lock() GameWorld.Pulser.submit(object : Pulse(){ var counter = 0 @@ -45,7 +43,7 @@ class HauntedMineListeners : InteractionListener { }) addItemOrDrop(player, Items.ZEALOTS_KEY_4078) sendMessage(player, "You pick the zealot's pocket and retrieve a small silvery key.") - } else if(getAttribute(player, attributeKeyMentioned, false) && player.inventory.containsItem(Item(Items.ZEALOTS_KEY_4078))) { + } else if(getAttribute(player, HauntedMine.attributeKeyMentioned, false) && player.inventory.containsItem(Item(Items.ZEALOTS_KEY_4078))) { sendMessage(player, "I've already picked his pockets.") } else { sendMessage(player, "I doubt he's got much of value on him.") @@ -61,8 +59,8 @@ class HauntedMineListeners : InteractionListener { } // points settings - on(Scenery.POINTS_SETTINGS_4949, IntType.SCENERY, "Check") { player, node -> - // open iface 144 + on(Scenery.POINTS_SETTINGS_4949, IntType.SCENERY, "Check") { player, _ -> + openOverlay(player, HauntedMine.pointsSettingsInterface) return@on true } @@ -75,5 +73,85 @@ class HauntedMineListeners : InteractionListener { return@on true } + + // Lever A + on(Scenery.LEVER_4951, IntType.SCENERY, "Pull") { player, node -> + replaceScenery(node as core.game.node.scenery.Scenery, Scenery.LEVER_4958, 2) + val varp = getVarp(player, HauntedMine.pointsSettingsVarp) xor 1.shl(2) + setVarp(player, HauntedMine.pointsSettingsVarp, varp) + sendMessage(player, "You pull the lever. The old points creak into place.") + + return@on true + } + + // Lever B + on(Scenery.LEVER_4950, IntType.SCENERY, "Pull") { player, node -> + replaceScenery(node as core.game.node.scenery.Scenery, Scenery.LEVER_4958, 2) + val varp = getVarp(player, HauntedMine.pointsSettingsVarp) xor 1.shl(1) + setVarp(player, HauntedMine.pointsSettingsVarp, varp) + sendMessage(player, "You pull the lever. The old points creak into place.") + + return@on true + } + + // Lever C + on(Scenery.LEVER_4952, IntType.SCENERY, "Pull") { player, node -> + replaceScenery(node as core.game.node.scenery.Scenery, Scenery.LEVER_4958, 2) + val varp = getVarp(player, HauntedMine.pointsSettingsVarp) xor 1.shl(3) + setVarp(player, HauntedMine.pointsSettingsVarp, varp) + sendMessage(player, "You pull the lever. The old points creak into place.") + + return@on true + } + + // Lever D + on(Scenery.LEVER_4953, IntType.SCENERY, "Pull") { player, node -> + replaceScenery(node as core.game.node.scenery.Scenery, Scenery.LEVER_4958, 2) + val varp = getVarp(player, HauntedMine.pointsSettingsVarp) xor 1.shl(4) + setVarp(player, HauntedMine.pointsSettingsVarp, varp) + sendMessage(player, "You pull the lever. The old points creak into place.") + + return@on true + } + + // Lever E + on(Scenery.LEVER_4954, IntType.SCENERY, "Pull") { player, node -> + replaceScenery(node as core.game.node.scenery.Scenery, Scenery.LEVER_4958, 2) + val varp = getVarp(player, HauntedMine.pointsSettingsVarp) xor 1.shl(5) + setVarp(player, HauntedMine.pointsSettingsVarp, varp) + sendMessage(player, "You pull the lever. The old points creak into place.") + + return@on true + } + + // Lever I + on(Scenery.LEVER_4955, IntType.SCENERY, "Pull") { player, node -> + replaceScenery(node as core.game.node.scenery.Scenery, Scenery.LEVER_4958, 2) + val varp = getVarp(player, HauntedMine.pointsSettingsVarp) xor 1.shl(6) + setVarp(player, HauntedMine.pointsSettingsVarp, varp) + sendMessage(player, "You pull the lever. The old points creak into place.") + + return@on true + } + + // Lever J + on(Scenery.LEVER_4956, IntType.SCENERY, "Pull") { player, node -> + replaceScenery(node as core.game.node.scenery.Scenery, Scenery.LEVER_4958, 2) + val varp = getVarp(player, HauntedMine.pointsSettingsVarp) xor 1.shl(7) + setVarp(player, HauntedMine.pointsSettingsVarp, varp) + sendMessage(player, "You pull the lever. The old points creak into place.") + + return@on true + } + + // Lever K + on(Scenery.LEVER_4957, IntType.SCENERY, "Pull") { player, node -> + replaceScenery(node as core.game.node.scenery.Scenery, Scenery.LEVER_4958, 2) + val varp = getVarp(player, HauntedMine.pointsSettingsVarp) xor 1.shl(8) + setVarp(player, HauntedMine.pointsSettingsVarp, varp) + sendMessage(player, "You pull the lever. The old points creak into place.") + + return@on true + } } } \ No newline at end of file diff --git a/Server/src/main/content/region/morytania/quest/hauntedmine/PointsSettingsInterface.kt b/Server/src/main/content/region/morytania/quest/hauntedmine/PointsSettingsInterface.kt new file mode 100644 index 000000000..d3b39a84a --- /dev/null +++ b/Server/src/main/content/region/morytania/quest/hauntedmine/PointsSettingsInterface.kt @@ -0,0 +1,92 @@ +package content.region.morytania.quest.hauntedmine + +import core.api.* +import core.game.interaction.InterfaceListener +import core.game.node.entity.player.Player + +/* + * Varp 383 structure and notes: + * Offsets 0-8 (bits 1-9) correspond to the different operable lever positions. Note that levers F G H are inoperable. + * + * Offset 8 7 6 5 4 3 2 1 0 + * Lever K J I E D C A B + * Default Bits 0 0 0 0 0 0 0 0 0 = 0 + * Solved Bits 0 0 1 1 0 0 1 1 0 = 102 (5 of the seven sources agree this is the correct solution. The player must match it exactly.) + * + * Offsets 12-20 (bits 13-21) correspond to minecart animations. + * + * offset 12 - minecart at start + * offset 14 - minecart at correct end + * offset 15 - SW bad end + * offset 16 - SSW bad end + * offset 17 - SSE bad end + * offset 18 - SE bad end + * offset 19 - E bad end + * offset 20 - minecart going back to start + * + * The F point doesn't seem to let the cart through in the right direction, but it's inoperable. + * I guess that is just an authentic typo. I don't see how the cart works otherwise. + * + * Note this varp has a randomized start. One of the written sources states that it's unique per player. + * + */ + +class PointsSettingsInterface : InterfaceListener { + + override fun defineInterfaceListeners() { + on(HauntedMine.pointsSettingsInterface) { player, _, _, buttonID, _, _ -> + when (buttonID) { + // button 147 is START + 147 -> checkCartRoute(player).also { closeInterface(player) } + + // button 188 is X (close) + 188 -> closeInterface(player) + } + + return@on true + } + } + + private fun checkCartRoute(player: Player) { + + player.debug("points varp is:") + player.debug(getVarp(player,HauntedMine.pointsSettingsVarp).toString()) + + // 5 of my 7 sources agree this is the correct solution. I have taken that to be the exact one, and the player must match it. + if(getVarp(player,HauntedMine.pointsSettingsVarp) == 102 || getVarp(player,HauntedMine.pointsSettingsVarp) == 103) { // 103 could also be an answer because the random function that sets the initial varp stage might make the first bit a 1. afaik that bit does nothing. + // if right, update the varp with the cart graphic and set an attribute that says you were successful. Player gets a hint message. + // todo make a nice cutscene like the video source. https://youtu.be/PMn0LRo4MCo?si=pi6gGDFnlgW_TPX7&t=498 + val varp = getVarp(player, HauntedMine.pointsSettingsVarp) xor 7.shl(12) + setVarp(player, HauntedMine.pointsSettingsVarp, varp) + setAttribute(player, HauntedMine.attributeCartSent, true) + sendDialogue(player, "I wonder if that cart is anywhere useful now?") + } else { + // if wrong, clear the fungus out of the cart. + setAttribute(player, HauntedMine.attributeFungusPlaced, false) + } + } +} + +/* + * From "498 interface configs": + * Dec. Binary + * Interface 144 child 220 config: [383, 0] 00000 + * Interface 144 child 208 config: [383, 1] 00001 + * Interface 144 child 209 config: [383, 2] 00010 + * Interface 144 child 210 config: [383, 3] 00011 + * Interface 144 child 211 config: [383, 4] 00100 + * Interface 144 child 212 config: [383, 5] 00101 + * Interface 144 child 213 config: [383, 6] 00110 + * Interface 144 child 214 config: [383, 7] 00111 + * Interface 144 child 215 config: [383, 8] 01000 + * Interface 144 child 221 config: [383, 13] 01101 + * Interface 144 child 369 config: [383, 13] + * Interface 144 child 368 config: [383, 13] + * Interface 144 child 277 config: [383, 14] 01110 + * Interface 144 child 258 config: [383, 15] 01111 + * Interface 144 child 297 config: [383, 16] 10000 + * Interface 144 child 308 config: [383, 17] 10001 + * Interface 144 child 320 config: [383, 18] 10010 + * Interface 144 child 354 config: [383, 19] 10011 + * Interface 144 child 367 config: [383, 20] 10100 + */ \ No newline at end of file From 62eb248109d932478ec65f422fd1799be7842044 Mon Sep 17 00:00:00 2001 From: aidan Date: Sun, 7 Dec 2025 15:11:09 -0600 Subject: [PATCH 7/7] I've got most of the stuff up till the dayth fight now. --- .../handlers/scenery/FieldPickingPlugin.java | 12 +- .../hauntedmine/AbandonedMineGhostZone.kt | 40 +++++ .../hauntedmine/AbandonedMineLevelFiveZone.kt | 58 +++++++ .../hauntedmine/AbandonedMineListeners.kt | 59 +++++-- .../quest/hauntedmine/AbandonedMineZone.kt | 58 +------ .../quest/hauntedmine/HauntedMine.kt | 7 + .../quest/hauntedmine/HauntedMineListeners.kt | 146 +++++++++++++++++- .../quest/hauntedmine/LiftGhostNPC.kt | 59 +++++++ .../quest/hauntedmine/MinecartNPC.kt | 2 +- .../hauntedmine/PointsSettingsInterface.kt | 8 +- .../quest/hauntedmine/TreusDaythNPC.kt | 2 + 11 files changed, 372 insertions(+), 79 deletions(-) create mode 100644 Server/src/main/content/region/morytania/quest/hauntedmine/AbandonedMineGhostZone.kt create mode 100644 Server/src/main/content/region/morytania/quest/hauntedmine/AbandonedMineLevelFiveZone.kt create mode 100644 Server/src/main/content/region/morytania/quest/hauntedmine/LiftGhostNPC.kt create mode 100644 Server/src/main/content/region/morytania/quest/hauntedmine/TreusDaythNPC.kt diff --git a/Server/src/main/content/global/handlers/scenery/FieldPickingPlugin.java b/Server/src/main/content/global/handlers/scenery/FieldPickingPlugin.java index 1d0fa5c07..1eb9d962b 100644 --- a/Server/src/main/content/global/handlers/scenery/FieldPickingPlugin.java +++ b/Server/src/main/content/global/handlers/scenery/FieldPickingPlugin.java @@ -105,11 +105,13 @@ public final class FieldPickingPlugin extends OptionHandler { if (!isBloomPlant) { SceneryBuilder.replace(plant == PickingPlant.BANANA_TREE_4 ? full : object, object.transform(banana ? plant.respawn : 0), banana ? 300 : plant.respawn); } - if (!plant.name().startsWith("NETTLES")) { - player.getPacketDispatch().sendMessage("You pick a " + reward.getName().toLowerCase() + "."); - } else { - player.getPacketDispatch().sendMessage("You pick a handful of nettles."); - } + if (plant.name().startsWith("NETTLES")) { + player.getPacketDispatch().sendMessage("You pick a handful of nettles."); + } else if (plant.name().startsWith("GLOWING")) { + player.getPacketDispatch().sendMessage("You pull the fungus from the water, it is very cold to the touch."); + } else { + player.getPacketDispatch().sendMessage("You pick a " + reward.getName().toLowerCase() + "."); + } return true; } }); diff --git a/Server/src/main/content/region/morytania/quest/hauntedmine/AbandonedMineGhostZone.kt b/Server/src/main/content/region/morytania/quest/hauntedmine/AbandonedMineGhostZone.kt new file mode 100644 index 000000000..680cc7539 --- /dev/null +++ b/Server/src/main/content/region/morytania/quest/hauntedmine/AbandonedMineGhostZone.kt @@ -0,0 +1,40 @@ +package content.region.morytania.quest.hauntedmine + +import core.api.* +import core.game.node.entity.Entity +import core.game.node.entity.player.Player +import core.game.world.map.zone.MapZone +import core.game.world.map.zone.ZoneBorders +import core.game.world.map.zone.ZoneBuilder +import core.plugin.Initializable +import core.plugin.Plugin +import org.rs09.consts.NPCs + +@Initializable + +class AbandonedMineLiftGhostZone : MapZone("Abandoned Mine Level 4 Lift Ghost Zone", true), Plugin { + + override fun newInstance(arg: Any?): Plugin { + ZoneBuilder.configure(this) + return this + } + + override fun fireEvent(identifier: String?, vararg args: Any?): Any { + return Unit + } + + // spawn the ghost that tries to turn the lift off if you've turned the lift on. + override fun enter(e: Entity?): Boolean { + if (e!!.isPlayer && getVarbit(e as Player, HauntedMine.liftMachineryVarbit) == 1 && !getAttribute(e, HauntedMine.attributeGhostSpawned, false)){ + LiftGhostNPC(NPCs.MISCHIEVOUS_GHOST_1551, location(2802, 4516,0)).init() + setAttribute(e, HauntedMine.attributeGhostSpawned, true) + } + + return super.enter(e) + } + + override fun configure() { + // just two squares, when the player crosses into it, we spawn the ghost that tries to turn off the lift. + register(ZoneBorders(2802, 4516, 2803, 4516)) + } +} diff --git a/Server/src/main/content/region/morytania/quest/hauntedmine/AbandonedMineLevelFiveZone.kt b/Server/src/main/content/region/morytania/quest/hauntedmine/AbandonedMineLevelFiveZone.kt new file mode 100644 index 000000000..4d022fa9e --- /dev/null +++ b/Server/src/main/content/region/morytania/quest/hauntedmine/AbandonedMineLevelFiveZone.kt @@ -0,0 +1,58 @@ +package content.region.morytania.quest.hauntedmine + +import core.api.* +import core.game.node.entity.Entity +import core.game.node.entity.player.Player +import core.game.node.item.Item +import core.game.world.map.zone.MapZone +import core.game.world.map.zone.ZoneBorders +import core.game.world.map.zone.ZoneBuilder +import core.plugin.Initializable +import core.plugin.Plugin +import org.rs09.consts.Items + +@Initializable + +// If you enter level 5 of the abandoned mine, any tinderboxes with you should become damp tinderboxes. +// Light sources should also be extinguished. This is so that when you try to go to mine level 5 and the +// player says "i need a light source", it'll force you to get a glowing fungus. +class AbandonedMineL5Zone : MapZone("Abandoned Mine Level 5", true), Plugin { + + override fun newInstance(arg: Any?): Plugin { + ZoneBuilder.configure(this) + return this + } + + override fun fireEvent(identifier: String?, vararg args: Any?): Any { + return Unit + } + + override fun enter(e: Entity?): Boolean { + if (e!!.isPlayer){ + val tindies = amountInInventory(e as Player, Items.TINDERBOX_1553) + if(removeItem(e, Item(Items.TINDERBOX_1553, tindies), Container.INVENTORY)){ + addItemOrDrop(e, Items.DAMP_TINDERBOX_4073, tindies) + } + //todo extinguish light sources. + } + + return super.enter(e) + } + + override fun leave(e: Entity?, logout: Boolean): Boolean { + + if (e!!.isPlayer){ + val tindies = amountInInventory(e as Player, Items.DAMP_TINDERBOX_4073) + if(removeItem(e, Item(Items.DAMP_TINDERBOX_4073, tindies), Container.INVENTORY)){ + addItemOrDrop(e, Items.TINDERBOX_1553, tindies) + } + } + + return super.leave(e, logout) + } + + override fun configure() { + // todo expand the borders to cover level 6, that way the tinderbox stays damp + register(ZoneBorders(2680, 4415, 2755, 4480)) + } +} \ No newline at end of file diff --git a/Server/src/main/content/region/morytania/quest/hauntedmine/AbandonedMineListeners.kt b/Server/src/main/content/region/morytania/quest/hauntedmine/AbandonedMineListeners.kt index 2c5244ea6..03a09a3e5 100644 --- a/Server/src/main/content/region/morytania/quest/hauntedmine/AbandonedMineListeners.kt +++ b/Server/src/main/content/region/morytania/quest/hauntedmine/AbandonedMineListeners.kt @@ -1,13 +1,11 @@ package content.region.morytania.quest.hauntedmine -import content.data.tables.BirdNest import core.api.* import core.game.global.action.DoorActionHandler import core.game.interaction.IntType import core.game.interaction.InteractionListener import core.game.node.entity.npc.NPC import core.game.node.entity.player.Player -import core.game.node.item.Item import core.game.world.map.Location import org.rs09.consts.Items import org.rs09.consts.NPCs @@ -150,16 +148,8 @@ class AbandonedMineListeners : InteractionListener { return@on true } - on(Scenery.LARGE_DOOR_4963, IntType.SCENERY, "Open") { player, node -> - if (player.inventory.contains(Items.CRYSTAL_MINE_KEY_4077, 1)) { - DoorActionHandler.handleAutowalkDoor(player, node.asScenery()) - } else { - sendMessage(player, "This door is locked.") - } - return@on true - } - - on(Scenery.LARGE_DOOR_4964, IntType.SCENERY, "Open") { player, node -> + // These are the doors from the shortcut to level 2, and also the ones on level 6 that go to the crystals. Both require the crystal mine key. + on(intArrayOf(Scenery.LARGE_DOOR_4963, Scenery.LARGE_DOOR_4964), IntType.SCENERY, "Open") { player, node -> if (player.inventory.contains(Items.CRYSTAL_MINE_KEY_4077, 1)) { DoorActionHandler.handleAutowalkDoor(player, node.asScenery()) } else { @@ -251,10 +241,11 @@ class AbandonedMineListeners : InteractionListener { loc.y in 4485..4487 ) { + // randomize the points settings so all players have to pull different levers. setVarp(player, HauntedMine.pointsSettingsVarp, (0..511).random()) - player.debug("points varp is:") - player.debug(getVarp(player,HauntedMine.pointsSettingsVarp).toString()) + //player.debug("points varp is:") + //player.debug(getVarp(player,HauntedMine.pointsSettingsVarp).toString()) animate(player, 828) teleport(player, Location.create(2790, 4486, 0)) @@ -274,7 +265,7 @@ class AbandonedMineListeners : InteractionListener { // mine level 4 to 3 on(Scenery.LADDER_4968, IntType.SCENERY, "Climb-up") { player, node -> - // ladder 4968 is reused in two locations, so we have to see which one the player is interacting with + // ladder 4968 is reused in four locations, so we have to see which one the player is interacting with val loc = player.location // north-east ladder @@ -324,6 +315,44 @@ class AbandonedMineListeners : InteractionListener { return@on true } + // stair from mine level 5 to 6 + on(Scenery.STAIRS_4971, IntType.SCENERY, "Walk-down") { player, node -> + // stair 4971 is reused in two locations, so we have to see which one the player is interacting with + val loc = player.location + if(inInventory(player, Items.GLOWING_FUNGUS_4075)) { + + // left stairs to crystals + if (loc.x in 2691..2696) { + teleport(player, Location.create(2758, 4453, 0)) + + // right stairs to dayth + } else if (loc.x in 2745..2750) { + teleport(player, Location.create(2811, 4453, 0)) + + } + } else sendPlayerDialogue(player, "It's kind of dark down here. I should probably find a light source before going further.") + + return@on true + } + + // stair from mine level 6 to 5 + on(Scenery.STAIRS_4973, IntType.SCENERY, "Walk-up") { player, node -> + // stair 4973 is reused in two locations, so we have to see which one the player is interacting with + val loc = player.location + + // left stairs + if (loc.x == 2758) { + teleport(player, Location.create(2691, 4437, 0)) + + // right stairs + } else if (loc.x == 2811) { + teleport(player, Location.create(2750, 4437, 0)) + + } + + return@on true + } + } diff --git a/Server/src/main/content/region/morytania/quest/hauntedmine/AbandonedMineZone.kt b/Server/src/main/content/region/morytania/quest/hauntedmine/AbandonedMineZone.kt index bda02d442..3cbfa4dd3 100644 --- a/Server/src/main/content/region/morytania/quest/hauntedmine/AbandonedMineZone.kt +++ b/Server/src/main/content/region/morytania/quest/hauntedmine/AbandonedMineZone.kt @@ -1,12 +1,6 @@ package content.region.morytania.quest.hauntedmine -import core.api.Container -import core.api.addItem -import core.api.addItemOrDrop -import core.api.amountInInventory -import core.api.inInventory -import core.api.removeItem -import core.api.sendMessage +import core.api.* import core.game.node.entity.Entity import core.game.node.entity.player.Player import core.game.node.item.Item @@ -33,9 +27,10 @@ class AbandonedMineZone : MapZone("Abandoned Mine", true), Plugin { override fun leave(e: Entity?, logout: Boolean): Boolean { - //todo come back to this and fix it the leave logic. + // Come back to this and fix the leave logic. // Right now if you go from floor 2 to 1 it gets rid of the fungus. - // I could also just leave as-is. It doesn't impact the quest and still accomplishes the correct goal. + // This is a very low priority to fix. It doesn't impact the quest and still accomplishes the correct goal. + if (e!!.isPlayer){ // remove any glowing fungus the player is carrying. val fungi = amountInInventory(e as Player, Items.GLOWING_FUNGUS_4075) @@ -54,47 +49,4 @@ class AbandonedMineZone : MapZone("Abandoned Mine", true), Plugin { // mine floors 2-6 register(ZoneBorders(2680, 4415, 2820, 4609)) } -} - -// If you enter level 5 of the abandoned mine, any tinderboxes with you should become damp tinderboxes. -// Light sources should also be extinguished. This is so that when you try to go to mine level 5 and the -// player says "i need a light source", it'll force you to get a glowing fungus. -class AbandonedMineL5Zone : MapZone("Abandoned Mine Level 5", true), Plugin { - - override fun newInstance(arg: Any?): Plugin { - ZoneBuilder.configure(this) - return this - } - - override fun fireEvent(identifier: String?, vararg args: Any?): Any { - return Unit - } - - override fun enter(e: Entity?): Boolean { - if (e!!.isPlayer){ - val tindies = amountInInventory(e as Player, Items.TINDERBOX_1553) - if(removeItem(e, Item(Items.TINDERBOX_1553, tindies), Container.INVENTORY)){ - addItemOrDrop(e, Items.DAMP_TINDERBOX_4073, tindies) - } - //todo extinguish light sources. - } - - return super.enter(e) - } - - override fun leave(e: Entity?, logout: Boolean): Boolean { - - if (e!!.isPlayer){ - val tindies = amountInInventory(e as Player, Items.DAMP_TINDERBOX_4073) - if(removeItem(e, Item(Items.DAMP_TINDERBOX_4073, tindies), Container.INVENTORY)){ - addItemOrDrop(e, Items.TINDERBOX_1553, tindies) - } - } - - return super.leave(e, logout) - } - - override fun configure() { - register(ZoneBorders(2680, 4415, 2755, 4480)) - } -} +} \ No newline at end of file diff --git a/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMine.kt b/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMine.kt index 636810629..4c1fcc346 100644 --- a/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMine.kt +++ b/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMine.kt @@ -37,7 +37,10 @@ class HauntedMine : Quest(Quests.HAUNTED_MINE,73 ,72 ,2 ,hauntedMineVarp, 0, 1, const val hauntedMineVarp = 382 const val pointsSettingsVarp = 383 const val pointsSettingsInterface = 144 + const val liftMachineryVarbit = 2060 + const val attributeGhostSpawned = "/save:quest:hauntedmine-ghostspawned" // True after the mischievous ghost spawns. + const val attributeValveUnlocked = "/save:quest:hauntedmine-valveunlocked" // True after you use Zealot's Key with the water valve const val attributeFungusPlaced = "/save:quest:hauntedmine-fungusplaced" // True after you put a fungus in the minecart const val attributeCartSent = "/save:quest:hauntedmine-cartsent" // True after you solve the cart puzzle const val attributeKilledTreusDayth = "/save:quest:hauntedmine-killedtreusdayth" // True after you've killed Treus Dayth. @@ -48,6 +51,7 @@ class HauntedMine : Quest(Quests.HAUNTED_MINE,73 ,72 ,2 ,hauntedMineVarp, 0, 1, // Quest Journal ref: https://youtu.be/CD77NeKz1J4?si=AxNEg5YZU5oJ3T11&t=231 // Contains pre-starting journal entry: https://www.youtube.com/watch?v=PMn0LRo4MCo // The video fragment matches the current RS3 journal: https://runescape.wiki/w/Transcript:Haunted_Mine/Journal + // todo go back and add the quest stage progressions. override fun drawJournal(player: Player, stage: Int) { super.drawJournal(player, stage) var line = 12 @@ -106,7 +110,10 @@ class HauntedMine : Quest(Quests.HAUNTED_MINE,73 ,72 ,2 ,hauntedMineVarp, 0, 1, } override fun reset(player: Player) { + //todo come back at the end and make sure all the attributes you thought up get reset. + // for some that might persist after the quest, should they get reset when you leave the mine? removeAttribute(player, attributeKilledTreusDayth) + //removeAttribute(player, attributeValveUnlocked) // DON'T CLEAR THIS ONE, THAT WAY YOU CAN STILL GET BACK TO CRYSTALS setVarbit(player, 382, 0, true) // resets the quest and closes tarn's door. } diff --git a/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMineListeners.kt b/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMineListeners.kt index aad98c546..1ded202d0 100644 --- a/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMineListeners.kt +++ b/Server/src/main/content/region/morytania/quest/hauntedmine/HauntedMineListeners.kt @@ -1,11 +1,13 @@ package content.region.morytania.quest.hauntedmine +import content.data.Quests import core.api.* import core.game.interaction.IntType import core.game.interaction.InteractionListener import core.game.node.item.Item import core.game.system.task.Pulse import core.game.world.GameWorld +import core.game.world.map.Location import core.game.world.update.flag.context.Animation import org.rs09.consts.Items import org.rs09.consts.NPCs @@ -52,12 +54,80 @@ class HauntedMineListeners : InteractionListener { } // mine cart you are supposed to put the fungus into (south) and take the fungus out of (north). - // note that it appears this mine cart exists in both the start and end spots simultaneously. - on(Scenery.MINE_CART_4974, IntType.SCENERY, "Search") { player, node -> + on(Scenery.MINE_CART_4974, IntType.SCENERY, "Search") { player, _ -> + + // the mine cart is the same scenery in both locations, so we have to see which one the player is interacting with + val loc = player.location + + // Check around a 1-tile radius of the north cart + if (loc.z == 0 && + loc.x in 2773..2775 && + loc.y in 4536..4538) { + + // take fungus out if it's in there and you did the cart thing correctly. + if(getAttribute(player, HauntedMine.attributeFungusPlaced,false) && getAttribute(player, HauntedMine.attributeCartSent, false)) { + sendDialogueOptions(player, "There's a glowing fungus I placed in here earlier.", "Take it.", "Leave it.") + addDialogueAction(player) { _, buttonId -> + when (buttonId) { + 2 -> { + if (freeSlots(player) >= 1) { + addItem(player, Items.GLOWING_FUNGUS_4075) + setAttribute(player, HauntedMine.attributeFungusPlaced, false) + setAttribute(player, HauntedMine.attributeCartSent, false) + + } else sendMessage(player,"You need at least one free inventory space to take this.") + } + } + } + } else { + sendMessage(player, "The cart is empty.") + } + + // Check around a 1-tile radius of the south cart + } else if (loc.z == 0 && + loc.x in 2777..2779 && + loc.y in 4505..4507) { + + if(getAttribute(player, HauntedMine.attributeFungusPlaced,false)) { + sendMessage(player, "There's already a load of fungus in this cart.") + } else { + sendMessage(player, "The cart is empty.") + } + } return@on true } + onUseWith(SCENERY, Items.GLOWING_FUNGUS_4075, Scenery.MINE_CART_4974) { player, used, _ -> + + // the mine cart is the same scenery in both locations, so we have to see which one the player is interacting with + val loc = player.location + + // Check around a 1-tile radius of the north cart + if (loc.z == 0 && + loc.x in 2773..2775 && + loc.y in 4536..4538) { + + // don't let the player put the fungus back in the north cart. + sendMessage(player, "I just went to all the effort of getting this over here. I'm not sending it back.") + + // Check around a 1-tile radius of the south cart + } else if (loc.z == 0 && + loc.x in 2777..2779 && + loc.y in 4505..4507) { + + if(getAttribute(player, HauntedMine.attributeFungusPlaced,false)) { + sendMessage(player, "There's already a load of fungus in this cart.") + } else { + removeItem(player, used) + setAttribute(player, HauntedMine.attributeFungusPlaced, true) + sendMessage(player, "You place the glowing fungus in the mine cart.") + } + } + + return@onUseWith true + } + // points settings on(Scenery.POINTS_SETTINGS_4949, IntType.SCENERY, "Check") { player, _ -> openOverlay(player, HauntedMine.pointsSettingsInterface) @@ -77,6 +147,9 @@ class HauntedMineListeners : InteractionListener { // Lever A on(Scenery.LEVER_4951, IntType.SCENERY, "Pull") { player, node -> replaceScenery(node as core.game.node.scenery.Scenery, Scenery.LEVER_4958, 2) + // See PointsSettingsInterface.kt for an explanation on the points settings varp. + // Each lever corresponds to one bit in the varp. This interact XORs a 1 with the varp, with the bit shifted to the position that corresponds to each lever. + // This means that if you pull the lever once, the 0 becomes 1. If you pull it again, the 1 becomes a 0. val varp = getVarp(player, HauntedMine.pointsSettingsVarp) xor 1.shl(2) setVarp(player, HauntedMine.pointsSettingsVarp, varp) sendMessage(player, "You pull the lever. The old points creak into place.") @@ -153,5 +226,74 @@ class HauntedMineListeners : InteractionListener { return@on true } + + // water valve for lift + on(Scenery.WATER_VALVE_4924, IntType.SCENERY, "Turn") {player, _ -> + if(getAttribute(player, HauntedMine.attributeValveUnlocked, false)) { + if(getVarbit(player, HauntedMine.liftMachineryVarbit) == 1) { + sendMessage(player, "The valve is already open.") + } else { + sendMessage(player, "You open the valve. Water begins to flow through the lift mechanism.") + setVarbit(player, HauntedMine.liftMachineryVarbit, 1) + setAttribute(player, HauntedMine.attributeGhostSpawned,false) //resetting this here because it got stuck during test. + } + } else sendMessage(player, "The valve seems to be locked in position. There is a small keyhole in the side.") + return@on true + } + + // unlocking the water valve + onUseWith(SCENERY, Items.ZEALOTS_KEY_4078, Scenery.WATER_VALVE_4924) { player, _, _ -> + sendMessage(player, "The key unlocks the valve.") + setAttribute(player, HauntedMine.attributeValveUnlocked, true) + return@onUseWith true + } + + // lift from level 4 to 5 + on(intArrayOf(Scenery.LIFT_4937, Scenery.LIFT_4938, Scenery.LIFT_4940), IntType.SCENERY, "Go-down") { player, _ -> + // if lift is active, descend. + if (getVarbit(player, HauntedMine.liftMachineryVarbit) == 1) { + sendMessage(player, "You get in the lift. Now powered, the lift descends further into the mines...") + //teleport(player, Location.create(2724, 4456, 0)) + // todo figure out how to swim + teleport(player, Location.create(2724, 4452, 0)) + sendMessage(player, "...plunging you straight into the middle of a chamber flooded with water.") + } else sendMessage(player, "The lift is not active.") + + return@on true + } + + // lift from level 5 to 4 + on(Scenery.LIFT_4942, IntType.SCENERY, "Go-up") { player, _ -> + // todo this is inaccessible until i learn how to swim + teleport(player, Location.create(2807, 4493, 0)) + + return@on true + } + + // todo Make the picks respawn. + on(NPCs.INNOCENT_LOOKING_KEY_1543, IntType.NPC, "Take") { player, _ -> + if(getAttribute(player, HauntedMine.attributeKilledTreusDayth, false)) { + addItemOrDrop(player, Items.CRYSTAL_MINE_KEY_4077, 1) + } else { + // todo add dayth cutscene + // start treus dayth fight + } + + return@on true + } + + // crystals! + on(intArrayOf(Scenery.CRYSTAL_OUTCROP_4926, Scenery.CRYSTAL_OUTCROP_4927, Scenery.CRYSTAL_OUTCROP_4928), IntType.SCENERY, "Cut") { player, _ -> + if (freeSlots(player) >= 1 && (getAttribute(player,HauntedMine.attributeKilledTreusDayth, false) || getQuestStage(player, Quests.HAUNTED_MINE) == 100)) { + addItem(player, Items.SALVE_SHARD_4082) + // complete the quest + if(getQuestStage(player,Quests.HAUNTED_MINE) != 100) { + finishQuest(player, Quests.HAUNTED_MINE) + } + + } else sendMessage(player,"You need at least one free inventory space to take this.") + + return@on true + } } } \ No newline at end of file diff --git a/Server/src/main/content/region/morytania/quest/hauntedmine/LiftGhostNPC.kt b/Server/src/main/content/region/morytania/quest/hauntedmine/LiftGhostNPC.kt new file mode 100644 index 000000000..725ccaf93 --- /dev/null +++ b/Server/src/main/content/region/morytania/quest/hauntedmine/LiftGhostNPC.kt @@ -0,0 +1,59 @@ +package content.region.morytania.quest.hauntedmine + +import core.api.* +import core.game.node.entity.npc.AbstractNPC +import core.game.node.entity.npc.NPC +import core.game.node.entity.npc.NPCBehavior +import core.game.world.map.Location +import org.rs09.consts.NPCs + +class LiftGhostNPC(id: Int = 0, location: Location? = null) : AbstractNPC(id, location) { + + override fun construct(id: Int, location: Location, vararg objects: Any): AbstractNPC { + return LiftGhostNPC(id, location) + } + + override fun getIds(): IntArray { + return intArrayOf(NPCs.MISCHIEVOUS_GHOST_1551) + } +} + +class LiftGhostNPCBehavior : NPCBehavior(NPCs.MISCHIEVOUS_GHOST_1551) { + + override fun onCreation(self: NPC) { + sendChat(self, "Ooooo Wooooo Woo") + // the ghost is supposed to path through walls directly towards the valve, but this works too i guess. + val movementPath = arrayOf( + Location.create(2802, 4516, 0), + Location.create(2806, 4516, 0), + Location.create(2806, 4510, 0), + Location.create(2807, 4510, 0), + Location.create(2807, 4509, 0), + Location.create(2808, 4509, 0), + Location.create(2808, 4502, 0), + Location.create(2806, 4502, 0), + Location.create(2806, 4497, 0), + Location.create(2807, 4497, 0), + Location.create(2807, 4496, 0) + ) + self.configureMovementPath(*movementPath) + self.isWalks = true + } + + // logic to check if ghost is at end of path. If it is, turn off valve that powers the lift. + override fun tick(self: NPC): Boolean { + + for (p in self.viewport.currentPlane.players) { + if (self.location == location(2807,4496,0) && getVarbit(p, HauntedMine.liftMachineryVarbit) == 1) { + sendMessage(p, "You hear the sound of a valve being turned.") + setVarbit(p, HauntedMine.liftMachineryVarbit, 0) + setAttribute(p, HauntedMine.attributeGhostSpawned, false) + self.clear() + } + } + + + + return true + } +} \ No newline at end of file diff --git a/Server/src/main/content/region/morytania/quest/hauntedmine/MinecartNPC.kt b/Server/src/main/content/region/morytania/quest/hauntedmine/MinecartNPC.kt index 0c8b25177..09019e1d7 100644 --- a/Server/src/main/content/region/morytania/quest/hauntedmine/MinecartNPC.kt +++ b/Server/src/main/content/region/morytania/quest/hauntedmine/MinecartNPC.kt @@ -60,7 +60,7 @@ class MinecartNPCBehavior : NPCBehavior(NPCs.MINE_CART_1544, NPCs.MINE_CART_1545 // logic to check for, push, and damage players. override fun tick(self: NPC): Boolean { for (p in self.viewport.currentPlane.players) { - // todo come back and refine the pushing, it doesn't work very well. + // todo come back and refine the pushing, it doesn't work very well. can i just override the player's pathing with the minecarts pathing? if (p.location == self.location /*|| p.location == self.location.transform(self.direction,1)*/) { forceMove(p, p.location,self.location.transform(self.direction,1),0,0) impact(p,random(0,2)) diff --git a/Server/src/main/content/region/morytania/quest/hauntedmine/PointsSettingsInterface.kt b/Server/src/main/content/region/morytania/quest/hauntedmine/PointsSettingsInterface.kt index d3b39a84a..622b3b3ff 100644 --- a/Server/src/main/content/region/morytania/quest/hauntedmine/PointsSettingsInterface.kt +++ b/Server/src/main/content/region/morytania/quest/hauntedmine/PointsSettingsInterface.kt @@ -1,6 +1,7 @@ package content.region.morytania.quest.hauntedmine import core.api.* +import core.game.dialogue.FacialExpression import core.game.interaction.InterfaceListener import core.game.node.entity.player.Player @@ -33,6 +34,7 @@ import core.game.node.entity.player.Player class PointsSettingsInterface : InterfaceListener { + //todo make this interface close if the player moves override fun defineInterfaceListeners() { on(HauntedMine.pointsSettingsInterface) { player, _, _, buttonID, _, _ -> when (buttonID) { @@ -49,8 +51,8 @@ class PointsSettingsInterface : InterfaceListener { private fun checkCartRoute(player: Player) { - player.debug("points varp is:") - player.debug(getVarp(player,HauntedMine.pointsSettingsVarp).toString()) + //player.debug("points varp is:") + //player.debug(getVarp(player,HauntedMine.pointsSettingsVarp).toString()) // 5 of my 7 sources agree this is the correct solution. I have taken that to be the exact one, and the player must match it. if(getVarp(player,HauntedMine.pointsSettingsVarp) == 102 || getVarp(player,HauntedMine.pointsSettingsVarp) == 103) { // 103 could also be an answer because the random function that sets the initial varp stage might make the first bit a 1. afaik that bit does nothing. @@ -59,7 +61,7 @@ class PointsSettingsInterface : InterfaceListener { val varp = getVarp(player, HauntedMine.pointsSettingsVarp) xor 7.shl(12) setVarp(player, HauntedMine.pointsSettingsVarp, varp) setAttribute(player, HauntedMine.attributeCartSent, true) - sendDialogue(player, "I wonder if that cart is anywhere useful now?") + sendPlayerDialogue(player, "I wonder if that cart is anywhere useful now?", FacialExpression.THINKING) } else { // if wrong, clear the fungus out of the cart. setAttribute(player, HauntedMine.attributeFungusPlaced, false) diff --git a/Server/src/main/content/region/morytania/quest/hauntedmine/TreusDaythNPC.kt b/Server/src/main/content/region/morytania/quest/hauntedmine/TreusDaythNPC.kt new file mode 100644 index 000000000..c378f276c --- /dev/null +++ b/Server/src/main/content/region/morytania/quest/hauntedmine/TreusDaythNPC.kt @@ -0,0 +1,2 @@ +package content.region.morytania.quest.hauntedmine +