Compare commits

...

3 commits

Author SHA1 Message Date
oftheshire
28e0c5b3ff Merge branch 'haunted-mine' into 'master'
Draft: Haunted Mine Quest

Closes #2454

See merge request 2009scape/2009scape!2211
2025-12-07 21:11:29 +00:00
aidan
62eb248109 I've got most of the stuff up till the dayth fight now. 2025-12-07 15:11:09 -06:00
aidan
9f75ba700d points settings! 2025-12-05 16:47:27 -06:00
14 changed files with 582 additions and 98 deletions

View file

@ -265,7 +265,7 @@
}, },
{ {
"item_id": "995", "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", "item_id": "1005",
@ -325,15 +325,19 @@
}, },
{ {
"item_id": "1237", "item_id": "1237",
"loc_data": "{60,2808,4572,0,1}-" "loc_data": "{1,2808,4572,0,60}-"
}, },
{ {
"item_id": "1265", "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", "item_id": "1269",
"loc_data": "{60,2812,4571,0,1}-" "loc_data": "{1,2812,4571,0,60}-"
}, },
{ {
"item_id": "1321", "item_id": "1321",
@ -421,7 +425,7 @@
}, },
{ {
"item_id": "1755", "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", "item_id": "1785",

View file

@ -203,6 +203,12 @@
"walkable": "false", "walkable": "false",
"tabIndex": "-1" "tabIndex": "-1"
}, },
{
"id": "144",
"interfaceType": "1",
"walkable": "false",
"tabIndex": "-1"
},
{ {
"id": "149", "id": "149",
"interfaceType": "2", "interfaceType": "2",

View file

@ -157,7 +157,7 @@
}, },
{ {
"npc_id": "47", "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", "npc_id": "48",
@ -245,7 +245,7 @@
}, },
{ {
"npc_id": "78", "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", "npc_id": "80",
@ -1221,7 +1221,7 @@
}, },
{ {
"npc_id": "412", "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", "npc_id": "419",
@ -2781,7 +2781,7 @@
}, },
{ {
"npc_id": "1015", "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", "npc_id": "1017",
@ -3869,7 +3869,7 @@
}, },
{ {
"npc_id": "1538", "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", "npc_id": "1542",

View file

@ -105,11 +105,13 @@ public final class FieldPickingPlugin extends OptionHandler {
if (!isBloomPlant) { if (!isBloomPlant) {
SceneryBuilder.replace(plant == PickingPlant.BANANA_TREE_4 ? full : object, object.transform(banana ? plant.respawn : 0), banana ? 300 : plant.respawn); SceneryBuilder.replace(plant == PickingPlant.BANANA_TREE_4 ? full : object, object.transform(banana ? plant.respawn : 0), banana ? 300 : plant.respawn);
} }
if (!plant.name().startsWith("NETTLES")) { if (plant.name().startsWith("NETTLES")) {
player.getPacketDispatch().sendMessage("You pick a " + reward.getName().toLowerCase() + "."); player.getPacketDispatch().sendMessage("You pick a handful of nettles.");
} else { } else if (plant.name().startsWith("GLOWING")) {
player.getPacketDispatch().sendMessage("You pick a handful of nettles."); 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; return true;
} }
}); });

View file

@ -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<Any?> {
override fun newInstance(arg: Any?): Plugin<Any?> {
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))
}
}

View file

@ -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<Any?> {
override fun newInstance(arg: Any?): Plugin<Any?> {
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))
}
}

View file

@ -1,13 +1,11 @@
package content.region.morytania.quest.hauntedmine package content.region.morytania.quest.hauntedmine
import content.data.tables.BirdNest
import core.api.* import core.api.*
import core.game.global.action.DoorActionHandler import core.game.global.action.DoorActionHandler
import core.game.interaction.IntType import core.game.interaction.IntType
import core.game.interaction.InteractionListener import core.game.interaction.InteractionListener
import core.game.node.entity.npc.NPC import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player import core.game.node.entity.player.Player
import core.game.node.item.Item
import core.game.world.map.Location import core.game.world.map.Location
import org.rs09.consts.Items import org.rs09.consts.Items
import org.rs09.consts.NPCs import org.rs09.consts.NPCs
@ -150,16 +148,8 @@ class AbandonedMineListeners : InteractionListener {
return@on true return@on true
} }
on(Scenery.LARGE_DOOR_4963, 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.
if (player.inventory.contains(Items.CRYSTAL_MINE_KEY_4077, 1)) { on(intArrayOf(Scenery.LARGE_DOOR_4963, Scenery.LARGE_DOOR_4964), IntType.SCENERY, "Open") { player, node ->
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)) { if (player.inventory.contains(Items.CRYSTAL_MINE_KEY_4077, 1)) {
DoorActionHandler.handleAutowalkDoor(player, node.asScenery()) DoorActionHandler.handleAutowalkDoor(player, node.asScenery())
} else { } else {
@ -251,6 +241,12 @@ class AbandonedMineListeners : InteractionListener {
loc.y in 4485..4487 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())
animate(player, 828) animate(player, 828)
teleport(player, Location.create(2790, 4486, 0)) teleport(player, Location.create(2790, 4486, 0))
@ -269,7 +265,7 @@ class AbandonedMineListeners : InteractionListener {
// mine level 4 to 3 // mine level 4 to 3
on(Scenery.LADDER_4968, IntType.SCENERY, "Climb-up") { player, node -> 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 val loc = player.location
// north-east ladder // north-east ladder
@ -319,6 +315,44 @@ class AbandonedMineListeners : InteractionListener {
return@on true 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
}
} }

View file

@ -1,12 +1,6 @@
package content.region.morytania.quest.hauntedmine package content.region.morytania.quest.hauntedmine
import core.api.Container import core.api.*
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.Entity
import core.game.node.entity.player.Player import core.game.node.entity.player.Player
import core.game.node.item.Item import core.game.node.item.Item
@ -33,9 +27,10 @@ class AbandonedMineZone : MapZone("Abandoned Mine", true), Plugin<Any?> {
override fun leave(e: Entity?, logout: Boolean): Boolean { 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. // 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){ if (e!!.isPlayer){
// remove any glowing fungus the player is carrying. // remove any glowing fungus the player is carrying.
val fungi = amountInInventory(e as Player, Items.GLOWING_FUNGUS_4075) val fungi = amountInInventory(e as Player, Items.GLOWING_FUNGUS_4075)
@ -55,46 +50,3 @@ class AbandonedMineZone : MapZone("Abandoned Mine", true), Plugin<Any?> {
register(ZoneBorders(2680, 4415, 2820, 4609)) 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<Any?> {
override fun newInstance(arg: Any?): Plugin<Any?> {
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))
}
}

View file

@ -29,19 +29,29 @@ import org.rs09.consts.Items
// ::setqueststage 73 0 to reset quest // ::setqueststage 73 0 to reset quest
@Initializable @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 { companion object {
const val questName = "Haunted Mine" const val questName = "Haunted Mine"
const val attributeKilledTreusDayth = "/save:quest:hauntedmine-killedtreusdayth" // True after you've killed Treus Dayth. const val hauntedMineVarp = 382
const val attributeKeyMentioned = "/save:quest:hauntedmine-keymentioned" // True after the player asks about a way into the mines. const val pointsSettingsVarp = 383
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 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.
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 // Quest Journal ref: https://youtu.be/CD77NeKz1J4?si=AxNEg5YZU5oJ3T11&t=231
// Contains pre-starting journal entry: https://www.youtube.com/watch?v=PMn0LRo4MCo // 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 // 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) { override fun drawJournal(player: Player, stage: Int) {
super.drawJournal(player, stage) super.drawJournal(player, stage)
var line = 12 var line = 12
@ -100,7 +110,10 @@ class HauntedMine : Quest(Quests.HAUNTED_MINE,73 ,72 ,2 ,382, 0, 1, 11) {
} }
override fun reset(player: Player) { 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, 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. setVarbit(player, 382, 0, true) // resets the quest and closes tarn's door.
} }

View file

@ -1,13 +1,13 @@
package content.region.morytania.quest.hauntedmine package content.region.morytania.quest.hauntedmine
import content.region.morytania.quest.hauntedmine.HauntedMine.Companion.attributeKeyMentioned import content.data.Quests
import core.api.* import core.api.*
import core.game.global.action.DoorActionHandler
import core.game.interaction.IntType import core.game.interaction.IntType
import core.game.interaction.InteractionListener import core.game.interaction.InteractionListener
import core.game.node.item.Item import core.game.node.item.Item
import core.game.system.task.Pulse import core.game.system.task.Pulse
import core.game.world.GameWorld import core.game.world.GameWorld
import core.game.world.map.Location
import core.game.world.update.flag.context.Animation import core.game.world.update.flag.context.Animation
import org.rs09.consts.Items import org.rs09.consts.Items
import org.rs09.consts.NPCs import org.rs09.consts.NPCs
@ -17,17 +17,17 @@ class HauntedMineListeners : InteractionListener {
override fun defineListeners() { override fun defineListeners() {
onUseWith(ITEM, Items.SALVE_SHARD_4082, Items.BALL_OF_WOOL_1759) { player, used, _ -> onUseWith(ITEM, Items.SALVE_SHARD_4082, Items.BALL_OF_WOOL_1759) { player, used, with ->
removeItem(player, Items.SALVE_SHARD_4082) removeItem(player, used)
removeItem(player, Items.BALL_OF_WOOL_1759) removeItem(player, with)
addItem(player, Items.SALVE_AMULET_4081) addItem(player, Items.SALVE_AMULET_4081)
sendMessage(player, "You string the salve amulet.") sendMessage(player, "You string the salve amulet.")
return@onUseWith true 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. // 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 -> on(NPCs.ZEALOT_1528, IntType.NPC, "pickpocket"){ player, _ ->
if(getAttribute(player, attributeKeyMentioned, false) && !player.inventory.containsItem(Item(Items.ZEALOTS_KEY_4078))){ if(getAttribute(player, HauntedMine.attributeKeyMentioned, false) && !player.inventory.containsItem(Item(Items.ZEALOTS_KEY_4078))){
player.lock() player.lock()
GameWorld.Pulser.submit(object : Pulse(){ GameWorld.Pulser.submit(object : Pulse(){
var counter = 0 var counter = 0
@ -45,7 +45,7 @@ class HauntedMineListeners : InteractionListener {
}) })
addItemOrDrop(player, Items.ZEALOTS_KEY_4078) addItemOrDrop(player, Items.ZEALOTS_KEY_4078)
sendMessage(player, "You pick the zealot's pocket and retrieve a small silvery key.") 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.") sendMessage(player, "I've already picked his pockets.")
} else { } else {
sendMessage(player, "I doubt he's got much of value on him.") sendMessage(player, "I doubt he's got much of value on him.")
@ -54,15 +54,83 @@ class HauntedMineListeners : InteractionListener {
} }
// mine cart you are supposed to put the fungus into (south) and take the fungus out of (north). // 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, _ ->
on(Scenery.MINE_CART_4974, IntType.SCENERY, "Search") { player, node ->
// 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 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 // points settings
on(Scenery.POINTS_SETTINGS_4949, IntType.SCENERY, "Check") { player, node -> on(Scenery.POINTS_SETTINGS_4949, IntType.SCENERY, "Check") { player, _ ->
// open iface 144 openOverlay(player, HauntedMine.pointsSettingsInterface)
return@on true return@on true
} }
@ -75,5 +143,157 @@ class HauntedMineListeners : InteractionListener {
return@on true 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)
// 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.")
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
}
// 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
}
} }
} }

View file

@ -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
}
}

View file

@ -60,7 +60,7 @@ class MinecartNPCBehavior : NPCBehavior(NPCs.MINE_CART_1544, NPCs.MINE_CART_1545
// logic to check for, push, and damage players. // logic to check for, push, and damage players.
override fun tick(self: NPC): Boolean { override fun tick(self: NPC): Boolean {
for (p in self.viewport.currentPlane.players) { 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)*/) { 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) forceMove(p, p.location,self.location.transform(self.direction,1),0,0)
impact(p,random(0,2)) impact(p,random(0,2))

View file

@ -0,0 +1,94 @@
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
/*
* 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 {
//todo make this interface close if the player moves
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)
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)
}
}
}
/*
* 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
*/

View file

@ -0,0 +1,2 @@
package content.region.morytania.quest.hauntedmine