mirror of
https://gitlab.com/2009scape/2009scape.git
synced 2026-08-24 20:05:13 -06:00
Merge branch 2009scape:master into master
This commit is contained in:
commit
aa489af87a
78 changed files with 2920 additions and 794 deletions
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
<ObjectAction mode="remove" id="356" x="2804" y="3428" z="0"/>
|
||||
<ObjectAction mode="add" id="356" x="2804" y="3428" z="0"/>
|
||||
<ObjectAction mode="add" id="2783" x="3229" y="3254" z="0"/>
|
||||
|
||||
<ObjectAction mode="remove" id="20228" x="2537" y="3573" z="0"/>
|
||||
<ObjectAction mode="add" id="27663" x="2537" y="3573" z="0" direction="w"/>
|
||||
|
|
|
|||
|
|
@ -343,7 +343,7 @@
|
|||
},
|
||||
{
|
||||
"id": "2054",
|
||||
"replaceId": "24375",
|
||||
"replaceId": "2055",
|
||||
"fence": "false",
|
||||
"metal": "false"
|
||||
},
|
||||
|
|
@ -419,18 +419,6 @@
|
|||
"fence": "false",
|
||||
"metal": "false"
|
||||
},
|
||||
{
|
||||
"id": "2391",
|
||||
"replaceId": "1561",
|
||||
"fence": "false",
|
||||
"metal": "true"
|
||||
},
|
||||
{
|
||||
"id": "2392",
|
||||
"replaceId": "1561",
|
||||
"fence": "false",
|
||||
"metal": "true"
|
||||
},
|
||||
{
|
||||
"id": "2397",
|
||||
"replaceId": "24383",
|
||||
|
|
@ -2169,7 +2157,7 @@
|
|||
},
|
||||
{
|
||||
"id": "24376",
|
||||
"replaceId": "24377",
|
||||
"replaceId": "24375",
|
||||
"fence": "false",
|
||||
"metal": "false"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@
|
|||
},
|
||||
{
|
||||
"item_id": "401",
|
||||
"loc_data": "{1,2959,2959,0,160}-{1,2943,2950,0,160}-{1,2866,2976,0,160}-{1,2854,2977,0,160}-{1,2839,2975,0,160}-{1,2757,2947,0,160}-{1,2755,2952,0,160}-{1,2786,2960,0,160}-{1,2782,2987,0,160}-{1,2771,2995,0,160}-{1,2761,3000,0,160}-{1,3829,3053,0,160}-{1,3813,3066,0,160}-{1,3814,3064,0,160}-{1,3808,3060,0,160}-{1,2945,3068,0,160}-{1,2975,3013,0,160}-{1,2955,3010,0,160}-{1,2755,3008,0,160}-{1,2754,3017,0,160}-{1,2756,3060,0,160}-{1,2755,3070,0,160}-{1,2896,3119,0,160}-{1,2914,3111,0,160}-{1,2926,3110,0,160}-{1,2939,3102,0,160}-{1,2938,3073,0,160}-{1,2756,3074,0,160}-{1,2806,3128,0,160}-{1,2764,3131,0,160}-{1,2753,3125,0,160}-{1,2757,3109,0,160}-{1,2864,3195,0,160}-{1,2810,3387,0,160}-{1,2809,3388,0,160}-{1,2809,3385,0,160}-{1,2807,3386,0,160}-{1,2804,3385,0,160}-{1,2807,3384,0,160}-{1,2805,3384,0,160}-{1,2802,3382,0,160}-{1,2805,3381,0,160}-{1,2804,3380,0,160}-{1,2693,3727,0,160}-{1,2698,3729,0,160}-{1,2700,3731,0,160}-{1,2708,3728,0,160}-{1,2725,3731,0,160}-{1,2721,3730,0,160}-{1,2719,3733,0,160}-{1,2714,3733,0,160}-{1,2712,3732,0,160}-"
|
||||
"loc_data": "{1,2959,2959,0,160}-{1,2866,2976,0,160}-{1,2854,2977,0,160}-{1,2839,2975,0,160}-{1,2943,2950,0,160}-{1,2757,2947,0,160}-{1,2755,2952,0,160}-{1,2786,2960,0,160}-{1,2782,2987,0,160}-{1,2771,2995,0,160}-{1,2761,3000,0,160}-{1,2945,3068,0,160}-{1,2975,3013,0,160}-{1,2955,3010,0,160}-{1,3829,3053,0,160}-{1,3813,3066,0,160}-{1,3814,3064,0,160}-{1,3808,3060,0,160}-{1,2755,3008,0,160}-{1,2754,3017,0,160}-{1,2756,3060,0,160}-{1,2755,3070,0,160}-{1,2896,3119,0,160}-{1,2914,3111,0,160}-{1,2926,3110,0,160}-{1,2939,3102,0,160}-{1,2938,3073,0,160}-{1,2756,3074,0,160}-{1,2806,3128,0,160}-{1,2764,3131,0,160}-{1,2753,3125,0,160}-{1,2757,3109,0,160}-{1,2864,3195,0,160}-{1,2810,3387,0,160}-{1,2809,3388,0,160}-{1,2809,3385,0,160}-{1,2807,3386,0,160}-{1,2804,3385,0,160}-{1,2807,3384,0,160}-{1,2805,3384,0,160}-{1,2802,3382,0,160}-{1,2805,3381,0,160}-{1,2804,3380,0,160}-{1,2693,3727,0,160}-{1,2698,3729,0,160}-{1,2700,3731,0,160}-{1,2708,3728,0,160}-{1,2725,3731,0,160}-{1,2721,3730,0,160}-{1,2719,3733,0,160}-{1,2714,3733,0,160}-{1,2712,3732,0,160}-"
|
||||
},
|
||||
{
|
||||
"item_id": "444",
|
||||
|
|
@ -369,7 +369,7 @@
|
|||
},
|
||||
{
|
||||
"item_id": "1573",
|
||||
"loc_data": "{1,2559,2975,0,10}-{1,2560,2974,0,10}-{1,2561,2973,0,10}-{1,2561,2976,0,10}-{1,2740,3637,0,30}-{1,2736,3638,0,30}-{1,2735,3636,0,30}-{1,2743,3636,0,30}-{1,2739,3634,0,30}-{1,2743,3640,0,30}-{1,2741,3639,0,30}-{1,2736,3641,0,30}-{1,2738,3641,0,30}-{1,2734,3640,0,30}-{1,2738,3636,0,30}-"
|
||||
"loc_data": "{1,2560,2974,0,10}-{1,2561,2973,0,10}-{1,2561,2976,0,10}-{1,2559,2975,0,10}-{1,2740,3637,0,30}-{1,2736,3638,0,30}-{1,2735,3636,0,30}-{1,2743,3636,0,30}-{1,2739,3634,0,30}-{1,2743,3640,0,30}-{1,2741,3639,0,30}-{1,2736,3641,0,30}-{1,2738,3641,0,30}-{1,2734,3640,0,30}-{1,2738,3636,0,30}-"
|
||||
},
|
||||
{
|
||||
"item_id": "1590",
|
||||
|
|
@ -469,7 +469,7 @@
|
|||
},
|
||||
{
|
||||
"item_id": "1931",
|
||||
"loc_data": "{1,3209,3214,0,80}-{1,3166,3310,0,90}-{1,3144,3449,2,90}-"
|
||||
"loc_data": "{1,3209,3214,0,80}-{1,3166,3310,0,90}-{1,3144,3449,2,90}-{1,2918,10191,1,90}-"
|
||||
},
|
||||
{
|
||||
"item_id": "1935",
|
||||
|
|
|
|||
|
|
@ -17702,7 +17702,7 @@
|
|||
{
|
||||
"shop_price": "350",
|
||||
"ge_buy_limit": "5000",
|
||||
"examine": "A plain gold amulet.",
|
||||
"examine": "It needs a string so I can wear it.",
|
||||
"grand_exchange_price": "172",
|
||||
"durability": null,
|
||||
"name": "Gold amulet",
|
||||
|
|
@ -17722,7 +17722,7 @@
|
|||
{
|
||||
"shop_price": "810",
|
||||
"ge_buy_limit": "5000",
|
||||
"examine": "I wonder if I can get this enchanted.",
|
||||
"examine": "It needs a string so I can wear it.",
|
||||
"grand_exchange_price": "473",
|
||||
"durability": null,
|
||||
"name": "Sapphire amulet",
|
||||
|
|
@ -17742,7 +17742,7 @@
|
|||
{
|
||||
"shop_price": "1147",
|
||||
"ge_buy_limit": "5000",
|
||||
"examine": "I wonder if I can get this enchanted.",
|
||||
"examine": "It needs a string so I can wear it.",
|
||||
"grand_exchange_price": "695",
|
||||
"durability": null,
|
||||
"name": "Emerald amulet",
|
||||
|
|
@ -17762,7 +17762,7 @@
|
|||
{
|
||||
"shop_price": "2025",
|
||||
"ge_buy_limit": "5000",
|
||||
"examine": "I wonder if I can get this enchanted.",
|
||||
"examine": "It needs a string so I can wear it.",
|
||||
"grand_exchange_price": "1268",
|
||||
"durability": null,
|
||||
"name": "Ruby amulet",
|
||||
|
|
@ -17783,7 +17783,7 @@
|
|||
{
|
||||
"shop_price": "3307",
|
||||
"ge_buy_limit": "5000",
|
||||
"examine": "I wonder if I can get this enchanted.",
|
||||
"examine": "It needs a string so I can wear it.",
|
||||
"grand_exchange_price": "3359",
|
||||
"durability": null,
|
||||
"name": "Diamond amulet",
|
||||
|
|
@ -17802,7 +17802,7 @@
|
|||
},
|
||||
{
|
||||
"ge_buy_limit": "100",
|
||||
"examine": "I wonder if I can get this enchanted.",
|
||||
"examine": "It needs a string so I can wear it.",
|
||||
"grand_exchange_price": "26900",
|
||||
"durability": null,
|
||||
"name": "Dragonstone ammy",
|
||||
|
|
@ -48457,14 +48457,14 @@
|
|||
},
|
||||
{
|
||||
"shop_price": "200",
|
||||
"examine": "An acorn has been sown and watered in this plant pot.",
|
||||
"examine": "An acorn has been sown in this plant pot.",
|
||||
"durability": null,
|
||||
"name": "Oak seedling",
|
||||
"archery_ticket_price": "0",
|
||||
"id": "5358"
|
||||
},
|
||||
{
|
||||
"examine": "A willow tree seed has been sown and watered in this plant pot",
|
||||
"examine": "A willow tree seed has been sown in this plant pot.",
|
||||
"durability": null,
|
||||
"name": "Willow seedling",
|
||||
"weight": "0.9",
|
||||
|
|
@ -48472,7 +48472,7 @@
|
|||
"id": "5359"
|
||||
},
|
||||
{
|
||||
"examine": "A maple tree has been sown (and watered) in this plant pot.",
|
||||
"examine": "A maple tree seed has been sown in this plant pot.",
|
||||
"durability": null,
|
||||
"name": "Maple seedling",
|
||||
"weight": "0.9",
|
||||
|
|
@ -48480,7 +48480,7 @@
|
|||
"id": "5360"
|
||||
},
|
||||
{
|
||||
"examine": "A yew seed has been sown in the plant pot",
|
||||
"examine": "A yew tree seed has been sown in this plant pot.",
|
||||
"durability": null,
|
||||
"name": "Yew seedling",
|
||||
"weight": "1",
|
||||
|
|
@ -48488,7 +48488,7 @@
|
|||
"id": "5361"
|
||||
},
|
||||
{
|
||||
"examine": "A magic tree seed has been sown and watered in this plant pot.",
|
||||
"examine": "A magic tree seed has been sown in this plant pot.",
|
||||
"durability": null,
|
||||
"name": "Magic seedling",
|
||||
"weight": "0.9",
|
||||
|
|
@ -48496,7 +48496,7 @@
|
|||
"id": "5362"
|
||||
},
|
||||
{
|
||||
"examine": "A spirit seedling is growing in this pot. It has been sown and watered.",
|
||||
"examine": "A spirit tree seed has been sown in this plant pot.",
|
||||
"durability": null,
|
||||
"name": "Spirit seedling",
|
||||
"archery_ticket_price": "0",
|
||||
|
|
@ -48511,7 +48511,7 @@
|
|||
"id": "5364"
|
||||
},
|
||||
{
|
||||
"examine": "A willow tree seed has been sown and watered in this plant pot",
|
||||
"examine": "A willow tree seed has been sown and watered in this plant pot.",
|
||||
"durability": null,
|
||||
"name": "Willow seedling",
|
||||
"weight": "0.9",
|
||||
|
|
@ -48519,7 +48519,7 @@
|
|||
"id": "5365"
|
||||
},
|
||||
{
|
||||
"examine": "A maple tree has been sown (and watered) in this plant pot.",
|
||||
"examine": "A maple tree seed has been sown and watered in this plant pot.",
|
||||
"durability": null,
|
||||
"name": "Maple seedling",
|
||||
"weight": "0.9",
|
||||
|
|
@ -48527,7 +48527,7 @@
|
|||
"id": "5366"
|
||||
},
|
||||
{
|
||||
"examine": "A yew seed has been sown in the plant pot",
|
||||
"examine": "A yew tree seed has been sown and watered in this plant pot.",
|
||||
"durability": null,
|
||||
"name": "Yew seedling",
|
||||
"weight": "1",
|
||||
|
|
@ -48543,7 +48543,7 @@
|
|||
"id": "5368"
|
||||
},
|
||||
{
|
||||
"examine": "A spirit seedling is growing in this pot. It has been sown and watered.",
|
||||
"examine": "A spirit tree seed has been sown and watered in this plant pot.",
|
||||
"durability": null,
|
||||
"name": "Spirit seedling",
|
||||
"archery_ticket_price": "0",
|
||||
|
|
@ -49497,7 +49497,7 @@
|
|||
"id": "5479"
|
||||
},
|
||||
{
|
||||
"examine": "An apple tree has been sown (and watered) in this plant pot.",
|
||||
"examine": "An apple tree seed has been sown in this plant pot.",
|
||||
"durability": null,
|
||||
"name": "Apple seedling",
|
||||
"weight": "0.9",
|
||||
|
|
@ -49505,7 +49505,7 @@
|
|||
"id": "5480"
|
||||
},
|
||||
{
|
||||
"examine": "A banana tree seed has been sown and watered in this plant pot.",
|
||||
"examine": "A banana tree seed has been sown in this plant pot.",
|
||||
"durability": null,
|
||||
"name": "Banana seedling",
|
||||
"weight": "0.9",
|
||||
|
|
@ -49513,14 +49513,14 @@
|
|||
"id": "5481"
|
||||
},
|
||||
{
|
||||
"examine": "An orange tree seed has been sown (and watered)in this plant pot.",
|
||||
"examine": "An orange tree seed has been sown in this plant pot.",
|
||||
"durability": null,
|
||||
"name": "Orange seedling",
|
||||
"archery_ticket_price": "0",
|
||||
"id": "5482"
|
||||
},
|
||||
{
|
||||
"examine": "A curry seed has been sown and watered in this plant pot.",
|
||||
"examine": "A curry tree seed has been sown in this plant pot.",
|
||||
"durability": null,
|
||||
"name": "Curry seedling",
|
||||
"weight": "0.9",
|
||||
|
|
@ -49528,7 +49528,7 @@
|
|||
"id": "5483"
|
||||
},
|
||||
{
|
||||
"examine": "A pineapple tree has been sown (and watered) in this plant pot.",
|
||||
"examine": "A pineapple plant seed has been sown in this plant pot.",
|
||||
"durability": null,
|
||||
"name": "Pineapple seedling",
|
||||
"weight": "0.9",
|
||||
|
|
@ -49536,7 +49536,7 @@
|
|||
"id": "5484"
|
||||
},
|
||||
{
|
||||
"examine": "This needs watering before it will grow.",
|
||||
"examine": "A papaya tree seed has been sown in this plant pot.",
|
||||
"durability": null,
|
||||
"name": "Papaya seedling",
|
||||
"weight": "0.9",
|
||||
|
|
@ -49544,7 +49544,7 @@
|
|||
"id": "5485"
|
||||
},
|
||||
{
|
||||
"examine": "This sapling is ready to be replanted in a fruit tree patch.",
|
||||
"examine": "A palm tree seed has been sown in this plant pot.",
|
||||
"durability": null,
|
||||
"name": "Palm seedling",
|
||||
"weight": "0.66",
|
||||
|
|
@ -49552,7 +49552,7 @@
|
|||
"id": "5486"
|
||||
},
|
||||
{
|
||||
"examine": "A calquat tree has been sown (and watered) in this plant pot.",
|
||||
"examine": "A calquat tree seed has been sown in this plant pot.",
|
||||
"durability": null,
|
||||
"name": "Calquat seedling",
|
||||
"weight": "0.9",
|
||||
|
|
@ -49560,7 +49560,7 @@
|
|||
"id": "5487"
|
||||
},
|
||||
{
|
||||
"examine": "An apple tree has been sown (and watered) in this plant pot.",
|
||||
"examine": "An apple tree seed has been sown and watered in this plant pot.",
|
||||
"durability": null,
|
||||
"name": "Apple seedling",
|
||||
"weight": "0.9",
|
||||
|
|
@ -49576,14 +49576,14 @@
|
|||
"id": "5489"
|
||||
},
|
||||
{
|
||||
"examine": "An orange tree seed has been sown (and watered)in this plant pot.",
|
||||
"examine": "An orange tree seed has been sown and watered in this plant pot.",
|
||||
"durability": null,
|
||||
"name": "Orange seedling",
|
||||
"archery_ticket_price": "0",
|
||||
"id": "5490"
|
||||
},
|
||||
{
|
||||
"examine": "A curry seed has been sown and watered in this plant pot.",
|
||||
"examine": "A curry tree seed has been sown and watered in this plant pot.",
|
||||
"durability": null,
|
||||
"name": "Curry seedling",
|
||||
"weight": "0.9",
|
||||
|
|
@ -49591,7 +49591,7 @@
|
|||
"id": "5491"
|
||||
},
|
||||
{
|
||||
"examine": "A pineapple tree has been sown (and watered) in this plant pot.",
|
||||
"examine": "A pineapple plant seed has been sown and watered in this plant pot.",
|
||||
"durability": null,
|
||||
"name": "Pineapple seedling",
|
||||
"weight": "0.9",
|
||||
|
|
@ -49599,7 +49599,7 @@
|
|||
"id": "5492"
|
||||
},
|
||||
{
|
||||
"examine": "This needs watering before it will grow.",
|
||||
"examine": "A papaya tree seed has been sown and watered in this plant pot.",
|
||||
"durability": null,
|
||||
"name": "Papaya seedling",
|
||||
"weight": "0.9",
|
||||
|
|
@ -49607,7 +49607,7 @@
|
|||
"id": "5493"
|
||||
},
|
||||
{
|
||||
"examine": "This sapling is ready to be replanted in a fruit tree patch.",
|
||||
"examine": "A palm tree seed has been sown and watered in this plant pot.",
|
||||
"durability": null,
|
||||
"name": "Palm seedling",
|
||||
"weight": "0.66",
|
||||
|
|
@ -49615,7 +49615,7 @@
|
|||
"id": "5494"
|
||||
},
|
||||
{
|
||||
"examine": "A calquat tree has been sown (and watered) in this plant pot.",
|
||||
"examine": "A calquat tree seed has been sown and watered in this plant pot.",
|
||||
"durability": null,
|
||||
"name": "Calquat seedling",
|
||||
"weight": "0.9",
|
||||
|
|
@ -51571,9 +51571,9 @@
|
|||
"equip_audio": "2248",
|
||||
"render_anim": "2584",
|
||||
"equipment_slot": "3",
|
||||
"attack_anims": "400,400,401,400",
|
||||
"grand_exchange_price": "483",
|
||||
"attack_audios": "2517,2517,2500,2517",
|
||||
"attack_anims": "400,400,401,400",
|
||||
"name": "Iron dagger(p+)",
|
||||
"tradeable": "true",
|
||||
"archery_ticket_price": "0",
|
||||
|
|
@ -51600,9 +51600,9 @@
|
|||
"equip_audio": "2248",
|
||||
"render_anim": "2584",
|
||||
"equipment_slot": "3",
|
||||
"attack_anims": "400,400,401,400",
|
||||
"grand_exchange_price": "350",
|
||||
"attack_audios": "2517,2517,2500,2517",
|
||||
"attack_anims": "400,400,401,400",
|
||||
"name": "Bronze dagger(p+)",
|
||||
"tradeable": "true",
|
||||
"archery_ticket_price": "0",
|
||||
|
|
@ -51630,9 +51630,9 @@
|
|||
"equip_audio": "2248",
|
||||
"render_anim": "2584",
|
||||
"equipment_slot": "3",
|
||||
"attack_anims": "400,400,401,400",
|
||||
"grand_exchange_price": "575",
|
||||
"attack_audios": "2517,2517,2500,2517",
|
||||
"attack_anims": "400,400,401,400",
|
||||
"name": "Steel dagger(p+)",
|
||||
"tradeable": "true",
|
||||
"archery_ticket_price": "0",
|
||||
|
|
@ -51660,9 +51660,9 @@
|
|||
"equip_audio": "2248",
|
||||
"render_anim": "2584",
|
||||
"equipment_slot": "3",
|
||||
"attack_anims": "400,400,401,400",
|
||||
"grand_exchange_price": "538",
|
||||
"attack_audios": "2517,2517,2500,2517",
|
||||
"attack_anims": "400,400,401,400",
|
||||
"name": "Mithril dagger(p+)",
|
||||
"tradeable": "true",
|
||||
"archery_ticket_price": "0",
|
||||
|
|
@ -51686,9 +51686,9 @@
|
|||
"equip_audio": "2248",
|
||||
"render_anim": "2584",
|
||||
"equipment_slot": "3",
|
||||
"attack_anims": "400,400,401,400",
|
||||
"grand_exchange_price": "800",
|
||||
"attack_audios": "2517,2517,2500,2517",
|
||||
"attack_anims": "400,400,401,400",
|
||||
"name": "Adamant dagger(p+)",
|
||||
"tradeable": "true",
|
||||
"archery_ticket_price": "0",
|
||||
|
|
@ -51783,9 +51783,9 @@
|
|||
"equip_audio": "2248",
|
||||
"render_anim": "2584",
|
||||
"equipment_slot": "3",
|
||||
"attack_anims": "400,400,401,400",
|
||||
"grand_exchange_price": "664",
|
||||
"attack_audios": "2517,2517,2500,2517",
|
||||
"attack_anims": "400,400,401,400",
|
||||
"name": "Black dagger(p+)",
|
||||
"tradeable": "true",
|
||||
"archery_ticket_price": "0",
|
||||
|
|
@ -51831,9 +51831,9 @@
|
|||
"equip_audio": "2248",
|
||||
"render_anim": "2584",
|
||||
"equipment_slot": "3",
|
||||
"attack_anims": "400,400,401,400",
|
||||
"grand_exchange_price": "4128",
|
||||
"attack_audios": "2517,2517,2500,2517",
|
||||
"attack_anims": "400,400,401,400",
|
||||
"name": "Iron dagger(p++)",
|
||||
"tradeable": "true",
|
||||
"archery_ticket_price": "0",
|
||||
|
|
@ -51860,9 +51860,9 @@
|
|||
"equip_audio": "2248",
|
||||
"render_anim": "2584",
|
||||
"equipment_slot": "3",
|
||||
"attack_anims": "400,400,401,400",
|
||||
"grand_exchange_price": "5088",
|
||||
"attack_audios": "2517,2517,2500,2517",
|
||||
"attack_anims": "400,400,401,400",
|
||||
"name": "Br'ze dagger(p++)",
|
||||
"tradeable": "true",
|
||||
"archery_ticket_price": "0",
|
||||
|
|
@ -51890,9 +51890,9 @@
|
|||
"equip_audio": "2248",
|
||||
"render_anim": "2584",
|
||||
"equipment_slot": "3",
|
||||
"attack_anims": "400,400,401,400",
|
||||
"grand_exchange_price": "4729",
|
||||
"attack_audios": "2517,2517,2500,2517",
|
||||
"attack_anims": "400,400,401,400",
|
||||
"name": "Steel dagger(p++)",
|
||||
"tradeable": "true",
|
||||
"archery_ticket_price": "0",
|
||||
|
|
@ -51920,9 +51920,9 @@
|
|||
"equip_audio": "2248",
|
||||
"render_anim": "2584",
|
||||
"equipment_slot": "3",
|
||||
"attack_anims": "400,400,401,400",
|
||||
"grand_exchange_price": "3476",
|
||||
"attack_audios": "2517,2517,2500,2517",
|
||||
"attack_anims": "400,400,401,400",
|
||||
"name": "Mithril dagger(p++)",
|
||||
"tradeable": "true",
|
||||
"archery_ticket_price": "0",
|
||||
|
|
@ -51946,9 +51946,9 @@
|
|||
"equip_audio": "2248",
|
||||
"render_anim": "2584",
|
||||
"equipment_slot": "3",
|
||||
"attack_anims": "400,400,401,400",
|
||||
"grand_exchange_price": "4612",
|
||||
"attack_audios": "2517,2517,2500,2517",
|
||||
"attack_anims": "400,400,401,400",
|
||||
"name": "Adamant dagger(p++)",
|
||||
"tradeable": "true",
|
||||
"archery_ticket_price": "0",
|
||||
|
|
@ -51976,10 +51976,10 @@
|
|||
"equip_audio": "2248",
|
||||
"render_anim": "2584",
|
||||
"equipment_slot": "3",
|
||||
"attack_anims": "400,400,401,400",
|
||||
"lendable": "true",
|
||||
"grand_exchange_price": "5061",
|
||||
"attack_audios": "2517,2517,2500,2517",
|
||||
"attack_anims": "400,400,401,400",
|
||||
"name": "Rune dagger(p++)",
|
||||
"tradeable": "true",
|
||||
"archery_ticket_price": "0",
|
||||
|
|
@ -52043,9 +52043,9 @@
|
|||
"equip_audio": "2248",
|
||||
"render_anim": "2584",
|
||||
"equipment_slot": "3",
|
||||
"attack_anims": "400,400,401,400",
|
||||
"grand_exchange_price": "4921",
|
||||
"attack_audios": "2517,2517,2500,2517",
|
||||
"attack_anims": "400,400,401,400",
|
||||
"name": "Black dagger(p++)",
|
||||
"tradeable": "true",
|
||||
"archery_ticket_price": "0",
|
||||
|
|
@ -52751,7 +52751,7 @@
|
|||
},
|
||||
{
|
||||
"ge_buy_limit": "100",
|
||||
"examine": "This looks a good deal stronger than normal dwarven stout.",
|
||||
"examine": "This looks a good deal stronger than normal Dwarven Stout.",
|
||||
"grand_exchange_price": "56400",
|
||||
"durability": null,
|
||||
"name": "Dwarven stout(m)",
|
||||
|
|
@ -53779,7 +53779,7 @@
|
|||
},
|
||||
{
|
||||
"ge_buy_limit": "100",
|
||||
"examine": "This looks a good deal stronger than normal dwarven stout.",
|
||||
"examine": "This looks a good deal stronger than normal Dwarven Stout.",
|
||||
"grand_exchange_price": "44600",
|
||||
"durability": null,
|
||||
"name": "Dwarven stout(m1)",
|
||||
|
|
@ -53798,7 +53798,7 @@
|
|||
},
|
||||
{
|
||||
"ge_buy_limit": "100",
|
||||
"examine": "This looks a good deal stronger than normal dwarven stout.",
|
||||
"examine": "This looks a good deal stronger than normal Dwarven Stout.",
|
||||
"grand_exchange_price": "68900",
|
||||
"durability": null,
|
||||
"name": "Dwarven stout(m2)",
|
||||
|
|
@ -53817,7 +53817,7 @@
|
|||
},
|
||||
{
|
||||
"ge_buy_limit": "100",
|
||||
"examine": "This looks a good deal stronger than normal dwarven stout.",
|
||||
"examine": "This looks a good deal stronger than normal Dwarven Stout.",
|
||||
"grand_exchange_price": "98800",
|
||||
"durability": null,
|
||||
"name": "Dwarven stout(m3)",
|
||||
|
|
@ -53836,7 +53836,7 @@
|
|||
},
|
||||
{
|
||||
"ge_buy_limit": "100",
|
||||
"examine": "This looks a good deal stronger than normal dwarven stout.",
|
||||
"examine": "This looks a good deal stronger than normal Dwarven Stout.",
|
||||
"grand_exchange_price": "237400",
|
||||
"durability": null,
|
||||
"name": "Dwarven stout(m4)",
|
||||
|
|
@ -60136,7 +60136,7 @@
|
|||
"id": "6578"
|
||||
},
|
||||
{
|
||||
"examine": "I wonder if I can get this enchanted.",
|
||||
"examine": "It needs a string so I can wear it.",
|
||||
"grand_exchange_price": "9058124",
|
||||
"durability": null,
|
||||
"name": "Onyx amulet",
|
||||
|
|
@ -60318,9 +60318,9 @@
|
|||
"equip_audio": "2248",
|
||||
"render_anim": "2584",
|
||||
"equipment_slot": "3",
|
||||
"attack_anims": "400,400,401,400",
|
||||
"grand_exchange_price": "497",
|
||||
"attack_audios": "2517,2517,2500,2517",
|
||||
"attack_anims": "400,400,401,400",
|
||||
"name": "White dagger(p)",
|
||||
"tradeable": "true",
|
||||
"archery_ticket_price": "0",
|
||||
|
|
@ -60348,9 +60348,9 @@
|
|||
"equip_audio": "2248",
|
||||
"render_anim": "2584",
|
||||
"equipment_slot": "3",
|
||||
"attack_anims": "400,400,401,400",
|
||||
"grand_exchange_price": "982",
|
||||
"attack_audios": "2517,2517,2500,2517",
|
||||
"attack_anims": "400,400,401,400",
|
||||
"name": "White dagger(p+)",
|
||||
"tradeable": "true",
|
||||
"archery_ticket_price": "0",
|
||||
|
|
@ -60378,9 +60378,9 @@
|
|||
"equip_audio": "2248",
|
||||
"render_anim": "2584",
|
||||
"equipment_slot": "3",
|
||||
"attack_anims": "400,400,401,400",
|
||||
"grand_exchange_price": "8422",
|
||||
"attack_audios": "2517,2517,2500,2517",
|
||||
"attack_anims": "400,400,401,400",
|
||||
"name": "White dagger(p++)",
|
||||
"tradeable": "true",
|
||||
"archery_ticket_price": "0",
|
||||
|
|
|
|||
|
|
@ -44609,7 +44609,9 @@
|
|||
"strength_level": "1",
|
||||
"id": "5079",
|
||||
"range_level": "1",
|
||||
"attack_level": "1"
|
||||
"attack_level": "1",
|
||||
"death_animation": "5183",
|
||||
"examine": "Handle with care."
|
||||
},
|
||||
{
|
||||
"examine": "It looks fluffy and cute; it's probably deadly.",
|
||||
|
|
@ -59144,7 +59146,7 @@
|
|||
"magic_animation": "7515",
|
||||
"death_animation": "7461",
|
||||
"name": "Revenant hellhound",
|
||||
"defence_level": "1",
|
||||
"defence_level": "50",
|
||||
"safespot": null,
|
||||
"lifepoints": "80",
|
||||
"strength_level": "50",
|
||||
|
|
@ -59990,7 +59992,7 @@
|
|||
"magic_animation": "7515",
|
||||
"death_animation": "7461",
|
||||
"name": "Revenant hellhound",
|
||||
"defence_level": "1",
|
||||
"defence_level": "50",
|
||||
"safespot": null,
|
||||
"lifepoints": "80",
|
||||
"strength_level": "50",
|
||||
|
|
@ -76113,6 +76115,7 @@
|
|||
"id": "2308"
|
||||
},
|
||||
{
|
||||
"examine": "In his former life an expert brewer.",
|
||||
"name": "Metarialus",
|
||||
"id": "2322"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -5547,6 +5547,10 @@
|
|||
"npc_id": "2321",
|
||||
"loc_data": "{2915,10194,1,1,0}-"
|
||||
},
|
||||
{
|
||||
"npc_id": "2322",
|
||||
"loc_data": "{3679,9957,0,1,1}-"
|
||||
},
|
||||
{
|
||||
"npc_id": "2323",
|
||||
"loc_data": "{3056,3306,0,1,1}-"
|
||||
|
|
|
|||
|
|
@ -19168,87 +19168,87 @@
|
|||
"ids": "13614"
|
||||
},
|
||||
{
|
||||
"examine": "A gateway to Varrock",
|
||||
"examine": "A gateway to Varrock.",
|
||||
"ids": "13615"
|
||||
},
|
||||
{
|
||||
"examine": "A gateway to Lumbridge",
|
||||
"examine": "A gateway to Lumbridge.",
|
||||
"ids": "13616"
|
||||
},
|
||||
{
|
||||
"examine": "A gateway to Falador",
|
||||
"examine": "A gateway to Falador.",
|
||||
"ids": "13617"
|
||||
},
|
||||
{
|
||||
"examine": "A gateway to Camelot",
|
||||
"examine": "A gateway to Camelot.",
|
||||
"ids": "13618"
|
||||
},
|
||||
{
|
||||
"examine": "A gateway to Ardougne",
|
||||
"examine": "A gateway to Ardougne.",
|
||||
"ids": "13619"
|
||||
},
|
||||
{
|
||||
"examine": "A gateway to the Yanille watchtower",
|
||||
"examine": "A gateway to the Yanille watchtower.",
|
||||
"ids": "13620"
|
||||
},
|
||||
{
|
||||
"examine": "A gateway to Trollheim",
|
||||
"examine": "A gateway to Kharyrll.",
|
||||
"ids": "13621"
|
||||
},
|
||||
{
|
||||
"examine": "A gateway to Varrock",
|
||||
"examine": "A gateway to Varrock.",
|
||||
"ids": "13622"
|
||||
},
|
||||
{
|
||||
"examine": "A gateway to Lumbridge",
|
||||
"examine": "A gateway to Lumbridge.",
|
||||
"ids": "13623"
|
||||
},
|
||||
{
|
||||
"examine": "A gateway to Falador",
|
||||
"examine": "A gateway to Falador.",
|
||||
"ids": "13624"
|
||||
},
|
||||
{
|
||||
"examine": "A gateway to Camelot",
|
||||
"examine": "A gateway to Camelot.",
|
||||
"ids": "13625"
|
||||
},
|
||||
{
|
||||
"examine": "A gateway to Ardougne",
|
||||
"examine": "A gateway to Ardougne.",
|
||||
"ids": "13626"
|
||||
},
|
||||
{
|
||||
"examine": "A gateway to the Yanille watchtower",
|
||||
"examine": "A gateway to the Yanille watchtower.",
|
||||
"ids": "13627"
|
||||
},
|
||||
{
|
||||
"examine": "A gateway to Trollheim",
|
||||
"examine": "A gateway to Kharyrll.",
|
||||
"ids": "13628"
|
||||
},
|
||||
{
|
||||
"examine": "A gateway to Varrock",
|
||||
"examine": "A gateway to Varrock.",
|
||||
"ids": "13629"
|
||||
},
|
||||
{
|
||||
"examine": "A gateway to Lumbridge",
|
||||
"examine": "A gateway to Lumbridge.",
|
||||
"ids": "13630"
|
||||
},
|
||||
{
|
||||
"examine": "A gateway to Falador",
|
||||
"examine": "A gateway to Falador.",
|
||||
"ids": "13631"
|
||||
},
|
||||
{
|
||||
"examine": "A gateway to Camelot",
|
||||
"examine": "A gateway to Camelot.",
|
||||
"ids": "13632"
|
||||
},
|
||||
{
|
||||
"examine": "A gateway to Ardougne",
|
||||
"examine": "A gateway to Ardougne.",
|
||||
"ids": "13633"
|
||||
},
|
||||
{
|
||||
"examine": "A gateway to the Yanille watchtower",
|
||||
"examine": "A gateway to the Yanille watchtower.",
|
||||
"ids": "13634"
|
||||
},
|
||||
{
|
||||
"examine": "A gateway to Trollheim",
|
||||
"examine": "A gateway to Kharyrll.",
|
||||
"ids": "13635"
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -11,11 +11,13 @@ import core.game.node.entity.player.Player
|
|||
import core.game.node.entity.player.link.TeleportManager
|
||||
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 core.game.world.update.flag.context.Graphics
|
||||
import org.rs09.consts.Items
|
||||
import core.game.world.GameWorld.Pulser
|
||||
import core.tools.Log
|
||||
import org.rs09.consts.Sounds
|
||||
import java.util.*
|
||||
|
||||
|
|
@ -73,17 +75,17 @@ enum class EnchantedJewellery(
|
|||
),
|
||||
AMULET_OF_GLORY(
|
||||
arrayOf(
|
||||
"Edgeville.",
|
||||
"Karamja.",
|
||||
"Draynor Village.",
|
||||
"Al-Kharid.",
|
||||
"Nowhere."
|
||||
"Edgeville",
|
||||
"Karamja",
|
||||
"Draynor Village",
|
||||
"Al Kharid",
|
||||
"Nowhere"
|
||||
),
|
||||
arrayOf(
|
||||
Location.create(3087, 3495, 0),
|
||||
Location.create(2919, 3175, 0),
|
||||
Location.create(3104, 3249, 0),
|
||||
Location.create(3304, 3124, 0)
|
||||
Location.create(3292, 3175, 0)
|
||||
),
|
||||
Items.AMULET_OF_GLORY4_1712,
|
||||
Items.AMULET_OF_GLORY3_1710,
|
||||
|
|
@ -209,7 +211,7 @@ enum class EnchantedJewellery(
|
|||
constructor(options: Array<String>, locations: Array<Location>, vararg ids: Int) : this(options, locations, false, *ids)
|
||||
|
||||
/**
|
||||
* Method used when the player "Use"s the jewellery piece.
|
||||
* Method used when the player clicks one of the options in the jewellery piece's options dialog.
|
||||
* @param player the player.
|
||||
* @param item the used jewellery item.
|
||||
* @param buttonID the button id.
|
||||
|
|
@ -222,7 +224,7 @@ enum class EnchantedJewellery(
|
|||
}
|
||||
return
|
||||
}
|
||||
attemptTeleport(player, item, buttonID, isEquipped)
|
||||
attemptTeleport(player, item, buttonID, true, isEquipped)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -230,43 +232,69 @@ enum class EnchantedJewellery(
|
|||
* @param player the player.
|
||||
* @param item the used jewellery item.
|
||||
* @param buttonID the button id.
|
||||
* @param replace Whether to attempt replacing the item with its lower-charge version. Always true unless you generated a fake item in code.
|
||||
* @param isEquipped If the player is operating.
|
||||
*/
|
||||
fun attemptTeleport(player: Player, item: Item, buttonID: Int, isEquipped: Boolean): Boolean {
|
||||
fun attemptTeleport(player: Player, item: Item, buttonID: Int, replace: Boolean, isEquipped: Boolean): Boolean {
|
||||
val itemIndex = getItemIndex(item)
|
||||
val nextJewellery = Item(getNext(itemIndex))
|
||||
if (!canTeleport(player, nextJewellery)) {
|
||||
return false
|
||||
}
|
||||
Pulser.submit(object : Pulse(0) {
|
||||
private var count = 0
|
||||
private var location = getLocation(buttonID)
|
||||
override fun pulse(): Boolean {
|
||||
when (count) {
|
||||
0 -> {
|
||||
lock(player,4)
|
||||
visualize(player, ANIMATION, GRAPHICS)
|
||||
playGlobalAudio(player.location, Sounds.TELEPORT_ALL_200)
|
||||
player.impactHandler.disabledTicks = 4
|
||||
closeInterface(player)
|
||||
val location = getLocation(buttonID)
|
||||
player.scripts.delay = GameWorld.ticks + 4
|
||||
queueScript(player, 0, QueueStrength.SOFT) { stage ->
|
||||
when (stage) {
|
||||
0 -> {
|
||||
lock(player, 4)
|
||||
visualize(player, ANIMATION, GRAPHICS)
|
||||
playGlobalAudio(player.location, Sounds.TELEPORT_ALL_200)
|
||||
player.impactHandler.disabledTicks = 4
|
||||
closeInterface(player)
|
||||
return@queueScript delayScript(player, 3)
|
||||
}
|
||||
1 -> {
|
||||
teleport(player, location)
|
||||
resetAnimator(player)
|
||||
unlock(player)
|
||||
player.dispatch(TeleportEvent(TeleportManager.TeleportType.NORMAL, TeleportMethod.JEWELRY, item, location))
|
||||
if (!replace) {
|
||||
return@queueScript stopExecuting(player)
|
||||
}
|
||||
3 -> {
|
||||
teleport(player,location)
|
||||
resetAnimator(player)
|
||||
if (isLastItemIndex(itemIndex)) {
|
||||
if (isCrumble) crumbleJewellery(player, item, isEquipped)
|
||||
} else {
|
||||
replaceJewellery(player, item, nextJewellery, isEquipped)
|
||||
if (isLastItemIndex(itemIndex)) {
|
||||
if (isSlayerRing(item)) {
|
||||
if (isEquipped) {
|
||||
// Remove it now, but only addItemOrDrop the gem after the teleport has procced
|
||||
if (removeItem(player, item, Container.EQUIPMENT)) {
|
||||
return@queueScript delayScript(player, 1)
|
||||
}
|
||||
log(this.javaClass, Log.ERR, "Error replacing slayer ring with enchanted gem (removeItem from equipment)")
|
||||
}
|
||||
// Not equipped -> can replace fluently
|
||||
if (replaceSlot(player, item.slot, Item(Items.ENCHANTED_GEM_4155), item) == item) {
|
||||
return@queueScript stopExecuting(player)
|
||||
}
|
||||
log(this.javaClass, Log.ERR, "Error replacing slayer ring with enchanted gem (replaceSlot)")
|
||||
}
|
||||
unlock(player)
|
||||
player.dispatch(TeleportEvent(TeleportManager.TeleportType.NORMAL, TeleportMethod.JEWELRY, item, location))
|
||||
return true
|
||||
// Not slayer ring
|
||||
if (isCrumble) {
|
||||
val removeFrom = if (isEquipped) Container.EQUIPMENT else Container.INVENTORY
|
||||
if (removeItem(player, item, removeFrom)) {
|
||||
return@queueScript stopExecuting(player)
|
||||
}
|
||||
log(this.javaClass, Log.ERR, "Error crumbling jewelry")
|
||||
}
|
||||
} else {
|
||||
replaceJewellery(player, item, nextJewellery, isEquipped)
|
||||
}
|
||||
}
|
||||
count += 1
|
||||
return false
|
||||
2 -> {
|
||||
addItemOrDrop(player, Items.ENCHANTED_GEM_4155)
|
||||
sendMessage(player, "Your Ring of Slaying reverts back into a regular enchanted gem.")
|
||||
}
|
||||
}
|
||||
})
|
||||
return@queueScript stopExecuting(player)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
@ -278,21 +306,6 @@ enum class EnchantedJewellery(
|
|||
}
|
||||
}
|
||||
|
||||
private fun crumbleJewellery(player: Player, item: Item, isEquipped: Boolean) {
|
||||
if (isEquipped) {
|
||||
removeItem(player, item, Container.EQUIPMENT)
|
||||
} else {
|
||||
removeItem(player, item)
|
||||
}
|
||||
if (isSlayerRing(item)) {
|
||||
queueScript(player, 1, QueueStrength.SOFT) {
|
||||
addItemOrDrop(player, Items.ENCHANTED_GEM_4155)
|
||||
sendMessage(player, "Your Ring of Slaying reverts back into a regular enchanted gem.")
|
||||
return@queueScript stopExecuting(player)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isSlayerRing(item: Item): Boolean {
|
||||
return (item.id in RING_OF_SLAYING.ids)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -203,8 +203,8 @@ public enum Consumables {
|
|||
ASGARNIAN_ALE(new Drink(new int[] {1905, 1919}, new MultiEffect(new HealingEffect(2), new SkillEffect(Skills.STRENGTH, 2, 0), new SkillEffect(Skills.ATTACK, -4, 0)), "You drink the ale. You feel slightly reinvigorated...", "...and slightly dizzy too.")),
|
||||
ASGARNIAN_ALE_POH(new Drink(new int[] {7744, 7742}, new MultiEffect(new HealingEffect(2), new SkillEffect(Skills.STRENGTH, 2, 0), new SkillEffect(Skills.ATTACK, -4, 0)), "You drink the ale. You feel slightly reinvigorated...", "...and slightly dizzy too.")),
|
||||
ASGARNIAN_ALE_KEG(new Drink(new int[] {5785, 5783, 5781, 5779, 5769}, new MultiEffect(new SkillEffect(Skills.STRENGTH, 2, 0), new SkillEffect(Skills.ATTACK, -4, 0)), new Animation(2289), "You drink the ale. You feel slightly reinvigorated...", "...and slightly dizzy too.")),
|
||||
ASGARNIAN_ALE_M(new Drink(new int[] {5739, 1919}, new MultiEffect(new SkillEffect(Skills.STRENGTH, 3, 0), new SkillEffect(Skills.ATTACK, -6, 0)))),
|
||||
ASGARNIAN_ALE_M_KEG(new Drink(new int[] {5865, 5863, 5861, 5859, 5769}, new MultiEffect(new SkillEffect(Skills.STRENGTH, 3, 0), new SkillEffect(Skills.ATTACK, -6, 0)), new Animation(2289))),
|
||||
ASGARNIAN_ALE_M(new Drink(new int[] {5739, 1919}, new MultiEffect(new SkillEffect(Skills.STRENGTH, 3, 0), new SkillEffect(Skills.ATTACK, -6, 0)), "You drink the ale. You feel slightly reinvigorated...", "...and slightly dizzy too.")),
|
||||
ASGARNIAN_ALE_M_KEG(new Drink(new int[] {5865, 5863, 5861, 5859, 5769}, new MultiEffect(new SkillEffect(Skills.STRENGTH, 3, 0), new SkillEffect(Skills.ATTACK, -6, 0)), new Animation(2289), "You drink the ale. You feel slightly reinvigorated...", "...and slightly dizzy too.")),
|
||||
AXEMANS_FOLLY(new Drink(new int[] {5751, 1919}, new MultiEffect(new SkillEffect(Skills.WOODCUTTING, 1, 0), new HealingEffect(1), new SkillEffect(Skills.STRENGTH, -3, 0), new SkillEffect(Skills.ATTACK, -3, 0)))),
|
||||
AXEMANS_FOLLY_KEG(new Drink(new int[] {5825, 5823, 5821, 5819, 5769}, new MultiEffect(new SkillEffect(Skills.WOODCUTTING, 1, 0), new HealingEffect(1), new SkillEffect(Skills.STRENGTH, -3, 0), new SkillEffect(Skills.ATTACK, -3, 0)), new Animation(2289))),
|
||||
AXEMANS_FOLLY_M(new Drink(new int[] {5753, 1919}, new MultiEffect(new SkillEffect(Skills.WOODCUTTING, 2, 0), new HealingEffect(2), new SkillEffect(Skills.STRENGTH, -4, 0), new SkillEffect(Skills.ATTACK, -4, 0)))),
|
||||
|
|
@ -231,24 +231,26 @@ public enum Consumables {
|
|||
DRAGON_BITTER_M_KEG(new Drink(new int[] {5889, 5887, 5885, 5883, 5769}, new MultiEffect(new HealingEffect(2), new SkillEffect(Skills.STRENGTH, 3, 0), new SkillEffect(Skills.ATTACK, -6, 0)), new Animation(2289))),
|
||||
DWARVEN_STOUT(new Drink(new int[] {1913, 1919}, new MultiEffect(new SkillEffect(Skills.MINING, 1, 0), new SkillEffect(Skills.SMITHING, 1 ,0), new SkillEffect(Skills.ATTACK, -2, 0), new SkillEffect(Skills.STRENGTH, -2, 0), new SkillEffect(Skills.DEFENCE, -2, 0), new HealingEffect(1)), "You drink the Dwarven Stout. It tastes foul.", "It tastes pretty strong too.")),
|
||||
DWARVEN_STOUT_KEG(new Drink(new int[] {5777, 5775, 5773, 5771, 5769}, new MultiEffect(new SkillEffect(Skills.MINING, 1, 0), new SkillEffect(Skills.SMITHING, 1 ,0), new SkillEffect(Skills.ATTACK, -2, 0), new SkillEffect(Skills.STRENGTH, -2, 0), new SkillEffect(Skills.DEFENCE, -2, 0), new HealingEffect(1)), new Animation(2289), "You drink the Dwarven Stout. It tastes foul.", "It tastes pretty strong too.")),
|
||||
DWARVEN_STOUT_M(new Drink(new int[] {5747, 1919}, new MultiEffect(new SkillEffect(Skills.MINING, 2, 0), new SkillEffect(Skills.SMITHING, 2 ,0), new SkillEffect(Skills.ATTACK, -7, 0), new SkillEffect(Skills.STRENGTH, -7, 0), new SkillEffect(Skills.DEFENCE, -7, 0), new HealingEffect(1)))),
|
||||
DWARVEN_STOUT_M_KEG(new Drink(new int[] {5857, 5855, 5853, 5851, 5769}, new MultiEffect(new SkillEffect(Skills.MINING, 2, 0), new SkillEffect(Skills.SMITHING, 2 ,0), new SkillEffect(Skills.ATTACK, -7, 0), new SkillEffect(Skills.STRENGTH, -7, 0), new SkillEffect(Skills.DEFENCE, -7, 0), new HealingEffect(1)), new Animation(2289))),
|
||||
DWARVEN_STOUT_M(new Drink(new int[] {5747, 1919}, new MultiEffect(new SkillEffect(Skills.MINING, 2, 0), new SkillEffect(Skills.SMITHING, 2 ,0), new SkillEffect(Skills.ATTACK, -7, 0), new SkillEffect(Skills.STRENGTH, -7, 0), new SkillEffect(Skills.DEFENCE, -7, 0), new HealingEffect(1)), "You drink the Dwarven Stout. It tastes foul.", "It tastes pretty strong too.")),
|
||||
DWARVEN_STOUT_M_KEG(new Drink(new int[] {5857, 5855, 5853, 5851, 5769}, new MultiEffect(new SkillEffect(Skills.MINING, 2, 0), new SkillEffect(Skills.SMITHING, 2 ,0), new SkillEffect(Skills.ATTACK, -7, 0), new SkillEffect(Skills.STRENGTH, -7, 0), new SkillEffect(Skills.DEFENCE, -7, 0), new HealingEffect(1)), new Animation(2289), "You drink the Dwarven Stout. It tastes foul.", "It tastes pretty strong too.")),
|
||||
GREENMANS_ALE(new Drink(new int[] {1909, 1919}, new MultiEffect(new HealingEffect(1), new SkillEffect(Skills.HERBLORE, 1, 0), new SkillEffect(Skills.ATTACK, -3, 0), new SkillEffect(Skills.STRENGTH, -3, 0), new SkillEffect(Skills.DEFENCE, -3, 0)))),
|
||||
GREENMANS_ALE_POH(new Drink(new int[] {7746, 7742}, new MultiEffect(new HealingEffect(1), new SkillEffect(Skills.HERBLORE, 1, 0), new SkillEffect(Skills.ATTACK, -3, 0), new SkillEffect(Skills.STRENGTH, -3, 0), new SkillEffect(Skills.DEFENCE, -3, 0)))),
|
||||
GREENMANS_ALE_KEG(new Drink(new int[] {5793, 5791, 5789, 5787, 5769}, new MultiEffect(new HealingEffect(1), new SkillEffect(Skills.HERBLORE, 1, 0), new SkillEffect(Skills.ATTACK, -3, 0), new SkillEffect(Skills.STRENGTH, -3, 0), new SkillEffect(Skills.DEFENCE, -3, 0)), new Animation(2289))),
|
||||
GREENMANS_ALE_M(new Drink(new int[] {5743, 1919}, new MultiEffect(new HealingEffect(1), new SkillEffect(Skills.HERBLORE, 2, 0), new SkillEffect(Skills.ATTACK, -2, 0), new SkillEffect(Skills.STRENGTH, -2, 0)))),
|
||||
GREENMANS_ALE_M_KEG(new Drink(new int[] {5873, 5871, 5869, 5867, 5769}, new MultiEffect(new HealingEffect(1), new SkillEffect(Skills.HERBLORE, 2, 0), new SkillEffect(Skills.ATTACK, -2, 0), new SkillEffect(Skills.STRENGTH, -2, 0)), new Animation(2289))),
|
||||
GROG(new Drink(new int[] {1915, 1919}, new MultiEffect(new SkillEffect(Skills.STRENGTH, 3, 0), new SkillEffect(Skills.ATTACK, -6, 0)))),
|
||||
MOONLIGHT_MEAD(new Drink(new int[] {2955, 1919}, new HealingEffect(4), "It tastes like something just died in your mouth.")),
|
||||
MOONLIGHT_MEAD_KEG(new Drink(new int[] {5817, 5815, 5813, 5811, 5769}, new HealingEffect(4), new Animation(2289), "It tastes like something just died in your mouth.")),
|
||||
MOONLIGHT_MEAD_M(new Drink(new int[] {5749, 1919}, new HealingEffect(6))),
|
||||
MOONLIGHT_MEAD_M_KEG(new Drink(new int[] {5897, 5895, 5893, 5891, 5769}, new HealingEffect(6), new Animation(2289))),
|
||||
MOONLIGHT_MEAD(new Drink(new int[] {2955, 1919}, new HealingEffect(5), "It tastes like something just died in your mouth.")),
|
||||
MOONLIGHT_MEAD_KEG(new Drink(new int[] {5817, 5815, 5813, 5811, 5769}, new HealingEffect(5), new Animation(2289), "It tastes like something just died in your mouth.")),
|
||||
MOONLIGHT_MEAD_M(new Drink(new int[] {5749, 1919}, new HealingEffect(4), "It tastes like something just died in your mouth.")),
|
||||
MOONLIGHT_MEAD_M_KEG(new Drink(new int[] {5897, 5895, 5893, 5891, 5769}, new HealingEffect(4), new Animation(2289), "It tastes like something just died in your mouth.")),
|
||||
SLAYERS_RESPITE(new Drink(new int[] {5759, 1919}, new MultiEffect(new HealingEffect(1), new SkillEffect(Skills.SLAYER, 2, 0), new SkillEffect(Skills.ATTACK, -2, 0), new SkillEffect(Skills.STRENGTH, -2, 0)))),
|
||||
SLAYERS_RESPITE_KEG(new Drink(new int[] {5841, 5839, 5837, 5835, 5769}, new MultiEffect(new HealingEffect(1), new SkillEffect(Skills.SLAYER, 2, 0), new SkillEffect(Skills.ATTACK, -2, 0), new SkillEffect(Skills.STRENGTH, -2, 0)), new Animation(2289))),
|
||||
SLAYERS_RESPITE_M(new Drink(new int[] {5761, 1919}, new MultiEffect(new HealingEffect(1), new SkillEffect(Skills.SLAYER, 4, 0), new SkillEffect(Skills.ATTACK, -2, 0), new SkillEffect(Skills.STRENGTH, -2, 0)))),
|
||||
SLAYERS_RESPITE_M_KEG(new Drink(new int[] {5841, 5839, 5837, 5835, 5769}, new MultiEffect(new HealingEffect(1), new SkillEffect(Skills.SLAYER, 4, 0), new SkillEffect(Skills.ATTACK, -2, 0), new SkillEffect(Skills.STRENGTH, -2, 0)), new Animation(2289))),
|
||||
WIZARDS_MIND_BOMB(new Drink(new int[] {1907, 1919}, new WizardsMindBombEffect(), "You drink the Wizard's Mind Bomb.", "You feel very strange.")),
|
||||
MATURE_WMB(new Drink(new int[] {5741, 1919}, new MatureWmbEffect())),
|
||||
WIZARDS_MIND_BOMB_KEG(new Drink(new int[] {5801, 5799, 5797, 5795, 5769}, new WizardsMindBombEffect(), new Animation(2289), "You drink the Wizard's Mind Bomb.", "You feel very strange.")),
|
||||
MATURE_WMB(new Drink(new int[] {5741, 1919}, new MatureWmbEffect(), "You drink the mature Wizard's Mind Bomb.", "You feel very strange.")),
|
||||
MATURE_WMB_KEG(new Drink(new int[] {5881, 5879, 5877, 5875, 5769}, new MatureWmbEffect(), new Animation(2289), "You drink the mature Wizard's Mind Bomb.", "You feel very strange.")),
|
||||
|
||||
/** Cocktails */
|
||||
FRUIT_BLAST(new Drink(new int[] {2084, 2026}, new HealingEffect(9))),
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ class ShootingStar(var level: ShootingStarType = ShootingStarType.values().rando
|
|||
"South-west Varrock mine" to Location.create(3176, 3362, 0), // South-west Varrock mine / Champion's Guild mine
|
||||
"Varrock east bank" to Location.create(3259, 3407, 0), // Varrock east bank / Rune shop
|
||||
"Lumbridge Swamp south-east mine" to Location.create(3227, 3150, 0), // Lumbridge Swamp south-east mine
|
||||
//"Burgh de Rott bank" to Location.create(3500, 3219, 0), // Burgh de Rott bank (requires quest to enter)
|
||||
"Burgh de Rott bank" to Location.create(3500, 3219, 0), // Burgh de Rott bank (requires quest to enter)
|
||||
"Canifis Bank" to Location.create(3504, 3487, 0), // Canifis bank
|
||||
"Mos Le'Harmless bank" to Location.create(3687, 2969, 0), // Mos Le'Harmless bank (requires quest to enter but is currently accessible for Slayer)
|
||||
"Gnome stronghold Bank" to Location.create(2460, 3432, 0), // Gnome stronghold bank
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ class ShootingStarPlugin : LoginListener, InteractionListener, TickListener, Com
|
|||
fun teleportToStar(player: Player) {
|
||||
val condition: (p: Player) -> Boolean = when (star.location.toLowerCase()) {
|
||||
"canifis bank" -> {p -> requireQuest(p, Quests.PRIEST_IN_PERIL, "to access this.")}
|
||||
//"burgh de rott bank" -> {p -> hasRequirement(p, Quests.IN_AID_OF_THE_MYREQUE)} //disabled: crash
|
||||
"burgh de rott bank" -> {p -> hasRequirement(p, Quests.IN_AID_OF_THE_MYREQUE)}
|
||||
"crafting guild" -> {p -> hasLevelStat(p, Skills.CRAFTING, 40)}
|
||||
"lletya bank" -> {p -> hasRequirement(p, Quests.MOURNINGS_END_PART_I)}
|
||||
"jatizso mine" -> {p -> hasRequirement(p, Quests.THE_FREMENNIK_ISLES)}
|
||||
|
|
@ -120,7 +120,7 @@ class ShootingStarPlugin : LoginListener, InteractionListener, TickListener, Com
|
|||
1 -> dialogue("WARNING: The star is located in the wilderness.").also { stage++ }
|
||||
2 -> player.dialogueInterpreter.sendOptions("Teleport to the star?", "Yes", "No").also { stage++ }
|
||||
3 -> when (buttonID) {
|
||||
1 -> end().also { teleportToStar(player) }
|
||||
1 -> teleportToStar(player)
|
||||
2 -> end()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ class EmptyOptionListener : InteractionListener {
|
|||
BUCKET_OF_COMPOST(Items.COMPOST_6032, Items.BUCKET_1925, "You empty the bucket of compost."),
|
||||
BUCKET_OF_SUPERCOMPOST(Items.SUPERCOMPOST_6034, Items.BUCKET_1925, "You empty the bucket of supercompost."),
|
||||
BUCKET_OF_SLIME(Items.BUCKET_OF_SLIME_4286, Items.BUCKET_1925, "You empty the contents of the bucket on the floor.", Sounds.LIQUID_2401),
|
||||
APPLE_MUSH(Items.APPLE_MUSH_5992,Items.BUCKET_1925, "You empty the bucket of apple mush."),
|
||||
VIAL_OF_WATER(Items.VIAL_OF_WATER_227, Items.VIAL_229, "You empty the vial.", Sounds.LIQUID_2401),
|
||||
BOWL_OF_WATER(Items.BOWL_OF_WATER_1921, Items.BOWL_1923, "You empty the contents of the bowl onto the floor.", Sounds.LIQUID_2401),
|
||||
BOWL_OF_HOT_WATER(Items.BOWL_OF_HOT_WATER_4456, Items.BOWL_1923, "You empty the contents of the bowl onto the floor.", Sounds.LIQUID_2401),
|
||||
|
|
|
|||
|
|
@ -50,15 +50,15 @@ class EnchantedJewelleryListener : InteractionListener {
|
|||
jewellery.use(player, item, 0, isEquipped)
|
||||
return
|
||||
}
|
||||
openDialogue(player,EnchantedJewelleryDialogueFile(jewellery,item,isEquipped))
|
||||
openDialogue(player,EnchantedJewelleryDialogueFile(jewellery, item, true, isEquipped))
|
||||
}
|
||||
}
|
||||
|
||||
class EnchantedJewelleryDialogueFile(val jewellery: EnchantedJewellery, val item: Item, val isEquipped: Boolean) : DialogueFile() {
|
||||
class EnchantedJewelleryDialogueFile(val jewellery: EnchantedJewellery, val item: Item, val replace: Boolean, val isEquipped: Boolean) : DialogueFile() {
|
||||
override fun handle(componentID: Int, buttonID: Int) {
|
||||
when (stage) {
|
||||
START_DIALOGUE -> {
|
||||
interpreter!!.sendOptions("Where would you like to go?", *jewellery.options)
|
||||
interpreter!!.sendOptions("Where would you like to teleport to?", *jewellery.options)
|
||||
stage++
|
||||
}
|
||||
1 -> end().also { jewellery.use(player!!, item, buttonID - 1, isEquipped) }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
package content.global.handlers.item.withitem
|
||||
|
||||
import core.api.addItem
|
||||
import core.api.animate
|
||||
import core.api.removeItem
|
||||
import core.game.interaction.InteractionListener
|
||||
import org.rs09.consts.Items
|
||||
|
||||
class CalquatKeg : InteractionListener{
|
||||
override fun defineListeners() {
|
||||
onUseWith(ITEM, Items.CALQUAT_FRUIT_5980, Items.KNIFE_946) { player, _, _ ->
|
||||
if (removeItem(player, Items.CALQUAT_FRUIT_5980)){
|
||||
animate(player,2290)
|
||||
addItem(player, Items.CALQUAT_KEG_5769)
|
||||
}
|
||||
return@onUseWith true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
package content.global.handlers.npc
|
||||
|
||||
import core.api.*
|
||||
import core.api.playGlobalAudio
|
||||
import core.api.sendGraphics
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.npc.NPCBehavior
|
||||
import org.rs09.consts.NPCs
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.player.Player
|
||||
import core.tools.RandomFunction
|
||||
import core.game.world.update.flag.context.Graphics
|
||||
import core.game.node.entity.combat.ImpactHandler.HitsplatType;
|
||||
|
||||
private val chinchompaIDs = intArrayOf(
|
||||
NPCs.CHINCHOMPA_5079,
|
||||
NPCs.CARNIVOROUS_CHINCHOMPA_5080
|
||||
)
|
||||
|
||||
/**
|
||||
* Minimal evasive approach to the Chinchompas exploding on death cause by combat and not by trapping.
|
||||
*/
|
||||
class ChinchompaDeathListener: NPCBehavior(*chinchompaIDs) {
|
||||
override fun onDeathFinished(self: NPC, killer: Entity) {
|
||||
|
||||
// If it 'died' from getting trapped an attribute is set of 'hunter'.
|
||||
if (!self.attributes.containsKey("hunter") && killer is Player) {
|
||||
val explosionLoc = self.location
|
||||
val validExplosionDmgTiles = explosionLoc.surroundingTiles
|
||||
|
||||
val chinExplosionGFX = Graphics(157, 96)
|
||||
sendGraphics(chinExplosionGFX, explosionLoc)
|
||||
playGlobalAudio(explosionLoc, 158)
|
||||
|
||||
if (validExplosionDmgTiles.contains(killer.location)) {
|
||||
//As weird this looks, it does allow to have a hit from 0 to 2
|
||||
val hitAmount = RandomFunction.random(0, 3)
|
||||
impact(killer, hitAmount, HitsplatType.NORMAL)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* At content.global.skill.hunter.TrapSetting
|
||||
* sets an attribute of 'hunter' during it's getCatchPulse for reward rolling, but it never cleans it up after.
|
||||
* These NPCs is a member of NPC class although exists a HunterNPC class, but it's mainly used for imps.
|
||||
* Logically you'd do this after death finishes, but it would interfere with the reward rolls and I fear it may affect other hunter NPCs.
|
||||
*/
|
||||
override fun onRespawn(self: NPC) {
|
||||
self.removeAttribute("hunter")
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package content.global.handlers.npc
|
||||
|
||||
import content.data.consumables.Consumables
|
||||
import content.global.skill.cooking.fermenting.CalquatDecant
|
||||
import core.api.*
|
||||
import core.game.consumable.Potion
|
||||
import core.game.dialogue.DialogueFile
|
||||
|
|
@ -14,23 +15,39 @@ class DecantListener : InteractionListener {
|
|||
|
||||
companion object {
|
||||
val potions = Consumables.potions.toIntArray()
|
||||
val decantables = potions + CalquatDecant.allKegIds
|
||||
}
|
||||
|
||||
override fun defineListeners() {
|
||||
on(IntType.NPC,"decant"){ player, node ->
|
||||
val (toRemove, toAdd) = decantContainer(player.inventory)
|
||||
for (item in toRemove)
|
||||
removeItem(player, item)
|
||||
for (item in toAdd)
|
||||
// Decant potions
|
||||
val (potionRemove, potionAdd) = decantContainer(player.inventory)
|
||||
for (item in potionRemove)
|
||||
if (!removeItem(player, item)) { return@on false }
|
||||
for (item in potionAdd)
|
||||
addItem(player, item.id, item.amount)
|
||||
|
||||
// Decant kegs
|
||||
val (kegRemove, kegAdd) = CalquatDecant.decantCalquat(player.inventory)
|
||||
for (item in kegRemove)
|
||||
if (!removeItem(player, item)) { return@on false }
|
||||
for (item in kegAdd)
|
||||
addItem(player, item.id, item.amount)
|
||||
|
||||
player.dialogueInterpreter.open(DecantingDialogue(),node.asNpc())
|
||||
return@on true
|
||||
}
|
||||
|
||||
onUseWith(IntType.ITEM, potions, *potions) { player, used, with ->
|
||||
onUseWith(IntType.ITEM, decantables, *decantables) { player, used, with ->
|
||||
if (used !is Item) return@onUseWith false
|
||||
if (with !is Item) return@onUseWith false
|
||||
|
||||
// Check if these are kegs - handle with CalquatDecant
|
||||
if (CalquatDecant.isKeg(used.id) || CalquatDecant.isKeg(with.id)) {
|
||||
return@onUseWith CalquatDecant.combineKegs(player, used, with)
|
||||
}
|
||||
|
||||
// Otherwise handle as potions
|
||||
// Verify these are both the same potion types
|
||||
val potionUsed = Consumables.getConsumableById(used.id)?.consumable as? Potion ?: return@onUseWith false
|
||||
val potionWith = Consumables.getConsumableById(with.id)?.consumable as? Potion ?: return@onUseWith false
|
||||
|
|
@ -83,6 +100,57 @@ class DecantListener : InteractionListener {
|
|||
|
||||
return@onUseWith true
|
||||
}
|
||||
|
||||
// Decant keg into beer glass
|
||||
onUseWith(IntType.ITEM, Items.BEER_GLASS_1919, *CalquatDecant.allKegIds) { player, used, with ->
|
||||
if (used !is Item || with !is Item) return@onUseWith false
|
||||
|
||||
// Determine which is the glass and which is the keg
|
||||
val (glass, keg) = if (used.id == Items.BEER_GLASS_1919) {
|
||||
used to with
|
||||
} else {
|
||||
with to used
|
||||
}
|
||||
|
||||
return@onUseWith CalquatDecant.pourIntoGlass(player, glass, keg)
|
||||
}
|
||||
|
||||
// Barbarian decanting: use a 4-dose potion and an empty vial together to make two 2-dose potions
|
||||
onUseWith(IntType.ITEM, potions, Items.VIAL_229) { player, used, with ->
|
||||
// Check if player has started barbarian herblore training
|
||||
if (getAttribute(player, "/save:barbtraining:herblore", 0) == 0) {
|
||||
return@onUseWith false
|
||||
}
|
||||
|
||||
if (used !is Item) return@onUseWith false
|
||||
if (with !is Item) return@onUseWith false
|
||||
|
||||
// Determine which item is the potion and which is the vial
|
||||
val (potionItem) = if (used.id == Items.VIAL_229) {
|
||||
Pair(with, used)
|
||||
} else {
|
||||
Pair(used, with)
|
||||
}
|
||||
|
||||
// Check if the potion is 4 doses
|
||||
val potion = Consumables.getConsumableById(potionItem.id)?.consumable as? Potion ?: return@onUseWith false
|
||||
val dose = potion.getDose(potionItem)
|
||||
|
||||
if (dose != 4) {
|
||||
return@onUseWith false
|
||||
}
|
||||
|
||||
// Get the 2-dose version of this potion by index
|
||||
val twoDoseId = potion.ids[2]
|
||||
|
||||
// Replace ingredients with products
|
||||
replaceSlot(player, with.slot, Item(twoDoseId))
|
||||
replaceSlot(player, used.slot, Item(twoDoseId))
|
||||
|
||||
playAudio(player, 2401)
|
||||
|
||||
return@onUseWith true
|
||||
}
|
||||
}
|
||||
|
||||
internal class DecantingDialogue : DialogueFile(){
|
||||
|
|
|
|||
|
|
@ -90,8 +90,6 @@ public final class BuildingUtils {
|
|||
|
||||
for (int menuIndex = 0; menuIndex < 7; menuIndex++) {
|
||||
int itemsStringOffset = 97 + (menuIndex * 5);
|
||||
|
||||
//97 +
|
||||
if (menuIndex >= hotspot.getDecorations().length || (hotspot.getDecorations()[menuIndex] != null && hotspot.getDecorations()[menuIndex].isInvisibleNode())) {
|
||||
for (int j = 0; j < 5; j++) {
|
||||
player.getPacketDispatch().sendString("", 396, itemsStringOffset + j);
|
||||
|
|
@ -104,43 +102,24 @@ public final class BuildingUtils {
|
|||
Decoration decoration = hotspot.getDecorations()[menuIndex];
|
||||
items[BUILD_INDEXES[menuIndex]] = new Item(decoration.getInterfaceItem());
|
||||
player.getPacketDispatch().sendString(ItemDefinition.forId(decoration.getInterfaceItem()).getName(), 396, itemsStringOffset);
|
||||
boolean hasRequirements = player.getSkills().getLevel(Skills.CONSTRUCTION) >= decoration.getLevel();
|
||||
boolean hasRequirements = player.getSkills().getLevel(Skills.CONSTRUCTION) >= decoration.getLevel(); //nails are checked in buildDecoration
|
||||
Item[] reqItems = decoration.getItems();
|
||||
String[] reqsText = decoration.getReqsText();
|
||||
for (int j = 0; j < 4; j++) {
|
||||
if (j >= decoration.getItems().length) {
|
||||
if (j == decoration.getItems().length && decoration.getNailAmount() > 0) {
|
||||
player.getPacketDispatch().sendString("Nails: " + decoration.getNailAmount(), 396, (itemsStringOffset + 1) + j);
|
||||
} else {
|
||||
player.getPacketDispatch().sendString("", 396, (itemsStringOffset + 1) + j);
|
||||
}
|
||||
} else {
|
||||
Item item = decoration.getItems()[j];
|
||||
if (!player.getInventory().containsItem(item)) {
|
||||
hasRequirements = false;
|
||||
}
|
||||
String s = item.getName() + ": " + item.getAmount();
|
||||
/*if (j > 1 && (decoration == Decoration.RUNE_CASE1 || decoration == Decoration.RUNE_CASE2)) {
|
||||
if (j == 3) {
|
||||
offset--;
|
||||
item = decoration.getItems()[++j];
|
||||
s = item.getName() + ": " + item.getAmount();
|
||||
}
|
||||
item = decoration.getItems()[j + 1];
|
||||
s += ", " + item.getName() + ": " + item.getAmount();
|
||||
player.getPacketDispatch().sendString(s, 396, 15 + offset + j);
|
||||
continue;
|
||||
}*/
|
||||
player.getPacketDispatch().sendString(s, 396, (itemsStringOffset + 1) + j);
|
||||
if (j < reqItems.length && !player.getInventory().containsItem(reqItems[j])) {
|
||||
hasRequirements = false;
|
||||
}
|
||||
player.getPacketDispatch().sendString(reqsText[j], 396, (itemsStringOffset + 1) + j);
|
||||
}
|
||||
if (hasRequirements) {
|
||||
c261Value += (1 << (menuIndex + 1));
|
||||
}
|
||||
setVarp(player, 1485 + menuIndex, hasRequirements || player.isStaff() ? 1 : 0);
|
||||
setVarp(player, 1485 + menuIndex, hasRequirements || player.isStaff() ? 1 : 0);
|
||||
player.getPacketDispatch().sendString("Level " + decoration.getLevel(), 396, 140 + menuIndex);
|
||||
//player.getPacketDispatch().sendItemZoomOnInterface(items[i].protocol(), 50000, 396, 49 + i);
|
||||
}
|
||||
|
||||
setVarp(player, 261, c261Value);
|
||||
setVarp(player, 261, c261Value);
|
||||
PacketRepository.send(ContainerPacket.class, new ContainerContext(player, 396, 132, 8, items, false));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -454,7 +454,7 @@ public enum Decoration {
|
|||
* Quest hall decorations.
|
||||
*/
|
||||
ANTIDRAGON_SHIELD(13522, 8282, 47, 280, new Item[] { new Item(Items.TEAK_PLANK_8780, 3), new Item(Items.ANTI_DRAGON_SHIELD_1540) }, new Item[] { new Item(Items.ANTI_DRAGON_SHIELD_1540) }),
|
||||
AMULET_OF_GLORY (13523, 8283, 47, 290, new Item[] { new Item(Items.TEAK_PLANK_8780, 3), new Item(Items.AMULET_OF_GLORY_1704) }, new Item[] { new Item(Items.AMULET_OF_GLORY_1704) }),
|
||||
AMULET_OF_GLORY (13523, 8283, 47, 290, new Item[] { new Item(Items.TEAK_PLANK_8780, 3), new Item(Items.AMULET_OF_GLORY_1704) }, new Item[] { new Item(Items.AMULET_OF_GLORY_1704) }, new String[] { "Teak plank: 3", "Amulet of Glory", "(uncharged): 1" }),
|
||||
CAPE_OF_LEGENDS (13524, 8284, 47, 300, new Item[] { new Item(Items.TEAK_PLANK_8780, 3), new Item(Items.CAPE_OF_LEGENDS_1052) }, new Item[] { new Item(Items.CAPE_OF_LEGENDS_1052) }),
|
||||
KING_ARTHUR (13510, 8285, 35, 211, new Item[] { new Item(Items.TEAK_PLANK_8780, 3), new Item(Items.ARTHUR_PORTRAIT_7995) }),
|
||||
ELENA (13511, 8286, 35, 211, new Item[] { new Item(Items.TEAK_PLANK_8780, 3), new Item(Items.ELENA_PORTRAIT_7996) }),
|
||||
|
|
@ -727,23 +727,42 @@ public enum Decoration {
|
|||
private final int[] objectIds;
|
||||
|
||||
/**
|
||||
* If this node should be invisible to user build options
|
||||
* If this node should be invisible to user build options.
|
||||
*/
|
||||
private boolean invisibleNode;
|
||||
|
||||
/**
|
||||
* Constructs a new object, no items, no tools, no refund items.
|
||||
* The requirements text to show for this node.
|
||||
*/
|
||||
private String[] reqsText = {"", "", "", ""};
|
||||
|
||||
private String[] generateDefaultReqsText(Item[] items, int nailAmount) {
|
||||
String[] ret = {"", "", "", ""};
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (i >= items.length) {
|
||||
if (i == items.length && nailAmount > 0) {
|
||||
ret[i] = "Nails: " + nailAmount;
|
||||
}
|
||||
} else {
|
||||
ret[i] = items[i].getName() + ": " + items[i].getAmount();
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new object, default items, default tools, default refund items, default requirements text.
|
||||
* @param objectId The object id.
|
||||
* @param interfaceItem The item id for the building interface.
|
||||
* @param level The level required.
|
||||
* @param experience The experience gained.
|
||||
*/
|
||||
Decoration(int objectId, int interfaceItem, int level, int experience) {
|
||||
this(objectId, interfaceItem, level, experience, new int[] { Items.HAMMER_2347, Items.SAW_8794 }, new Item[] {}, new Item[] {});
|
||||
this(objectId, interfaceItem, level, experience, new int[] { Items.HAMMER_2347, Items.SAW_8794 }, new Item[] {}, new Item[] {}, new String[] {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new object, no tools, no refund items.
|
||||
* Constructs a new object, default tools, default refund items, default requirements text.
|
||||
* @param objectId The object id.
|
||||
* @param interfaceItem The item id for the building interface.
|
||||
* @param level The level required.
|
||||
|
|
@ -751,11 +770,12 @@ public enum Decoration {
|
|||
* @param items The items required.
|
||||
*/
|
||||
Decoration(int objectId, int interfaceItem, int level, int experience, Item[] items) {
|
||||
this(objectId, interfaceItem, level, experience, new int[] { Items.HAMMER_2347, Items.SAW_8794 }, items, new Item[] {});
|
||||
this(objectId, interfaceItem, level, experience, new int[] { Items.HAMMER_2347, Items.SAW_8794 }, items, new Item[] {}, new String[] {});
|
||||
this.reqsText = generateDefaultReqsText(items, getNailAmount());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new object, no refund items.
|
||||
* Constructs a new object, default refund items, default requirements text.
|
||||
* @param objectId The object id.
|
||||
* @param interfaceItem The item id for the building interface.
|
||||
* @param level The level required.
|
||||
|
|
@ -764,7 +784,8 @@ public enum Decoration {
|
|||
* @param items The items required.
|
||||
*/
|
||||
Decoration(int objectId, int interfaceItem, int level, int experience, int[] tools, Item[] items) {
|
||||
this(objectId, interfaceItem, level, experience, tools, items, new Item[] {});
|
||||
this(objectId, interfaceItem, level, experience, tools, items, new Item[] {}, new String[] {});
|
||||
this.reqsText = generateDefaultReqsText(items, getNailAmount());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -777,7 +798,21 @@ public enum Decoration {
|
|||
* @param refundItems The items to be refunded when the item is removed.
|
||||
*/
|
||||
Decoration(int objectId, int interfaceItem, int level, int experience, Item[] items, Item[] refundItems) {
|
||||
this(objectId, interfaceItem, level, experience, new int[] { Items.HAMMER_2347, Items.SAW_8794 }, items, refundItems);
|
||||
this(objectId, interfaceItem, level, experience, new int[] { Items.HAMMER_2347, Items.SAW_8794 }, items, refundItems, new String[] {});
|
||||
this.reqsText = generateDefaultReqsText(items, getNailAmount());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new object, default tools.
|
||||
* @param objectId The object id.
|
||||
* @param interfaceItem The item id for the building interface.
|
||||
* @param level The level required.
|
||||
* @param experience The experience gained.
|
||||
* @param items The items required.
|
||||
* @param refundItems The items to be refunded when the item is removed.
|
||||
*/
|
||||
Decoration(int objectId, int interfaceItem, int level, int experience, Item[] items, Item[] refundItems, String[] reqsText) {
|
||||
this(objectId, interfaceItem, level, experience, new int[] { Items.HAMMER_2347, Items.SAW_8794 }, items, refundItems, reqsText);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -789,8 +824,9 @@ public enum Decoration {
|
|||
* @param tools The tools needed.
|
||||
* @param items The items required.
|
||||
* @param refundItems The items to be refunded when the item is removed.
|
||||
* @param reqsText The requirements text to be shown in the interface.
|
||||
*/
|
||||
Decoration(int objectId, int interfaceItem, int level, int experience, int[] tools, Item[] items, Item[] refundItems) {
|
||||
Decoration(int objectId, int interfaceItem, int level, int experience, int[] tools, Item[] items, Item[] refundItems, String[] reqsText) {
|
||||
this.objectId = objectId;
|
||||
this.objectIds = null;
|
||||
this.interfaceItem = interfaceItem;
|
||||
|
|
@ -799,6 +835,9 @@ public enum Decoration {
|
|||
this.tools = tools;
|
||||
this.items = items;
|
||||
this.refundItems = refundItems;
|
||||
if (reqsText.length > 0) {
|
||||
System.arraycopy(reqsText, 0, this.reqsText, 0, reqsText.length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -822,18 +861,6 @@ public enum Decoration {
|
|||
Decoration(int[] objectIds, int interfaceItem, int level, int experience, Item[] items) {
|
||||
this(objectIds, interfaceItem, level, experience, new int[] { Items.HAMMER_2347, Items.SAW_8794 }, items, new Item[] {});
|
||||
}
|
||||
/**
|
||||
* Constructs a new object no refund items.
|
||||
* @param objectIds The object id.
|
||||
* @param interfaceItem The item id for the building interface.
|
||||
* @param level The level required.
|
||||
* @param experience The experience gained.
|
||||
* @param tools The tools needed.
|
||||
* @param items The items required.
|
||||
*/
|
||||
Decoration(int[] objectIds, int interfaceItem, int level, int experience, int[] tools, Item[] items) {
|
||||
this(objectIds, interfaceItem, level, experience, tools, items, new Item[] {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new object.
|
||||
|
|
@ -1000,4 +1027,12 @@ public enum Decoration {
|
|||
public boolean isInvisibleNode() {
|
||||
return invisibleNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the requirements text.
|
||||
* @return The requirements text.
|
||||
*/
|
||||
public String[] getReqsText() {
|
||||
return reqsText;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package content.global.skill.construction.decoration.portalchamber;
|
||||
|
||||
|
||||
import content.data.Quests;
|
||||
import content.global.skill.construction.Hotspot;
|
||||
import content.global.skill.runecrafting.Rune;
|
||||
import core.cache.def.impl.SceneryDefinition;
|
||||
|
|
@ -18,6 +19,7 @@ import core.plugin.Plugin;
|
|||
import core.plugin.ClassScanner;
|
||||
|
||||
import static content.region.kandarin.ardougne.quest.plaguecity.PlagueCityListeners.ARDOUGNE_TELE_ATTRIBUTE;
|
||||
import static core.api.ContentAPIKt.*;
|
||||
|
||||
/**
|
||||
* PortalChamberPlugin
|
||||
|
|
@ -89,15 +91,14 @@ public class PortalChamberPlugin extends OptionHandler {
|
|||
}
|
||||
for (Locations l : Locations.values()) {
|
||||
if (l.name().contains(identifier)) {
|
||||
if (l == Locations.ARDOUGNE){
|
||||
if (!player.getAttribute(ARDOUGNE_TELE_ATTRIBUTE, false)) {
|
||||
player.sendMessage("You do not have the requirements to direct the portal there");
|
||||
return;
|
||||
}
|
||||
if ((l == Locations.ARDOUGNE && !getAttribute(player, ARDOUGNE_TELE_ATTRIBUTE, false)) ||
|
||||
(l == Locations.KHARYRLL && !isQuestComplete(player, Quests.DESERT_TREASURE))) {
|
||||
sendMessage(player, "You do not have the requirements to direct the portal there.");
|
||||
return;
|
||||
}
|
||||
Item[] runes = l.runes;
|
||||
if (!player.getInventory().containsItems(runes)) {
|
||||
player.sendMessage("You do not have the required runes to build this portal");
|
||||
sendMessage(player, "You do not have the required runes to build this portal.");
|
||||
return;
|
||||
}
|
||||
player.getInventory().remove(runes);
|
||||
|
|
|
|||
|
|
@ -1,53 +1,53 @@
|
|||
package content.global.skill.construction.decoration.questhall
|
||||
|
||||
import content.data.EnchantedJewellery
|
||||
import content.global.handlers.item.EnchantedJewelleryListener.EnchantedJewelleryDialogueFile
|
||||
import core.api.delayScript
|
||||
import core.api.lock
|
||||
import core.api.openDialogue
|
||||
import core.api.playGlobalAudio
|
||||
import core.api.queueScript
|
||||
import core.api.resetAnimator
|
||||
import core.api.stopExecuting
|
||||
import core.api.teleport
|
||||
import core.api.visualize
|
||||
import core.game.interaction.IntType
|
||||
import core.game.interaction.InteractionListener
|
||||
import core.game.interaction.QueueStrength
|
||||
import core.game.node.Node
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.item.Item
|
||||
import core.game.node.scenery.Scenery
|
||||
import core.game.system.task.Pulse
|
||||
import core.game.world.map.Location
|
||||
import core.game.world.update.flag.context.Animation
|
||||
import core.game.world.update.flag.context.Graphics
|
||||
import org.rs09.consts.Items
|
||||
import org.rs09.consts.Sounds
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class MountedGlory : InteractionListener {
|
||||
|
||||
val MOUNTED_GLORY = 13523
|
||||
|
||||
val TELEPORTS = arrayOf(
|
||||
Location.create(3087, 3495, 0),
|
||||
Location.create(2919, 3175, 0),
|
||||
Location.create(3104, 3249, 0),
|
||||
Location.create(3304, 3124, 0)
|
||||
)
|
||||
val TELEPORTS = EnchantedJewellery.AMULET_OF_GLORY.locations
|
||||
|
||||
override fun defineListeners() {
|
||||
on(MOUNTED_GLORY, IntType.SCENERY, "Edgeville") { player, `object` ->
|
||||
mountedGloryAction(player, `object`, 0)
|
||||
return@on true
|
||||
}
|
||||
|
||||
on(MOUNTED_GLORY, IntType.SCENERY, "Karamja") { player, `object` ->
|
||||
mountedGloryAction(player, `object`, 1)
|
||||
return@on true
|
||||
}
|
||||
|
||||
on(MOUNTED_GLORY, IntType.SCENERY, "Draynor Village") { player, `object` ->
|
||||
mountedGloryAction(player, `object`, 2)
|
||||
return@on true
|
||||
}
|
||||
|
||||
on(MOUNTED_GLORY, IntType.SCENERY, "Al Kharid") { player, `object` ->
|
||||
mountedGloryAction(player, `object`, 3)
|
||||
return@on true
|
||||
}
|
||||
on(MOUNTED_GLORY, IntType.SCENERY, "Rub") { player, _ ->
|
||||
openDialogue(player,EnchantedJewelleryDialogueFile(EnchantedJewellery.AMULET_OF_GLORY, Item(Items.AMULET_OF_GLORY4_1712), false, false))
|
||||
return@on true
|
||||
}
|
||||
}
|
||||
private fun mountedGloryAction(player : Player, `object` : Node, int : Int) {
|
||||
if (player.houseManager.isBuildingMode) {
|
||||
|
|
@ -57,21 +57,16 @@ class MountedGlory : InteractionListener {
|
|||
if (!player.zoneMonitor.teleport(1, Item(Items.AMULET_OF_GLORY_1704))) {
|
||||
return
|
||||
}
|
||||
Executors.newSingleThreadScheduledExecutor().schedule({
|
||||
player.pulseManager.run(object : Pulse() {
|
||||
var counter = 0
|
||||
override fun pulse(): Boolean {
|
||||
when (counter++) {
|
||||
1 -> {
|
||||
player.lock(5)
|
||||
player.visualize(Animation(714), Graphics(308, 100, 50))
|
||||
playGlobalAudio(player.location, Sounds.TELEPORT_ALL_200)
|
||||
}
|
||||
4 -> player.animator.reset().also { teleport(player, TELEPORTS[int]) }
|
||||
}
|
||||
return false
|
||||
queueScript(player, 0, QueueStrength.SOFT) { stage ->
|
||||
if (stage == 0) {
|
||||
lock(player, 4)
|
||||
visualize(player, Animation(714), Graphics(308, 100, 50))
|
||||
playGlobalAudio(player.location, Sounds.TELEPORT_ALL_200)
|
||||
return@queueScript delayScript(player, 3)
|
||||
}
|
||||
})
|
||||
}, 0, TimeUnit.SECONDS)
|
||||
resetAnimator(player)
|
||||
teleport(player, TELEPORTS[int])
|
||||
return@queueScript stopExecuting(player)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,98 +0,0 @@
|
|||
package content.global.skill.construction.decoration.questhall;
|
||||
|
||||
|
||||
import core.cache.def.impl.SceneryDefinition;
|
||||
import core.game.dialogue.DialogueAction;
|
||||
import core.game.dialogue.DialogueInterpreter;
|
||||
import core.game.interaction.OptionHandler;
|
||||
import core.game.node.Node;
|
||||
import core.game.node.entity.player.Player;
|
||||
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 core.game.world.update.flag.context.Graphics;
|
||||
import core.plugin.Initializable;
|
||||
import core.plugin.Plugin;
|
||||
import org.rs09.consts.Sounds;
|
||||
|
||||
import static core.api.ContentAPIKt.playGlobalAudio;
|
||||
|
||||
/**
|
||||
* Handles the POH Mounted Glory.
|
||||
* @author Splinter
|
||||
*/
|
||||
@Initializable
|
||||
public class MountedGloryPlugin extends OptionHandler {
|
||||
|
||||
/**
|
||||
* Represents the teleport animation.
|
||||
*/
|
||||
private static final Animation ANIMATION = new Animation(714);
|
||||
|
||||
/**
|
||||
* Represents the graphics to use.
|
||||
*/
|
||||
private static final Graphics GRAPHICS = new Graphics(308, 100, 50);
|
||||
|
||||
@Override
|
||||
public Plugin<Object> newInstance(Object arg) throws Throwable {
|
||||
SceneryDefinition.forId(13523).getHandlers().put("option:rub", this);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(Player player, Node node, String option) {
|
||||
DialogueInterpreter interpreter = player.getDialogueInterpreter();
|
||||
interpreter.sendOptions("Select a location.", "Edgeville", "Karamja", "Draynor Village", "Al-Kharid", "Nowhere.");
|
||||
interpreter.addAction(new DialogueAction() {
|
||||
|
||||
@Override
|
||||
public void handle(Player player, int buttonId) {
|
||||
switch (buttonId) {
|
||||
case 2:
|
||||
teleport(player, Location.create(3087, 3495, 0));
|
||||
break;
|
||||
case 3:
|
||||
teleport(player, Location.create(2919, 3175, 0));
|
||||
break;
|
||||
case 4:
|
||||
teleport(player, Location.create(3081, 3250, 0));
|
||||
break;
|
||||
case 5:
|
||||
teleport(player, Location.create(3304, 3124, 0));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method used to teleport to a location.
|
||||
* @param player the player.
|
||||
* @param location the location.
|
||||
*/
|
||||
private boolean teleport(final Player player, final Location location) {
|
||||
if (player.isTeleBlocked()) {
|
||||
player.sendMessage("A magical force has stopped you from teleporting.");
|
||||
return false;
|
||||
}
|
||||
player.lock();
|
||||
player.visualize(ANIMATION, GRAPHICS);
|
||||
playGlobalAudio(player.getLocation(), Sounds.TELEPORT_ALL_200);
|
||||
player.getImpactHandler().setDisabledTicks(4);
|
||||
GameWorld.getPulser().submit(new Pulse(4, player) {
|
||||
@Override
|
||||
public boolean pulse() {
|
||||
player.unlock();
|
||||
player.getProperties().setTeleportLocation(location);
|
||||
player.getAnimator().reset();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -94,6 +94,7 @@ public enum CookableItems {
|
|||
RAW_OOMLIE(Items.RAW_OOMLIE_2337, 0, Items.BURNT_OOMLIE_2426, 50, 0, 0, 0, 0, 0), // always burns
|
||||
OOMLIE_WRAP(Items.COOKED_OOMLIE_WRAP_2343, Items.WRAPPED_OOMLIE_2341, Items.BURNT_OOMLIE_WRAP_2345, 50, 30, 106, 450, 112, 476),
|
||||
SEAWEED(Items.SEAWEED_401, 0, Items.SODA_ASH_1781, 0, 0, 0, 0, 0, 0),
|
||||
BARLEY(Items.BARLEY_6006, 0, Items.BARLEY_MALT_6008, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
/**
|
||||
* Sinew gets overridden by BEEF in this enum, due to values being looked up by the items RAW id.
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ class CookingRewrite : InteractionListener {
|
|||
list.add(Items.COOKED_MEAT_2142)
|
||||
list.add(RAW_BEEF_2132)
|
||||
list.add(RAW_BEAR_MEAT_2136)
|
||||
list.add(Items.BARLEY_6006)
|
||||
list.add(SEAWEED_401)
|
||||
list.add(Items.BOWL_OF_WATER_1921)
|
||||
RAW_FOODS = list.toIntArray()
|
||||
|
|
@ -76,7 +77,7 @@ class CookingRewrite : InteractionListener {
|
|||
player.dialogueInterpreter.open(CookingDialogue(item.id,9436,true,obj,item.id))
|
||||
return@onUseWith true
|
||||
}
|
||||
BREAD_DOUGH_2307, UNCOOKED_CAKE_1889 -> if (!range) {
|
||||
BREAD_DOUGH_2307, UNCOOKED_CAKE_1889, Items.BARLEY_6006 -> if (!range) {
|
||||
player.packetDispatch.sendMessage("You need to cook this on a range.")
|
||||
return@onUseWith false
|
||||
}
|
||||
|
|
@ -104,7 +105,7 @@ class CookingRewrite : InteractionListener {
|
|||
}
|
||||
|
||||
companion object {
|
||||
val COOKING_OBJs = intArrayOf(24313,21302, 13528, 13529, 13533, 13531, 13536, 13539, 13542, 2728, 2729, 2730, 2731, 2732, 2859, 3038, 3769, 3775, 4265, 4266, 5249, 5499, 5631, 5632, 5981, 9682, 10433, 11404, 11405, 11406, 12102, 12796, 13337, 13881, 14169, 14919, 15156, 20000, 20001, 21620, 21792, 22713, 22714, 23046, 24283, 24284, 25155, 25156, 25465, 25730, 27297, 29139, 30017, 32099, 33500, 34495, 34546, 36973, 37597, 37629, 37726, 114, 4172, 5275, 8750, 16893, 22154, 34410, 34565, 114, 9085, 9086, 9087, 12269, 15398, 25440, 25441, 2724, 2725, 2726, 4618, 4650, 5165, 6093, 6094, 6095, 6096, 8712, 9374, 9439, 9440, 9441, 10824, 17640, 17641, 17642, 17643, 18039, 18170, 21795, 24285, 24329, 27251, 33498, 35449, 36815, 36816, 37426, 40110, 10377)
|
||||
val COOKING_OBJs = intArrayOf(24313 ,21302, 13528, 13529, 13533, 13531, 13536, 13539, 13542, 2728, 2729, 2730, 2731, 2732, 2859, 3038, 3769, 3775, 4265, 4266, 5249, 5499, 5631, 5632, 5981, 9682, 10433, 11404, 11405, 11406, 12102, 12796, 13337, 13881, 14169, 14919, 15156, 20000, 20001, 21620, 21792, 22713, 22714, 23046, 24283, 24284, 25155, 25156, 25465, 25730, 27297, 29139, 30017, 32099, 33500, 34495, 34546, 36973, 37597, 37629, 37726, 114, 4172, 5275, 8750, 16893, 22154, 34410, 34565, 114, 9085, 9086, 9087, 12269, 15398, 25440, 25441, 2724, 2725, 2726, 4618, 4650, 5165, 6093, 6094, 6095, 6096, 8712, 9374, 9439, 9440, 9441, 10824, 17640, 17641, 17642, 17643, 18039, 18170, 21795, 24285, 24329, 27251, 33498, 35449, 36815, 36816, 37426, 40110, 10377)
|
||||
|
||||
@JvmStatic
|
||||
fun cook(player: Player, `object`: Scenery?, initial: Int, product: Int, amount: Int) {
|
||||
|
|
|
|||
|
|
@ -200,6 +200,9 @@ public class StandardCookingPulse extends Pulse {
|
|||
if (product.getId() == Items.SODA_ASH_1781) {
|
||||
return "You burn the seaweed into soda ash.";
|
||||
}
|
||||
if (product.getId() == Items.BARLEY_MALT_6008) {
|
||||
return null; // Both live branches of Jagexscape lack a message for this and I can't find period evidence of a message
|
||||
}
|
||||
if (CookableItems.intentionalBurn(food.getId())) {
|
||||
return "You deliberately burn the perfectly good piece of meat.";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,187 @@
|
|||
package content.global.skill.cooking.fermenting
|
||||
|
||||
import core.api.*
|
||||
import core.game.interaction.QueueStrength
|
||||
import core.game.interaction.InteractionListener
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.skill.Skills
|
||||
import core.game.node.item.Item
|
||||
import core.game.node.scenery.Scenery
|
||||
import core.game.world.map.Location
|
||||
import core.game.world.update.flag.context.Animation
|
||||
import core.tools.ticksToCycles
|
||||
import org.rs09.consts.Items
|
||||
import org.rs09.consts.Scenery as SceneryIds
|
||||
|
||||
|
||||
class AppleMushListener : InteractionListener {
|
||||
|
||||
private data class BarrelLocations(
|
||||
val start: Location, // Where the player begins the mushing animation from
|
||||
val jump: Location, // Where the player ends the mushing animation at
|
||||
val tap: Location, // Where the apple barrel's tap is located
|
||||
val stand: Location // Where the player stands to collect from the tap
|
||||
)
|
||||
|
||||
private val barrelLocations = mapOf(
|
||||
14747 to BarrelLocations( // Port Phasmatys
|
||||
start = Location.create(3676, 9959, 0),
|
||||
jump = Location.create(3676, 9957, 0),
|
||||
tap = Location.create(3677, 9959, 0),
|
||||
stand = Location.create(3678, 9959, 0)
|
||||
),
|
||||
11679 to BarrelLocations( // Keldagrim
|
||||
start = Location.create(2914, 10193, 1),
|
||||
jump = Location.create(2914, 10191, 1),
|
||||
tap = Location.create(2915, 10193, 1),
|
||||
stand = Location.create(2916, 10193, 1)
|
||||
),
|
||||
9780 to BarrelLocations( // Gnome Orchard
|
||||
start = Location.create(2484, 3375, 0),
|
||||
jump = Location.create(2484, 3373, 0),
|
||||
tap = Location.create(2485, 3375, 0),
|
||||
stand = Location.create(2486, 3375, 0)
|
||||
)
|
||||
)
|
||||
|
||||
private val emptyAppleBarrels = intArrayOf(
|
||||
SceneryIds.APPLE_BARREL_7403,
|
||||
SceneryIds.APPLE_BARREL_8807
|
||||
)
|
||||
|
||||
private val fullAppleBarrels = intArrayOf(
|
||||
SceneryIds.APPLE_BARREL_7404,
|
||||
SceneryIds.APPLE_BARREL_8808
|
||||
)
|
||||
|
||||
private val appleTaps = intArrayOf(
|
||||
SceneryIds.BARREL_TAP_7406,
|
||||
SceneryIds.BARREL_TAP_8737
|
||||
)
|
||||
|
||||
private val MUSH_ANIM = Animation(2306)
|
||||
|
||||
override fun defineListeners() {
|
||||
|
||||
onUseWith(SCENERY, Items.COOKING_APPLE_1955, *emptyAppleBarrels) { player, _, with ->
|
||||
if (getDynLevel(player, Skills.COOKING) < 14) {
|
||||
sendDialogue(player, "You need a Cooking level of at least 14 in order to do this.")
|
||||
return@onUseWith true
|
||||
}
|
||||
if (!inInventory(player, Items.COOKING_APPLE_1955, 4)) {
|
||||
sendDialogue(player, "You need 4 cooking apples to make apple mush.")
|
||||
return@onUseWith true
|
||||
}
|
||||
if (!inInventory(player, Items.BUCKET_1925)) {
|
||||
sendDialogue(player, "You need a bucket to collect the apple mush.")
|
||||
return@onUseWith true
|
||||
}
|
||||
if (inInventory(player, Items.COOKING_APPLE_1955, 4)) {
|
||||
startMushing(player, with.asScenery())
|
||||
}
|
||||
return@onUseWith true
|
||||
}
|
||||
|
||||
onUseWith(SCENERY, Items.BUCKET_1925, *appleTaps) { player, _, _ ->
|
||||
if (getAttribute(player, "/save:cooking:brewing-apples", false)) {
|
||||
if (removeItem(player, Item(Items.BUCKET_1925, 1))) {
|
||||
addItem(player, Items.APPLE_MUSH_5992, 1)
|
||||
sendMessage(player, "You fill a bucket with apple mush.")
|
||||
}
|
||||
removeAttribute(player, "/save:cooking:brewing-apples")
|
||||
return@onUseWith true
|
||||
}
|
||||
sendMessage(player, "Nothing interesting happens.")
|
||||
return@onUseWith false
|
||||
}
|
||||
}
|
||||
|
||||
private fun startMushing(player: Player, barrel: Scenery) {
|
||||
val initLoc = player.location
|
||||
val barrelLoc = barrel.location
|
||||
val locations = barrelLocations[player.location.regionId]
|
||||
val startLoc = locations?.start
|
||||
val jumpLoc = locations?.jump
|
||||
val standLoc = locations?.stand
|
||||
val tapLoc = locations?.tap
|
||||
val fastStart: Boolean = initLoc == startLoc
|
||||
|
||||
// https://www.youtube.com/watch?v=7I_Ec_tQ-tc
|
||||
// Has to be soft or else you can log out and clog the barrel
|
||||
queueScript(player, 1 ,QueueStrength.SOFT) { counter ->
|
||||
when (counter) {
|
||||
0 -> {
|
||||
stopWalk(player)
|
||||
forceWalk(player, startLoc!!, "smart")
|
||||
lock(player, MUSH_ANIM.duration + 7)
|
||||
return@queueScript delayScript(player, if (fastStart) 1 else 4)
|
||||
}
|
||||
|
||||
1 -> {
|
||||
face(player, barrelLoc)
|
||||
if (!removeItem(player, Item(Items.COOKING_APPLE_1955, 4))) { return@queueScript stopExecuting(player) }
|
||||
setAttribute(player, "/save:cooking:brewing-apples", true)
|
||||
return@queueScript delayScript(player, 0)
|
||||
}
|
||||
|
||||
2 -> {
|
||||
forceMove(player, startLoc!!, barrelLoc, 0, ticksToCycles(1), anim = MUSH_ANIM.id)
|
||||
if (barrel.id == SceneryIds.APPLE_BARREL_7403) sendGraphics(414, barrelLoc)
|
||||
else sendGraphics(413, barrelLoc)
|
||||
swapBarrel(barrel)
|
||||
return@queueScript delayScript(player, MUSH_ANIM.duration - 1)
|
||||
}
|
||||
|
||||
3 -> {
|
||||
forceMove(player, barrelLoc, jumpLoc!!, 0, ticksToCycles(1))
|
||||
return@queueScript delayScript(player, 2)
|
||||
}
|
||||
|
||||
4 -> {
|
||||
stopWalk(player)
|
||||
return@queueScript delayScript(player, 1)
|
||||
}
|
||||
|
||||
5 -> {
|
||||
unlock(player)
|
||||
stopWalk(player)
|
||||
forceWalk(player, standLoc!!, "smart")
|
||||
lock(player, 5)
|
||||
return@queueScript delayScript(player, 4)
|
||||
}
|
||||
|
||||
6 -> {
|
||||
stopWalk(player)
|
||||
face(player, tapLoc!!)
|
||||
return@queueScript delayScript(player, 1)
|
||||
}
|
||||
|
||||
7 -> {
|
||||
if (removeItem(player, Item(Items.BUCKET_1925, 1))) {
|
||||
addItem(player, Items.APPLE_MUSH_5992, 1)
|
||||
sendMessage(player, "You fill a bucket with apple mush.")
|
||||
}
|
||||
removeAttribute(player, "/save:cooking:brewing-apples")
|
||||
val currentBarrel = getScenery(barrelLoc)
|
||||
currentBarrel?.let { swapBarrel(it) }
|
||||
unlock(player)
|
||||
return@queueScript stopExecuting(player)
|
||||
}
|
||||
else -> return@queueScript stopExecuting(player)
|
||||
}
|
||||
}
|
||||
unlock(player)
|
||||
}
|
||||
|
||||
private fun swapBarrel(barrel: Scenery) {
|
||||
val emptyIndex = emptyAppleBarrels.indexOf(barrel.id)
|
||||
val fullIndex = fullAppleBarrels.indexOf(barrel.id)
|
||||
val newId = when {
|
||||
emptyIndex != -1 -> fullAppleBarrels[emptyIndex]
|
||||
fullIndex != -1 -> emptyAppleBarrels[fullIndex]
|
||||
else -> return
|
||||
}
|
||||
replaceScenery(barrel, newId, -1)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
package content.global.skill.cooking.fermenting
|
||||
|
||||
import core.api.log
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.system.timer.PersistTimer
|
||||
import core.tools.Log
|
||||
import core.tools.secondsToTicks
|
||||
import org.json.simple.JSONArray
|
||||
import org.json.simple.JSONObject
|
||||
|
||||
/**
|
||||
* The timer for regular brewing operations
|
||||
*/
|
||||
|
||||
const val brewCycleTime = 6 /*hours*/ * 60 /*minutes per hour*/ * 100 /*ticks per minute*/
|
||||
|
||||
class BrewGrowth : PersistTimer(brewCycleTime, "cooking:brewing", isSoft = true) {
|
||||
private val vatMap = HashMap<Int, Vat>()
|
||||
lateinit var player: Player
|
||||
|
||||
override fun onRegister(entity: Entity) {
|
||||
player = (entity as? Player)!!
|
||||
for (vat in vatMap.values.toList()){
|
||||
catchUp(vat.nextBrew)
|
||||
}
|
||||
}
|
||||
|
||||
override fun save(root: JSONObject, entity: Entity) {
|
||||
player = (entity as? Player)!!
|
||||
val vats = JSONArray()
|
||||
for ((key, vat) in vatMap.entries.toList()){
|
||||
val isBrewingStage = vat.stage in listOf(
|
||||
BrewingStage.MIXED,
|
||||
BrewingStage.BREWING1,
|
||||
BrewingStage.BREWING2,
|
||||
BrewingStage.DONE,
|
||||
BrewingStage.MATURE,
|
||||
BrewingStage.BAD
|
||||
)
|
||||
|
||||
if (isBrewingStage) {
|
||||
val v = JSONObject()
|
||||
v["brew-ordinal"] = key
|
||||
v["brew-stuff"] = vat.theStuff
|
||||
v["brewing-nextBrew"] = vat.nextBrew
|
||||
v["brewing-stage"] = vat.stage.ordinal
|
||||
v["brewing-item"] = vat.brewingItem?.ordinal
|
||||
vats.add(v)
|
||||
}
|
||||
}
|
||||
root["brewing"] = vats
|
||||
}
|
||||
|
||||
override fun parse(root: JSONObject, entity: Entity) {
|
||||
player = (entity as? Player)!!
|
||||
val data = root["brewing"] as JSONArray
|
||||
for (d in data){
|
||||
val v = d as JSONObject
|
||||
val vatOrdinal = v["brew-ordinal"].toString().toInt()
|
||||
val vatStuff = v["brew-stuff"].toString().toBoolean()
|
||||
val vatNextBrew = v["brewing-nextBrew"].toString().toLong()
|
||||
val vatStage = BrewingStage.values()[v["brewing-stage"].toString().toInt()]
|
||||
val vatItem = v["brewing-item"]?.toString()?.toIntOrNull()?.let {
|
||||
Brewable.values().getOrNull(it)
|
||||
}
|
||||
|
||||
if (vatMap[vatOrdinal] == null){
|
||||
val brewingVat = BrewingVat.values()[vatOrdinal]
|
||||
val vat = Vat(player, brewingVat, vatStuff, vatNextBrew, vatStage, vatItem)
|
||||
vatMap[vatOrdinal] = vat
|
||||
vat.updateVat()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getVat(brewingVat: BrewingVat, addVat: Boolean = true) : Vat {
|
||||
return vatMap[brewingVat.ordinal] ?: (Vat(player, brewingVat).also { if (addVat) vatMap[brewingVat.ordinal] = it })
|
||||
}
|
||||
|
||||
private fun catchUp(timeTillGrow: Long){
|
||||
if (timeTillGrow < System.currentTimeMillis()){
|
||||
val seconds = (System.currentTimeMillis() - timeTillGrow)/1000
|
||||
if (seconds > Int.MAX_VALUE){
|
||||
execute(1024)
|
||||
}
|
||||
else{
|
||||
val cyclesToGrow = secondsToTicks(seconds.toInt()) / brewCycleTime
|
||||
execute(cyclesToGrow)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun run(entity: Entity): Boolean {
|
||||
player = (entity as? Player)!!
|
||||
return execute(0)
|
||||
}
|
||||
|
||||
private fun execute(count: Int) : Boolean {
|
||||
for (vat in vatMap.entries.toList()){
|
||||
if (vat.value.canBrew())
|
||||
for (i in 0..count){
|
||||
val resp = vat.value.brew()
|
||||
if (!resp){
|
||||
break
|
||||
}
|
||||
}
|
||||
else {
|
||||
vatMap.entries.removeIf { it.value.isVatEmpty() && it.value.isBarrelEmpty()}
|
||||
}
|
||||
}
|
||||
return vatMap.isNotEmpty()
|
||||
}
|
||||
|
||||
fun getVats(): MutableCollection<Vat>{
|
||||
return vatMap.values
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package content.global.skill.cooking.fermenting
|
||||
|
||||
import org.rs09.consts.Items
|
||||
|
||||
|
||||
enum class Brewable (val displayName: String, val itemID: Int, val level: Int, val product: IntArray, val levelXP: Double, val vatVarBitOffset: Int,
|
||||
val barrelVarBitOffset: Int, val ingredientAmount: Int = 4){
|
||||
DWARVEN_STOUT("Dwarven Stout", Items.HAMMERSTONE_HOPS_5994, 19, intArrayOf(Items.DWARVEN_STOUT_1913, Items.DWARVEN_STOUT4_5777, Items.DWARVEN_STOUTM_5747, Items.DWARVEN_STOUTM4_5857), 215.0, 4, 8),
|
||||
ASGARNIAN_ALE("Asgarnian Ale", Items.ASGARNIAN_HOPS_5996, 26, intArrayOf(Items.ASGARNIAN_ALE_1905, Items.ASGARNIAN_ALE4_5785, Items.ASGARNIAN_ALEM_5739, Items.ASGARNIAN_ALEM4_5865), 248.0, 10, 16),
|
||||
GREENMANS_ALE("Greenman's Ale", Items.CLEAN_HARRALANDER_255, 29, intArrayOf(Items.GREENMANS_ALE_1909, Items.GREENMANS_ALE4_5793, Items.GREENMANS_ALEM_5743, Items.GREENMANS_ALEM4_5873), 281.0, 16, 24),
|
||||
WIZARD_BOMB("Wizard's Mind Bomb", Items.YANILLIAN_HOPS_5998, 34, intArrayOf(Items.WIZARDS_MIND_BOMB_1907, Items.MIND_BOMB4_5801, Items.MATURE_WMB_5741, Items.MIND_BOMBM4_5881), 341.0, 22, 32),
|
||||
DRAGON_BITTER("Dragon Bitter", Items.KRANDORIAN_HOPS_6000, 39, intArrayOf(Items.DRAGON_BITTER_1911, Items.DRAGON_BITTER4_5809, Items.DRAGON_BITTERM_5745, Items.DRAGON_BITTERM4_5889), 347.0, 28, 40),
|
||||
MOONLIGHT_MEAD("Moonlight Mead", Items.MUSHROOM_6004, 44, intArrayOf(Items.MOONLIGHT_MEAD_2955, Items.MOONLIGHT_MEAD4_5817, Items.MOONLIGHT_MEADM_5749, Items.MLIGHT_MEADM4_5897), 380.0, 34, 48),
|
||||
AXEMANS_FOLLY("Axeman's Folly", Items.OAK_ROOTS_6043, 49, intArrayOf(Items.AXEMANS_FOLLY_5751, Items.AXEMANS_FOLLY4_5825, Items.AXEMANS_FOLLYM_5753, Items.AXEMANS_FOLLYM4_5905), 413.0, 40, 56, 1),
|
||||
CHEFS_DELIGHT("Chef's Delight", Items.CHOCOLATE_DUST_1975, 54, intArrayOf(Items.CHEFS_DELIGHT_5755, Items.CHEFS_DELIGHT4_5833, Items.CHEFS_DELIGHTM_5757, Items.CHEFS_DELIGHTM4_5913), 446.0, 46, 64),
|
||||
SLAYERS_RESPITE("Slayer's Respite", Items.WILDBLOOD_HOPS_6002, 59, intArrayOf(Items.SLAYERS_RESPITE_5759, Items.SLAYERS_RESPITE4_5841, Items.SLAYERS_RESPITEM_5761, Items.SLAYER_RESPITEM4_5921), 479.0, 52, 72),
|
||||
CIDER("cider", Items.APPLE_MUSH_5992, 14, intArrayOf(Items.CIDER_5763, Items.CIDER4_5849, Items.MATURE_CIDER_5765, Items.CIDERM4_5929), 182.0, 58, 80),
|
||||
KELDA_STOUT("Kelda Stout", Items.KELDA_HOPS_6113, 22, intArrayOf(Items.KELDA_STOUT_6118), 0.0, 68, 3, 1);
|
||||
|
||||
|
||||
companion object {
|
||||
fun getIngredients() : IntArray{
|
||||
return values().map { it.itemID }.toIntArray()
|
||||
}
|
||||
|
||||
fun getBrewable(itemId: Int) : Brewable?{
|
||||
return values().find { it.itemID == itemId }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,232 @@
|
|||
package content.global.skill.cooking.fermenting
|
||||
|
||||
import core.api.*
|
||||
import core.game.interaction.InteractionListener
|
||||
import core.game.interaction.QueueStrength
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.item.Item
|
||||
import core.game.world.update.flag.context.Animation
|
||||
import org.rs09.consts.Items
|
||||
import org.rs09.consts.Scenery
|
||||
|
||||
|
||||
const val KELDAGRIM_LOC = 11679
|
||||
const val PORT_PHASMATYS_LOC = 14747
|
||||
|
||||
val varbits = mapOf(
|
||||
PORT_PHASMATYS_LOC to BrewingVat.PORT_PHAS,
|
||||
KELDAGRIM_LOC to BrewingVat.KELDAGRIM
|
||||
)
|
||||
|
||||
class BrewingListener : InteractionListener {
|
||||
|
||||
private val aleIngredientsId = Brewable.getIngredients()
|
||||
|
||||
private val vatsNeedingYeast = intArrayOf(
|
||||
Scenery.FERMENTING_VAT_7444, // Hammerstone hops
|
||||
Scenery.FERMENTING_VAT_7449, // Asgarnian hops
|
||||
Scenery.FERMENTING_VAT_7454, // Harralander
|
||||
Scenery.FERMENTING_VAT_7459, // Yanillian hops
|
||||
Scenery.FERMENTING_VAT_7464, // Krandorian hops
|
||||
Scenery.FERMENTING_VAT_7469, // Bittercap mushrooms
|
||||
Scenery.FERMENTING_VAT_7474, // Oak roots
|
||||
Scenery.FERMENTING_VAT_7479, // Chocolate dust
|
||||
Scenery.FERMENTING_VAT_7484, // Wildblood hops
|
||||
Scenery.FERMENTING_VAT_7489, // Apple mush
|
||||
Scenery.FERMENTING_VAT_8871 // Kelda hops
|
||||
)
|
||||
|
||||
// Const Lib is missing some of these
|
||||
private val drainBarrels = intArrayOf(
|
||||
Scenery.BARREL_7408,
|
||||
Scenery.BARREL_7409,
|
||||
Scenery.BARREL_7410,
|
||||
|
||||
)
|
||||
private val barrels = intArrayOf(
|
||||
Scenery.KELDA_STOUT_8870,
|
||||
Scenery.DWARVEN_STOUT_7411,
|
||||
Scenery.ASGARNIAN_ALE_7413,
|
||||
Scenery.GREENMANS_ALE_7415,
|
||||
Scenery.WIZARDS_MIND_BOMB_7417,
|
||||
Scenery.DRAGON_BITTER_7419,
|
||||
Scenery.MOONLIGHT_MEAD_7421,
|
||||
Scenery.AXEMAN_S_FOLLY_7423,
|
||||
Scenery.CHEF_S_DELIGHT_7425,
|
||||
Scenery.SLAYER_S_RESPITE_7427,
|
||||
Scenery.CIDER_7429,
|
||||
Scenery.MATURE_DWARVEN_STOUT_7412,
|
||||
Scenery.MATURE_ASGARNIAN_ALE_7414,
|
||||
Scenery.MATURE_GREENMANS_ALE_7416,
|
||||
Scenery.MATURE_WIZARDS_MIND_BOMB_7418,
|
||||
Scenery.MATURE_DRAGON_BITTER_7420,
|
||||
Scenery.MATURE_MOONLIGHT_MEAD_7422,
|
||||
Scenery.MATURE_AXEMAN_S_FOLLY_7424,
|
||||
Scenery.MATURE_CHEF_S_DELIGHT_7426,
|
||||
Scenery.MATURE_SLAYER_S_RESPITE_7428,
|
||||
Scenery.MATURE_CIDER_7430
|
||||
)
|
||||
|
||||
|
||||
override fun defineListeners() {
|
||||
|
||||
// Fill an empty vat with water - self-contained operation
|
||||
onUseWith(SCENERY, Items.BUCKET_OF_WATER_1929, Scenery.FERMENTING_VAT_7437) { player, _, _ ->
|
||||
if (removeItem(player, Item(Items.BUCKET_OF_WATER_1929, 2))) {
|
||||
queueScript(player, 0) {
|
||||
addItem(player, Items.BUCKET_1925, 2)
|
||||
|
||||
lock(player, Animation(2283).duration)
|
||||
animate(player, Animation(2283))
|
||||
|
||||
sendMessage(player, "You add some water to the vat.")
|
||||
|
||||
val vatVarbit = varbits.getValue(player.location.regionId).varbit
|
||||
setVarbit(player, vatVarbit, 1, true)
|
||||
return@queueScript (stopExecuting(player))
|
||||
}
|
||||
}
|
||||
else{
|
||||
sendDialogue(player, "You need 2 buckets of water.")
|
||||
}
|
||||
return@onUseWith true
|
||||
}
|
||||
|
||||
// Fill an empty vat with apple mush
|
||||
onUseWith(SCENERY, Items.APPLE_MUSH_5992, Scenery.FERMENTING_VAT_7437) { player, used, _ ->
|
||||
getVat(player).addIngredient(used as Item)
|
||||
return@onUseWith true
|
||||
}
|
||||
|
||||
// Add barley malt to a vat with water - self-contained operation
|
||||
onUseWith(SCENERY, Items.BARLEY_MALT_6008, Scenery.FERMENTING_VAT_7438) { player, _, _ ->
|
||||
if (inInventory(player, Items.BARLEY_MALT_6008, 2)) {
|
||||
queueScript(player, 0, QueueStrength.SOFT) { counter ->
|
||||
when (counter) {
|
||||
0 -> {
|
||||
if (!removeItem(player, Item(Items.BARLEY_MALT_6008, 1))) { return@queueScript stopExecuting(player) }
|
||||
|
||||
lock(player, Animation(2295).duration * 2 + 2)
|
||||
animate(player, Animation(2295))
|
||||
|
||||
sendMessage(player, "You add some barley malt to the vat.")
|
||||
|
||||
return@queueScript delayScript(player, Animation(2295).duration + 1)
|
||||
}
|
||||
1 -> {
|
||||
if (!removeItem(player, Item(Items.BARLEY_MALT_6008, 1))) { return@queueScript stopExecuting(player) }
|
||||
|
||||
stopWalk(player)
|
||||
animate(player, Animation(2295))
|
||||
|
||||
val vatVarbit = varbits.getValue(player.location.regionId).varbit
|
||||
setVarbit(player, vatVarbit, 2, true)
|
||||
|
||||
return@queueScript delayScript(player, Animation(2295).duration + 1)
|
||||
}
|
||||
2 -> {
|
||||
stopWalk(player)
|
||||
return@queueScript stopExecuting(player)
|
||||
}
|
||||
else -> return@queueScript stopExecuting(player)
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
sendDialogue(player, "You need 2 barley malt.")
|
||||
}
|
||||
return@onUseWith true
|
||||
}
|
||||
|
||||
// Add The Stuff to a vat with malt
|
||||
onUseWith(SCENERY, Items.THE_STUFF_8988, Scenery.FERMENTING_VAT_7441) { player, _, _ ->
|
||||
if (inInventory(player, Items.THE_STUFF_8988, 1)) {
|
||||
getVat(player).addTheStuff()
|
||||
}
|
||||
return@onUseWith true
|
||||
}
|
||||
|
||||
// Add ingredients to a vat with malt
|
||||
onUseWith(SCENERY, aleIngredientsId, Scenery.FERMENTING_VAT_7441) { player, used, _ ->
|
||||
if (used.id == Items.APPLE_MUSH_5992) {
|
||||
sendDialogue(player, "Apple mush needs to be added to an empty vat.")
|
||||
return@onUseWith false
|
||||
}
|
||||
// If you try to make Kelda Stout in Port Phasmatys the vat deletes itself forever
|
||||
if (used.id == Items.KELDA_HOPS_6113 && player.location.regionId != KELDAGRIM_LOC) {
|
||||
sendMessage(player, "Nothing interesting happens.")
|
||||
return@onUseWith false
|
||||
}
|
||||
// Branch off into Kelda Stout logic
|
||||
if (used.id == Items.KELDA_HOPS_6113 && player.location.regionId == KELDAGRIM_LOC) {
|
||||
KeldaBypasses.keldaAddHops(player)
|
||||
return@onUseWith true
|
||||
}
|
||||
getVat(player).addIngredient(used as Item)
|
||||
return@onUseWith true
|
||||
}
|
||||
|
||||
// Add yeast to a vat that's ready to brew
|
||||
onUseWith(SCENERY, Items.ALE_YEAST_5767, *vatsNeedingYeast) { player, _, with ->
|
||||
if (inInventory(player, Items.ALE_YEAST_5767, 1)) {
|
||||
// Branch off into Kelda Stout logic
|
||||
if (with.id == Scenery.FERMENTING_VAT_8871 &&
|
||||
player.location.regionId == KELDAGRIM_LOC &&
|
||||
getVarbit(player, 736) == 68) { // 68 = Kelda MIXED state
|
||||
KeldaBypasses.keldaAddYeast(player)
|
||||
return@onUseWith true
|
||||
}
|
||||
getVat(player).addYeast()
|
||||
}
|
||||
return@onUseWith true
|
||||
}
|
||||
|
||||
// Turn the valve to empty a vat into a barrel
|
||||
on(intArrayOf(Scenery.VALVE_7442, Scenery.VALVE_7443), SCENERY, "turn") { player, _ ->
|
||||
// Branch off into Kelda Stout logic
|
||||
when {
|
||||
(player.location.regionId == KELDAGRIM_LOC && KeldaBypasses.keldaIsBrewing(player)) ->
|
||||
sendMessage(player, "The contents of the vat haven't finished fermenting yet.")
|
||||
(player.location.regionId == KELDAGRIM_LOC && KeldaBypasses.keldaIsComplete(player)) ->
|
||||
KeldaBypasses.keldaTurnValve(player)
|
||||
else -> getVat(player).turnValve()
|
||||
}
|
||||
return@on true
|
||||
}
|
||||
|
||||
// Drain a barrel of bad ale
|
||||
on(drainBarrels, SCENERY, "Drain") { player, _ ->
|
||||
getVat(player).drainBarrel()
|
||||
return@on true
|
||||
}
|
||||
|
||||
// Level a barrel (clicking on it)
|
||||
on(barrels, SCENERY, "Level") { player, _ ->
|
||||
queueScript(player, 1) {
|
||||
val goAgain : Boolean
|
||||
if (inInventory(player, Items.BEER_GLASS_1919)) {
|
||||
goAgain = getVat(player).levelBarrel(Items.BEER_GLASS_1919)
|
||||
}
|
||||
else if (inInventory(player, Items.CALQUAT_KEG_5769)) {
|
||||
goAgain = getVat(player).levelBarrel(Items.CALQUAT_KEG_5769)
|
||||
}
|
||||
else{
|
||||
goAgain = false
|
||||
sendDialogue(player, "You need a container to level the barrel.")
|
||||
}
|
||||
return@queueScript if(goAgain) delayScript(player, 1) else stopExecuting(player)
|
||||
}
|
||||
return@on true
|
||||
}
|
||||
|
||||
// Level a barrel (using a container on it)
|
||||
onUseWith(SCENERY, intArrayOf(Items.BEER_GLASS_1919, Items.CALQUAT_KEG_5769), *barrels) { player, used, _ ->
|
||||
getVat(player).levelBarrel(used.id)
|
||||
return@onUseWith true
|
||||
}
|
||||
}
|
||||
|
||||
private fun getVat(player: Player) : Vat {
|
||||
return varbits.getValue(player.location.regionId).getVat(player)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,217 @@
|
|||
package content.global.skill.cooking.fermenting
|
||||
|
||||
import core.api.*
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.item.Item
|
||||
import org.rs09.consts.Items
|
||||
|
||||
object CalquatDecant {
|
||||
|
||||
// Consumables.java hurts my eyes so I did this instead
|
||||
data class CalquatKegs (
|
||||
val emptyKeg: Int = Items.CALQUAT_KEG_5769,
|
||||
val fourDose: Int, val threeDose: Int = fourDose - 2, val twoDose: Int = threeDose - 2, val oneDose: Int = twoDose - 2, val glass: Int,
|
||||
val fourMature: Int, val threeMature: Int = fourMature - 2, val twoMature: Int = threeMature - 2, val oneMature: Int = twoMature - 2, val matureGlass: Int
|
||||
)
|
||||
|
||||
val calquatDrinks =
|
||||
Brewable.values()
|
||||
.filter { it.product.size == 4 }
|
||||
.associateWith { CalquatKegs (
|
||||
fourDose = it.product[1],
|
||||
glass = it.product[0],
|
||||
fourMature = it.product[3],
|
||||
matureGlass = it.product[2]
|
||||
)
|
||||
}
|
||||
|
||||
// Array of all kegs with nonzero contents
|
||||
val allKegIds: IntArray by lazy {
|
||||
calquatDrinks.values.flatMap { keg ->
|
||||
listOf(
|
||||
keg.fourDose, keg.threeDose, keg.twoDose, keg.oneDose,
|
||||
keg.fourMature, keg.threeMature, keg.twoMature, keg.oneMature
|
||||
)
|
||||
}.distinct().toIntArray()
|
||||
}
|
||||
|
||||
// Reverse lookup map
|
||||
private val kegLookupMap: Map<Int, Pair<Brewable, CalquatKegs>> by lazy {
|
||||
calquatDrinks.entries.flatMap { (brewable, kegs) ->
|
||||
listOf(
|
||||
kegs.fourDose, kegs.threeDose, kegs.twoDose, kegs.oneDose,
|
||||
kegs.fourMature, kegs.threeMature, kegs.twoMature, kegs.oneMature
|
||||
).map { itemId -> itemId to (brewable to kegs) }
|
||||
}.toMap()
|
||||
}
|
||||
|
||||
// Check what a keg is so it can be related to other kegs
|
||||
fun getKeg(itemId: Int): Pair<Brewable, CalquatKegs>? = kegLookupMap[itemId]
|
||||
|
||||
// Check if an item is a keg
|
||||
fun isKeg(itemId: Int): Boolean = kegLookupMap.containsKey(itemId)
|
||||
|
||||
// Check how full a keg is
|
||||
fun getDoseByKeg(itemId: Int, kegs: CalquatKegs): Int {
|
||||
return when (itemId) {
|
||||
kegs.fourDose, kegs.fourMature -> 4
|
||||
kegs.threeDose, kegs.threeMature -> 3
|
||||
kegs.twoDose, kegs.twoMature -> 2
|
||||
kegs.oneDose, kegs.oneMature -> 1
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
|
||||
// Check if a keg contains matured ale
|
||||
fun isMature(itemId: Int, kegs: CalquatKegs): Boolean {
|
||||
return itemId == kegs.fourMature || itemId == kegs.threeMature ||
|
||||
itemId == kegs.twoMature || itemId == kegs.oneMature
|
||||
}
|
||||
|
||||
// Identifies a keg's category by its contents
|
||||
fun getKegByDose(kegs: CalquatKegs, dose: Int, mature: Boolean): Int {
|
||||
return if (!mature) {
|
||||
when (dose) {
|
||||
4 -> kegs.fourDose
|
||||
3 -> kegs.threeDose
|
||||
2 -> kegs.twoDose
|
||||
1 -> kegs.oneDose
|
||||
else -> kegs.emptyKeg
|
||||
}
|
||||
} else {
|
||||
when (dose) {
|
||||
4 -> kegs.fourMature
|
||||
3 -> kegs.threeMature
|
||||
2 -> kegs.twoMature
|
||||
1 -> kegs.oneMature
|
||||
else -> kegs.emptyKeg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Decanting function (NPC) - should work the same as potions
|
||||
fun decantCalquat(container: core.game.container.Container): Pair<List<Item>, List<Item>> {
|
||||
val doseCount = HashMap<Pair<Brewable, Boolean>, Int>() // (Brewable, isMature), Total Doses
|
||||
val toRemove = ArrayList<Item>()
|
||||
val toAdd = ArrayList<Item>()
|
||||
|
||||
// Count up all doses grouped by keg type and maturity
|
||||
for (item in container.toArray()) {
|
||||
if (item == null) continue
|
||||
val kegInfo = getKeg(item.id) ?: continue
|
||||
val (brewable, kegs) = kegInfo
|
||||
val dose = getDoseByKeg(item.id, kegs)
|
||||
if (dose == 0) continue
|
||||
val mature = isMature(item.id, kegs)
|
||||
val key = brewable to mature
|
||||
doseCount[key] = (doseCount[key] ?: 0) + dose
|
||||
toRemove.add(item)
|
||||
}
|
||||
|
||||
// Convert doses back into kegs
|
||||
for ((key, totalDoses) in doseCount) {
|
||||
val (brewable, mature) = key
|
||||
val kegs = calquatDrinks[brewable] ?: continue
|
||||
|
||||
val fullKegs = totalDoses / 4 // Number of 4-dose kegs
|
||||
val remainderDose = totalDoses % 4 // Leftover doses
|
||||
|
||||
if (fullKegs > 0)
|
||||
toAdd.add(Item(getKegByDose(kegs, 4, mature), fullKegs))
|
||||
if (remainderDose > 0)
|
||||
toAdd.add(Item(getKegByDose(kegs, remainderDose, mature)))
|
||||
}
|
||||
|
||||
// Add empty kegs for removed containers
|
||||
val emptyKegs = toRemove.size - toAdd.sumOf { it.amount }
|
||||
if (emptyKegs > 0) {
|
||||
val firstKegs = calquatDrinks.values.firstOrNull()
|
||||
if (firstKegs != null)
|
||||
toAdd.add(Item(firstKegs.emptyKeg, emptyKegs))
|
||||
}
|
||||
|
||||
return Pair(toRemove, toAdd)
|
||||
}
|
||||
|
||||
// Decanting function (manual) - should work the same as potions
|
||||
fun combineKegs(player: Player, used: Item, with: Item): Boolean {
|
||||
// Identify both kegs
|
||||
val (usedBrewable, kegs) = getKeg(used.id) ?: return false
|
||||
val (withBrewable, _) = getKeg(with.id) ?: return false
|
||||
|
||||
// Verify the same drink is in both kegs
|
||||
if (usedBrewable != withBrewable) return false
|
||||
|
||||
val usedMature = isMature(used.id, kegs)
|
||||
val withMature = isMature(with.id, kegs)
|
||||
|
||||
// Verify the same maturity status is in both kegs
|
||||
if (usedMature != withMature) return false
|
||||
|
||||
// Get doses
|
||||
val usedDose = getDoseByKeg(used.id, kegs)
|
||||
val withDose = getDoseByKeg(with.id, kegs)
|
||||
|
||||
// Disallow combining full or empty kegs
|
||||
if (usedDose == 4 || withDose == 4 || usedDose == 0 || withDose == 0) {
|
||||
return false
|
||||
}
|
||||
|
||||
val totalDosage = usedDose + withDose
|
||||
val fullDoses = totalDosage / 4
|
||||
val leftoverDose = totalDosage % 4
|
||||
|
||||
// Replace the targeted keg with a (4) dose keg
|
||||
if (fullDoses != 0) {
|
||||
replaceSlot(player, with.slot, Item(getKegByDose(kegs, 4, usedMature)), with, Container.INVENTORY)
|
||||
}
|
||||
|
||||
// Replace the targeted keg with the updated dosage amount
|
||||
if (leftoverDose != 0 && fullDoses == 0) {
|
||||
replaceSlot(player, with.slot, Item(getKegByDose(kegs, leftoverDose, usedMature)), with, Container.INVENTORY)
|
||||
|
||||
// Replace the used with keg with the updated dosage amount
|
||||
} else if (leftoverDose != 0) {
|
||||
replaceSlot(player, used.slot, Item(getKegByDose(kegs, leftoverDose, usedMature)), used, Container.INVENTORY)
|
||||
}
|
||||
|
||||
// Replace the used with keg with an empty keg
|
||||
if (leftoverDose == 0 || fullDoses == 0) {
|
||||
replaceSlot(player, used.slot, Item(kegs.emptyKeg), used, Container.INVENTORY)
|
||||
}
|
||||
|
||||
// Send message/Play sound
|
||||
val amountString = when {
|
||||
totalDosage >= 4 -> "four"
|
||||
totalDosage == 3 -> "three"
|
||||
else -> "two"
|
||||
}
|
||||
|
||||
sendMessage(player, "You have combined the kegs into $amountString pints.")
|
||||
playAudio(player, 2401)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Decant keg into beer glass
|
||||
fun pourIntoGlass(player: Player, glass: Item, keg: Item): Boolean {
|
||||
// Find keg info
|
||||
val kegInfo = getKeg(keg.id) ?: return false
|
||||
val (_, kegs) = kegInfo
|
||||
val currentDose = getDoseByKeg(keg.id, kegs)
|
||||
val mature = isMature(keg.id, kegs)
|
||||
if (currentDose == 0) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Fill the glass
|
||||
val glassItem = if (mature) kegs.matureGlass else kegs.glass
|
||||
replaceSlot(player, glass.slot, Item(glassItem), glass, Container.INVENTORY)
|
||||
|
||||
// Drain the keg
|
||||
val newDose = currentDose - 1
|
||||
replaceSlot(player, keg.slot, Item(getKegByDose(kegs, newDose, mature)), keg, Container.INVENTORY)
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
package content.global.skill.cooking.fermenting
|
||||
|
||||
import core.api.getVarbit
|
||||
import core.api.sendMessage
|
||||
import core.game.node.entity.Entity
|
||||
import core.api.*
|
||||
import core.game.interaction.QueueStrength
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.item.Item
|
||||
import core.game.world.update.flag.context.Animation
|
||||
import org.rs09.consts.Items
|
||||
import core.game.system.timer.PersistTimer
|
||||
import core.game.system.timer.RSTimer
|
||||
|
||||
/**
|
||||
* Independent brewing timer and functions exclusively for Kelda Stout
|
||||
* Varbit progression: 68 (mixed) -> 69 (brewing1) -> 70 (brewing2) -> 71 (done)
|
||||
*/
|
||||
|
||||
class KeldaStoutGrowth : PersistTimer( 5 /*minutes*/ * 100 /*ticks per minute*/, "cooking:brewing-kelda", isSoft = true) {
|
||||
lateinit var player: Player
|
||||
|
||||
override fun run(entity: Entity): Boolean {
|
||||
player = entity as Player
|
||||
when (val currentVarbit = getVarbit(player, 736)) {
|
||||
69 -> {
|
||||
setVarbit(player, 736, currentVarbit + 1)
|
||||
return true
|
||||
}
|
||||
70 -> {
|
||||
setVarbit(player, 736, currentVarbit + 1)
|
||||
sendMessage(player, "Perhaps I should have a look and see if my Kelda Stout has brewed...")
|
||||
return false
|
||||
}
|
||||
else -> {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getTimer(vararg args: Any): RSTimer {
|
||||
return KeldaStoutGrowth()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
object KeldaBypasses {
|
||||
|
||||
fun keldaAddHops(player: Player) {
|
||||
queueScript(player, 0) {
|
||||
stopWalk(player)
|
||||
if (!removeItem(player, Item(Items.KELDA_HOPS_6113, 1))) { return@queueScript stopExecuting(player) }
|
||||
sendMessage(player, "You add some Kelda hops to the vat.")
|
||||
lock(player, Animation(2295).duration + 1)
|
||||
animate(player, Animation(2295))
|
||||
setVarbit(player, 736, getVarbit(player, 736) + 66)
|
||||
return@queueScript stopExecuting(player)
|
||||
}
|
||||
}
|
||||
|
||||
fun keldaAddYeast(player: Player) {
|
||||
//addYeast() override
|
||||
queueScript(player, 0) {
|
||||
|
||||
if (!removeItem(player, Item(Items.ALE_YEAST_5767, 1))) { return@queueScript stopExecuting(player) }
|
||||
addItem(player, Items.EMPTY_POT_1931)
|
||||
|
||||
lock(player, Animation(2283).duration)
|
||||
animate(player, Animation(2295))
|
||||
|
||||
sendMessage(player, "You add a pot of ale yeast to the vat.")
|
||||
sendMessage(player, "The contents of the vat have begun to ferment.")
|
||||
|
||||
setVarbit(player, 736, getVarbit(player, 736) + 1)
|
||||
registerTimer(player, KeldaStoutGrowth())
|
||||
return@queueScript true
|
||||
}
|
||||
}
|
||||
|
||||
fun keldaTurnValve(player: Player) {
|
||||
queueScript(player, 0, QueueStrength.SOFT) {
|
||||
|
||||
lock(player, Animation(780).duration)
|
||||
animate(player, Animation(780))
|
||||
|
||||
sendMessage(player, "You turn the valve.")
|
||||
|
||||
delayScript(player, 2)
|
||||
|
||||
// Fill the barrel, then empty the vat
|
||||
setVarbit(player, 738, 3, true)
|
||||
setVarbit(player, 736, 0, true)
|
||||
|
||||
sendMessage(player, "The barrel now contains 1 pint of Kelda Stout.")
|
||||
return@queueScript stopExecuting(player)
|
||||
}
|
||||
}
|
||||
|
||||
fun keldaIsBrewing(player: Player): Boolean {
|
||||
val vatVarbit = getVarbit(player, 736)
|
||||
return vatVarbit in 69..70
|
||||
}
|
||||
|
||||
fun keldaIsComplete(player: Player): Boolean {
|
||||
val vatVarbit = getVarbit(player, 736)
|
||||
return vatVarbit == 71
|
||||
}
|
||||
}
|
||||
366
Server/src/main/content/global/skill/cooking/fermenting/Vat.kt
Normal file
366
Server/src/main/content/global/skill/cooking/fermenting/Vat.kt
Normal file
|
|
@ -0,0 +1,366 @@
|
|||
package content.global.skill.cooking.fermenting
|
||||
|
||||
import core.api.*
|
||||
import core.game.interaction.QueueStrength
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.skill.Skills
|
||||
import core.game.node.item.Item
|
||||
import core.game.world.update.flag.context.Animation
|
||||
import core.tools.RandomFunction
|
||||
import org.rs09.consts.Items
|
||||
|
||||
|
||||
class Vat (var player: Player, private val brewingVat : BrewingVat, var theStuff: Boolean,
|
||||
var nextBrew: Long, var stage: BrewingStage,
|
||||
var brewingItem : Brewable?) {
|
||||
|
||||
private var barrelItem: Brewable? = null
|
||||
|
||||
constructor(player: Player, brewingVat: BrewingVat) :
|
||||
this(player, brewingVat, false, 0, BrewingStage.EMPTY, null)
|
||||
|
||||
fun addTheStuff() {
|
||||
if (!theStuff && removeItem(player, Item(Items.THE_STUFF_8988, 1))) {
|
||||
theStuff = true
|
||||
|
||||
lock(player, Animation(2283).duration)
|
||||
animate(player, Animation(2283))
|
||||
|
||||
sendMessage(player, "You add The Stuff to the mixture in the vat.")
|
||||
|
||||
} else { sendMessage(player, "Nothing interesting happens.") }
|
||||
}
|
||||
|
||||
fun addIngredient(item: Item): Boolean {
|
||||
val ingredient = Brewable.getBrewable(item.id) ?: return false
|
||||
if (getDynLevel(player, Skills.COOKING) < ingredient.level) {
|
||||
sendDialogue(player, "You need a Cooking level of at least ${ingredient.level} in order to brew ${ingredient.displayName}.")
|
||||
return false
|
||||
}
|
||||
if (!inInventory(player, item.id, ingredient.ingredientAmount)) {
|
||||
val ingredientWord = if (ingredient.itemID == Items.MUSHROOM_6004) item.name+"s" else item.name
|
||||
sendDialogue(player, "You need 4 $ingredientWord.")
|
||||
return false
|
||||
}
|
||||
queueScript(player, 0, QueueStrength.SOFT) { counter ->
|
||||
when (counter) {
|
||||
0 -> {
|
||||
if (!removeItem(player, Item(item.id, 1))) { return@queueScript stopExecuting(player) }
|
||||
if (ingredient.itemID == Items.APPLE_MUSH_5992) {
|
||||
addItem(player, Items.BUCKET_1925)
|
||||
}
|
||||
|
||||
stopWalk(player)
|
||||
animate(player, Animation(2295))
|
||||
|
||||
val ingredientWord = if (item.id == Items.MUSHROOM_6004) item.name+"s" else item.name
|
||||
sendMessage(player, "You add some $ingredientWord to the vat.")
|
||||
|
||||
if (ingredient.ingredientAmount == 1) {
|
||||
lock(player, Animation(2295).duration)
|
||||
|
||||
brewingItem = ingredient
|
||||
stage = BrewingStage.MIXED
|
||||
updateVat()
|
||||
|
||||
return@queueScript stopExecuting(player)
|
||||
}
|
||||
|
||||
lock(player, Animation(2295).duration * 4 + 3)
|
||||
return@queueScript delayScript(player, Animation(2295).duration + 1)
|
||||
}
|
||||
1, 2 -> {
|
||||
if (!removeItem(player, Item(item.id, 1))) { return@queueScript stopExecuting(player) }
|
||||
if (ingredient.itemID == Items.APPLE_MUSH_5992) {
|
||||
addItem(player, Items.BUCKET_1925)
|
||||
}
|
||||
|
||||
stopWalk(player)
|
||||
animate(player, Animation(2295))
|
||||
|
||||
return@queueScript delayScript(player, Animation(2295).duration + 1)
|
||||
}
|
||||
3 -> {
|
||||
if (!removeItem(player, Item(item.id, 1))) { return@queueScript stopExecuting(player) }
|
||||
if (ingredient.itemID == Items.APPLE_MUSH_5992) {
|
||||
addItem(player, Items.BUCKET_1925)
|
||||
}
|
||||
|
||||
stopWalk(player)
|
||||
animate(player, Animation(2295))
|
||||
|
||||
brewingItem = ingredient
|
||||
stage = BrewingStage.MIXED
|
||||
updateVat()
|
||||
|
||||
return@queueScript delayScript(player, Animation(2295).duration)
|
||||
}
|
||||
4 -> {
|
||||
stopWalk(player)
|
||||
return@queueScript stopExecuting(player)
|
||||
}
|
||||
else -> return@queueScript stopExecuting(player)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun addYeast() {
|
||||
if (removeItem(player, Item(Items.ALE_YEAST_5767, 1))) {
|
||||
addItem(player, Items.EMPTY_POT_1931)
|
||||
|
||||
lock(player, Animation(2283).duration)
|
||||
animate(player, Animation(2295))
|
||||
|
||||
sendMessage(player, "You add a pot of ale yeast to the vat.")
|
||||
sendMessage(player, "The contents of the vat have begun to ferment.")
|
||||
|
||||
stage = BrewingStage.BREWING1
|
||||
nextBrew = System.currentTimeMillis() + (brewCycleTime * 600) // ticks to ms
|
||||
updateVat()
|
||||
} else {
|
||||
sendMessage(player, "Nothing interesting happens.")
|
||||
}
|
||||
}
|
||||
|
||||
fun brew(forceStep: Boolean = false, forceGood: Boolean = false, forceMature: Boolean = false, forceBad: Boolean = false) : Boolean {
|
||||
val resp = internalBrew(forceStep, forceGood, forceMature, forceBad)
|
||||
updateVat()
|
||||
return resp
|
||||
}
|
||||
|
||||
fun canBrew() : Boolean {
|
||||
return listOf(BrewingStage.BREWING1, BrewingStage.BREWING2).any { it == stage }
|
||||
}
|
||||
|
||||
/** The meat of the brewing mechanic lives in the following internalBrew function
|
||||
* No one has clearly documented how this should work
|
||||
* Period sources are vague, unaccountable, and/or vary wildly in their claims
|
||||
* https://x.com/JagexAsh/status/994867369460813824
|
||||
* Ash states that it was challenging to follow when he was trying to do it in OSRS
|
||||
*
|
||||
* If a good source is uncovered, this section can easily be configured to match it
|
||||
*
|
||||
* Current config results in the following behavior:
|
||||
* Cooking level does not play a factor
|
||||
* Chance to advance a step (or go bad) - 20%
|
||||
* Chance to go bad when advancing - 25%
|
||||
* Chance to mature (w/o The Stuff) - 05%
|
||||
* Chance to mature (w/ The Stuff) - 50%
|
||||
* Time per cycle (in BrewGrowth.kt) - 6 hours, or 36000 ticks
|
||||
*/
|
||||
|
||||
private fun internalBrew(forceStep: Boolean, forceGood: Boolean, forceMature: Boolean, forceBad: Boolean):Boolean {
|
||||
nextBrew = System.currentTimeMillis() + (brewCycleTime * 600) // Ticks to ms
|
||||
if (listOf(BrewingStage.BREWING1, BrewingStage.BREWING2).all{ it != stage}) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Step advancement check
|
||||
if (RandomFunction.random(5) == 0 || forceStep || forceGood || forceMature || forceBad) {
|
||||
if ((RandomFunction.random(4) == 0 || forceBad) && !forceGood && !forceMature) {
|
||||
stage = BrewingStage.BAD
|
||||
return false
|
||||
}
|
||||
stage = if (stage == BrewingStage.BREWING1) BrewingStage.BREWING2 else BrewingStage.DONE
|
||||
}
|
||||
|
||||
// Maturity check
|
||||
if (stage == BrewingStage.DONE) {
|
||||
sendMessage(player, "Perhaps I should have a look and see if my ${brewingItem!!.displayName} has brewed...")
|
||||
val roll = if (theStuff) 2 else 20
|
||||
if ((RandomFunction.random(roll) == 0 || forceMature) && !forceGood) {
|
||||
stage = BrewingStage.MATURE
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun turnValve(){
|
||||
if (stage == BrewingStage.EMPTY) {
|
||||
queueScript(player, 1) {
|
||||
sendMessage(player, "Nothing interesting happens.")
|
||||
return@queueScript stopExecuting(player)
|
||||
}
|
||||
return
|
||||
}
|
||||
if (getVarbit(player,this.brewingVat.varbit + 2) > 0) {
|
||||
queueScript(player, 1) {
|
||||
sendMessage(player, "The barrel is already full.")
|
||||
return@queueScript stopExecuting(player)
|
||||
}
|
||||
return
|
||||
}
|
||||
if (stage == BrewingStage.BREWING1 || stage == BrewingStage.BREWING2) {
|
||||
queueScript(player,1) {
|
||||
sendMessage(player, "The contents of the vat haven't finished fermenting yet.")
|
||||
return@queueScript stopExecuting(player)
|
||||
}
|
||||
return
|
||||
}
|
||||
lock(player, Animation(780).duration)
|
||||
animate(player, Animation(780))
|
||||
|
||||
sendMessage(player, "You turn the valve.")
|
||||
|
||||
if (stage == BrewingStage.MATURE || stage == BrewingStage.DONE) {
|
||||
rewardXP(player, Skills.COOKING, brewingItem!!.levelXP)
|
||||
queueScript(player, 2, QueueStrength.SOFT) {
|
||||
sendMessage(player, "The barrel now contains 8 pints of ${brewingItem!!.displayName}.")
|
||||
fillBarrel()
|
||||
emptyVat()
|
||||
updateVat()
|
||||
return@queueScript stopExecuting(player)
|
||||
}
|
||||
} else {
|
||||
fillBarrel()
|
||||
emptyVat()
|
||||
updateVat()
|
||||
}
|
||||
}
|
||||
|
||||
private fun emptyVat() {
|
||||
brewingItem = null
|
||||
theStuff = false
|
||||
stage = BrewingStage.EMPTY
|
||||
updateVat()
|
||||
}
|
||||
|
||||
private fun fillBarrel() {
|
||||
var varbitValue = 0
|
||||
when (stage){
|
||||
BrewingStage.EMPTY -> Unit
|
||||
BrewingStage.WATER,
|
||||
BrewingStage.MALT,
|
||||
BrewingStage.MIXED,
|
||||
BrewingStage.BREWING1,
|
||||
BrewingStage.BREWING2 -> {
|
||||
varbitValue = 4
|
||||
}
|
||||
BrewingStage.DONE,
|
||||
BrewingStage.MATURE -> {
|
||||
barrelItem = brewingItem
|
||||
val barrelAmount = 8
|
||||
|
||||
varbitValue = barrelItem?.barrelVarBitOffset ?: 0
|
||||
|
||||
if (barrelItem != null){
|
||||
varbitValue += (barrelAmount - 1)
|
||||
if (stage == BrewingStage.MATURE) {
|
||||
varbitValue += 128
|
||||
}
|
||||
}
|
||||
}
|
||||
BrewingStage.BAD ->{
|
||||
varbitValue = if(brewingItem == Brewable.CIDER) 2 else 1
|
||||
}
|
||||
}
|
||||
setVarbit(player, this.brewingVat.varbit + 2, varbitValue, true)
|
||||
}
|
||||
|
||||
fun levelBarrel(container: Int): Boolean {
|
||||
var value = getVarbit(player, this.brewingVat.varbit + 2)
|
||||
if (value == 0) return false
|
||||
|
||||
// Check for mature bit (128) and strip it for calculations
|
||||
val isMature = value >= 128
|
||||
val baseValue = if (isMature) value - 128 else value
|
||||
var servingsLeft = if(baseValue == 3) 1 else (baseValue % 8) + 1
|
||||
|
||||
val brewable =
|
||||
if (baseValue == 3) Brewable.KELDA_STOUT
|
||||
else Brewable.values()[(baseValue/8) - 1]
|
||||
|
||||
val product = brewable.product
|
||||
|
||||
if (container == Items.BEER_GLASS_1919) {
|
||||
if(removeItem(player, container)) {
|
||||
animate(player, Animation(2285))
|
||||
value--
|
||||
servingsLeft--
|
||||
val productIndex = if (isMature) 2 else 0
|
||||
sendMessage(player, "You pour a glass of ${brewable.displayName}.")
|
||||
addItem(player, product[productIndex])
|
||||
}
|
||||
}
|
||||
else if (brewable == Brewable.KELDA_STOUT) {
|
||||
sendDialogue(player, "You must use a glass to level Kelda Stout.")
|
||||
return false
|
||||
}
|
||||
else if (container == Items.CALQUAT_KEG_5769) {
|
||||
if(removeItem(player, container)){
|
||||
animate(player, Animation(2284))
|
||||
val servingsToTake = minOf(servingsLeft, 4)
|
||||
value -= servingsToTake
|
||||
servingsLeft -= servingsToTake
|
||||
val filledKeg = CalquatDecant.calquatDrinks[brewable]!!
|
||||
addItem(player, CalquatDecant.getKegByDose(filledKeg, servingsToTake, isMature))
|
||||
}
|
||||
}
|
||||
if (servingsLeft == 0) {
|
||||
sendMessage(player, "The barrel is now empty.")
|
||||
value = 0
|
||||
}
|
||||
setVarbit(player, this.brewingVat.varbit + 2, value, true)
|
||||
return servingsLeft != 0
|
||||
}
|
||||
|
||||
fun drainBarrel() {
|
||||
sendMessage(player, "You drain the barrel.")
|
||||
setVarbit(player, this.brewingVat.varbit + 2, 0, true)
|
||||
|
||||
}
|
||||
|
||||
fun isVatEmpty(): Boolean {
|
||||
return stage == BrewingStage.EMPTY
|
||||
}
|
||||
|
||||
fun isBarrelEmpty(): Boolean {
|
||||
return getVarbit(player, (this.brewingVat.varbit + 2)) == 0
|
||||
}
|
||||
|
||||
private fun getVatDisplay(): Int {
|
||||
return when (stage){
|
||||
BrewingStage.EMPTY -> 0
|
||||
BrewingStage.WATER -> 1
|
||||
BrewingStage.MALT -> 2
|
||||
BrewingStage.MIXED -> brewingItem?.vatVarBitOffset ?: run { 0 }
|
||||
BrewingStage.BREWING1 -> (brewingItem?.vatVarBitOffset?.plus(1)) ?: run { 0 }
|
||||
BrewingStage.BREWING2 -> (brewingItem?.vatVarBitOffset?.plus(2)) ?: run { 0 }
|
||||
BrewingStage.DONE -> (brewingItem?.vatVarBitOffset?.plus(3)) ?: run { 0 }
|
||||
BrewingStage.MATURE -> (brewingItem?.vatVarBitOffset?.plus(4)) ?: run { 0 }
|
||||
BrewingStage.BAD -> if (brewingItem == Brewable.CIDER) 65 else 64
|
||||
}
|
||||
}
|
||||
|
||||
fun updateVat(){
|
||||
setVarbit(player, this.brewingVat.varbit, this.getVatDisplay(), true)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
enum class BrewingStage {
|
||||
EMPTY,
|
||||
WATER,
|
||||
MALT,
|
||||
MIXED,
|
||||
BREWING1,
|
||||
BREWING2,
|
||||
DONE,
|
||||
MATURE,
|
||||
BAD;
|
||||
}
|
||||
|
||||
|
||||
enum class BrewingVat(val varbit: Int) {
|
||||
KELDAGRIM(736),
|
||||
PORT_PHAS(737);
|
||||
|
||||
fun getVat(player: Player): Vat {
|
||||
val vat = getOrStartTimer<BrewGrowth>(player)
|
||||
return vat.getVat(this, true)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package content.global.skill.farming
|
||||
|
||||
import content.data.Quests
|
||||
import core.api.*
|
||||
import core.game.dialogue.DialogueFile
|
||||
import core.game.dialogue.FacialExpression
|
||||
|
|
@ -67,6 +68,8 @@ class FarmerPayOptionDialogue(val patch: Patch, val quickPay: Boolean = false):
|
|||
val amount = if (item?.amount == 1) "one" else item?.amount
|
||||
npc(FacialExpression.HAPPY, "I want $amount $protectionText, one monkey bar,", "and one ground tooth for that.")
|
||||
stage = 200
|
||||
} else if (patch.patch.type == PatchType.CALQUAT_TREE_PATCH && getQuestStage(player!!, Quests.JUNGLE_POTION) < 100) {
|
||||
npc("Sorry, I won't protect that.").also { stage = END_DIALOGUE } // Cannot confirm authenticity of this line just that there should be a rejection here
|
||||
} else if (quickPay && !(inInventory(player!!, item!!.id, item!!.amount) || inInventory(player!!, note(item!!).id, note(item!!).amount))) {
|
||||
val amount = if (item?.amount == 1) "one" else item?.amount
|
||||
npc(FacialExpression.HAPPY, "I want $amount $protectionText for that.")
|
||||
|
|
|
|||
|
|
@ -24,7 +24,8 @@ enum class Farmers(val id: Int, val patches: Array<FarmingPatch>) {
|
|||
TORRELL(2338, arrayOf(FarmingPatch.ARDOUGNE_BUSH)),
|
||||
FRIZZY(4560, arrayOf(FarmingPatch.PORT_SARIM_SPIRIT_TREE)),
|
||||
YULF(4561, arrayOf(FarmingPatch.ETCETERIA_SPIRIT_TREE)),
|
||||
PRAISTAN(4562, arrayOf(FarmingPatch.KARAMJA_SPIRIT_TREE))
|
||||
PRAISTAN(4562, arrayOf(FarmingPatch.KARAMJA_SPIRIT_TREE)),
|
||||
IMIAGO(8041, arrayOf(FarmingPatch.CALQUAT_TREE))
|
||||
;
|
||||
|
||||
companion object{
|
||||
|
|
|
|||
|
|
@ -67,7 +67,8 @@ enum class FarmingPatch(val varbit: Int, val type: PatchType) {
|
|||
DRAYNOR_BELLADONNA(748, PatchType.BELLADONNA_PATCH),
|
||||
CANIFIS_MUSHROOM(746, PatchType.MUSHROOM_PATCH),
|
||||
ALKHARID_CACTUS(744, PatchType.CACTUS_PATCH),
|
||||
EVIL_TURNIP(4291, PatchType.EVIL_TURNIP_PATCH);
|
||||
EVIL_TURNIP(4291, PatchType.EVIL_TURNIP_PATCH),
|
||||
CALQUAT_TREE(726, PatchType.CALQUAT_TREE_PATCH);
|
||||
|
||||
|
||||
companion object {
|
||||
|
|
|
|||
|
|
@ -60,6 +60,10 @@ class HealthChecker : OptionHandler() {
|
|||
patch.setCurrentState(patch.plantable!!.value + patch.plantable!!.stages + 3)
|
||||
sendMessage(player, "You examine the cactus for signs of disease and find that it is in perfect health.")
|
||||
}
|
||||
PatchType.CALQUAT_TREE_PATCH -> {
|
||||
patch.setCurrentState(patch.plantable!!.value + patch.plantable!!.stages + 6)
|
||||
sendMessage(player, "You examine the calquat tree for signs of disease and find that it is in perfect health.")
|
||||
}
|
||||
else -> log(this::class.java, Log.ERR, "Unreachable patch type from when(type) switch in HealthChecker.kt")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl
|
|||
var compost = CompostType.NONE
|
||||
var protectionPaid = false
|
||||
var cropLives = 3
|
||||
val checkablePatches = arrayOf(PatchType.TREE_PATCH, PatchType.BUSH_PATCH, PatchType.FRUIT_TREE_PATCH, PatchType.SPIRIT_TREE_PATCH, PatchType.CACTUS_PATCH)
|
||||
val checkablePatches = arrayOf(PatchType.TREE_PATCH, PatchType.BUSH_PATCH, PatchType.FRUIT_TREE_PATCH, PatchType.SPIRIT_TREE_PATCH, PatchType.CACTUS_PATCH, PatchType.CALQUAT_TREE_PATCH)
|
||||
|
||||
fun setNewHarvestAmount() {
|
||||
val compostMod = when(compost) {
|
||||
|
|
@ -164,6 +164,7 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl
|
|||
PatchType.CACTUS_PATCH -> setVarbit(player, patch.varbit, 31)
|
||||
PatchType.TREE_PATCH -> setVarbit(player, patch.varbit, plantable!!.value + plantable!!.stages)
|
||||
PatchType.SPIRIT_TREE_PATCH -> setVarbit(player, patch.varbit, plantable!!.value + plantable!!.stages + 24)
|
||||
PatchType.CALQUAT_TREE_PATCH -> setVarbit(player, patch.varbit, 34)
|
||||
else -> log(this::class.java, Log.WARN, "Invalid setting of isCheckHealth for patch type: " + patch.type.name + "at" + patch.name)
|
||||
}
|
||||
} else {
|
||||
|
|
@ -223,7 +224,13 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl
|
|||
if(isDead) setVisualState(getMushroomDeathValue())
|
||||
else if(isDiseased && !isDead) setVisualState(getMushroomDiseaseValue())
|
||||
}
|
||||
else -> {}
|
||||
PatchType.CALQUAT_TREE_PATCH -> {
|
||||
if(isDead) setVisualState(getCalquatDeathValue())
|
||||
else if(isDiseased && !isDead) setVisualState(getCalquatDiseaseValue())
|
||||
}
|
||||
else -> {
|
||||
log(this::class.java, Log.WARN, "Invalid patch type attempted to be displayed: " + patch.type.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -310,6 +317,14 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl
|
|||
return (plantable?.value ?: 0) + currentGrowthStage + 16
|
||||
}
|
||||
|
||||
private fun getCalquatDiseaseValue(): Int {
|
||||
return (plantable?.value ?: 0) + currentGrowthStage + 14
|
||||
}
|
||||
|
||||
private fun getCalquatDeathValue(): Int {
|
||||
return (plantable?.value ?: 0) + currentGrowthStage + 21
|
||||
}
|
||||
|
||||
private fun getHerbDiseaseValue(): Int {
|
||||
return if (plantable?.value ?: -1 <= 103) {
|
||||
128 + (((plantable?.ordinal ?: 0) - Plantable.GUAM_SEED.ordinal) * 3) + currentGrowthStage - 1
|
||||
|
|
@ -364,8 +379,12 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl
|
|||
isCheckHealth = true
|
||||
}
|
||||
|
||||
if((patch.type == PatchType.FRUIT_TREE_PATCH || patch.type == PatchType.BUSH_PATCH || patch.type == PatchType.CACTUS_PATCH) && plantable?.stages == currentGrowthStage){
|
||||
if((patch.type == PatchType.BUSH_PATCH && getFruitOrBerryCount() < 4) || (patch.type == PatchType.FRUIT_TREE_PATCH && getFruitOrBerryCount() < 6) || (patch.type == PatchType.CACTUS_PATCH && getFruitOrBerryCount() < 3)){
|
||||
if(arrayOf(PatchType.FRUIT_TREE_PATCH, PatchType.BUSH_PATCH, PatchType.CACTUS_PATCH, PatchType.CALQUAT_TREE_PATCH).any{ patch.type == it} && plantable?.stages == currentGrowthStage){
|
||||
if((patch.type == PatchType.BUSH_PATCH && getFruitOrBerryCount() < 4) ||
|
||||
(patch.type == PatchType.FRUIT_TREE_PATCH && getFruitOrBerryCount() < 6) ||
|
||||
(patch.type == PatchType.CACTUS_PATCH && getFruitOrBerryCount() < 3) ||
|
||||
(patch.type == PatchType.CALQUAT_TREE_PATCH && getFruitOrBerryCount() < 6)
|
||||
){
|
||||
setCurrentState(getCurrentState() + 1)
|
||||
}
|
||||
}
|
||||
|
|
@ -376,7 +395,7 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl
|
|||
}
|
||||
}
|
||||
|
||||
if(plantable?.stages ?: 0 > currentGrowthStage && !isGrown()){
|
||||
if((plantable?.stages ?: 0) > currentGrowthStage && !isGrown()){
|
||||
currentGrowthStage++
|
||||
setCurrentState(getCurrentState() + 1)
|
||||
isWatered = false
|
||||
|
|
@ -427,7 +446,7 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl
|
|||
|
||||
fun getStageGrowthMinutes() : Int {
|
||||
var minutes = patch.type.stageGrowthTime
|
||||
if(patch.type == PatchType.FRUIT_TREE_PATCH && isGrown()) {
|
||||
if(arrayOf(PatchType.FRUIT_TREE_PATCH, PatchType.CALQUAT_TREE_PATCH).any{ it == patch.type } && isGrown()) {
|
||||
// Fruit trees take 160 minutes per stage to grow, but
|
||||
// restocking their fruit should take 40 minutes per fruit
|
||||
minutes = 40
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ enum class PatchType(val stageGrowthTime: Int) {
|
|||
MUSHROOM_PATCH(30),
|
||||
BELLADONNA_PATCH(80),
|
||||
CACTUS_PATCH(60),
|
||||
EVIL_TURNIP_PATCH(5);
|
||||
EVIL_TURNIP_PATCH(5),
|
||||
CALQUAT_TREE_PATCH(160);
|
||||
|
||||
/**
|
||||
* Returns the display name of this PatchType.
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ enum class Plantable(val itemID: Int, val displayName: String, val value: Int, v
|
|||
MUSHROOM_SPORE(Items.MUSHROOM_SPORE_5282, "mushroom spore", 4, 6, 61.5, 57.7, 0.0, 53, PatchType.MUSHROOM_PATCH, Items.MUSHROOM_6004),
|
||||
CACTUS_SEED(Items.CACTUS_SEED_5280, "cactus seed", 8, 7, 66.5, 25.0, 374.0, 55, PatchType.CACTUS_PATCH, Items.CACTUS_SPINE_6016),
|
||||
EVIL_TURNIP_SEED(Items.EVIL_TURNIP_SEED_12148, "evil turnip seed", 4, 1, 41.0, 46.0, 0.0, 42, PatchType.EVIL_TURNIP_PATCH, Items.EVIL_TURNIP_12134),
|
||||
CALQUAT_SAPLING(Items.CALQUAT_SAPLING_5503, "calquat tree sapling", 4, 8, 130.5, 48.5, 12096.0, 72, PatchType.CALQUAT_TREE_PATCH, Items.CALQUAT_FRUIT_5980, Item(Items.POISON_IVY_BERRIES_6018, 8)),
|
||||
SPIRIT_SAPLING(Items.SPIRIT_SAPLING_5375, "spirit tree sapling", 8, 12, 199.5, 0.0, 19301.0, 83, PatchType.SPIRIT_TREE_PATCH, 0, Item(Items.MONKEY_NUTS_4012, 5), null, Item(Items.MONKEY_BAR_4014, 1), Item(Items.GROUND_TOOTH_9082, 1) )
|
||||
;
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ class SackBasketOptionHandler : OptionHandler() {
|
|||
appropriateProduce.amount = (max - specific)
|
||||
}
|
||||
|
||||
if(player.inventory.remove(item) && player.inventory.remove(appropriateProduce))
|
||||
if(player.inventory.remove(appropriateProduce) && player.inventory.remove(item))
|
||||
player.inventory.add(Item(container.containers[specific + appropriateProduce.amount]))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -57,19 +57,20 @@ class SeedlingListener : InteractionListener {
|
|||
|
||||
fun getSeedling(id: Int) : Int {
|
||||
return when (id) {
|
||||
Items.ACORN_5312 -> Items.OAK_SEEDLING_5358
|
||||
Items.WILLOW_SEED_5313 -> Items.WILLOW_SEEDLING_5359
|
||||
Items.MAPLE_SEED_5314 -> Items.MAPLE_SEEDLING_5360
|
||||
Items.YEW_SEED_5315 -> Items.YEW_SEEDLING_5361
|
||||
Items.MAGIC_SEED_5316 -> Items.MAGIC_SEEDLING_5362
|
||||
Items.APPLE_TREE_SEED_5283 -> Items.APPLE_SEEDLING_5480
|
||||
Items.BANANA_TREE_SEED_5284 -> Items.BANANA_SEEDLING_5481
|
||||
Items.ORANGE_TREE_SEED_5285 -> Items.ORANGE_SEEDLING_5482
|
||||
Items.CURRY_TREE_SEED_5286 -> Items.CURRY_SEEDLING_5483
|
||||
Items.PINEAPPLE_SEED_5287 -> Items.PINEAPPLE_SEEDLING_5484
|
||||
Items.PAPAYA_TREE_SEED_5288 -> Items.PAPAYA_SEEDLING_5485
|
||||
Items.PALM_TREE_SEED_5289 -> Items.PALM_SEEDLING_5486
|
||||
Items.SPIRIT_SEED_5317 -> Items.SPIRIT_SEEDLING_5363
|
||||
Items.ACORN_5312 -> Items.OAK_SEEDLING_5358
|
||||
Items.WILLOW_SEED_5313 -> Items.WILLOW_SEEDLING_5359
|
||||
Items.MAPLE_SEED_5314 -> Items.MAPLE_SEEDLING_5360
|
||||
Items.YEW_SEED_5315 -> Items.YEW_SEEDLING_5361
|
||||
Items.MAGIC_SEED_5316 -> Items.MAGIC_SEEDLING_5362
|
||||
Items.APPLE_TREE_SEED_5283 -> Items.APPLE_SEEDLING_5480
|
||||
Items.BANANA_TREE_SEED_5284 -> Items.BANANA_SEEDLING_5481
|
||||
Items.ORANGE_TREE_SEED_5285 -> Items.ORANGE_SEEDLING_5482
|
||||
Items.CURRY_TREE_SEED_5286 -> Items.CURRY_SEEDLING_5483
|
||||
Items.PINEAPPLE_SEED_5287 -> Items.PINEAPPLE_SEEDLING_5484
|
||||
Items.PAPAYA_TREE_SEED_5288 -> Items.PAPAYA_SEEDLING_5485
|
||||
Items.PALM_TREE_SEED_5289 -> Items.PALM_SEEDLING_5486
|
||||
Items.SPIRIT_SEED_5317 -> Items.SPIRIT_SEEDLING_5363
|
||||
Items.CALQUAT_TREE_SEED_5290 -> Items.CALQUAT_SEEDLING_5487
|
||||
else -> -1
|
||||
}
|
||||
}
|
||||
|
|
@ -87,7 +88,8 @@ class SeedlingListener : InteractionListener {
|
|||
Items.PINEAPPLE_SEED_5287,
|
||||
Items.PAPAYA_TREE_SEED_5288,
|
||||
Items.PALM_TREE_SEED_5289,
|
||||
Items.SPIRIT_SEED_5317
|
||||
Items.SPIRIT_SEED_5317,
|
||||
Items.CALQUAT_TREE_SEED_5290
|
||||
)
|
||||
|
||||
val TREE_SEEDLINGS = intArrayOf(
|
||||
|
|
@ -103,7 +105,8 @@ class SeedlingListener : InteractionListener {
|
|||
Items.PINEAPPLE_SEEDLING_5484,
|
||||
Items.PAPAYA_SEEDLING_5485,
|
||||
Items.PALM_SEEDLING_5486,
|
||||
Items.SPIRIT_SEEDLING_5363
|
||||
Items.SPIRIT_SEEDLING_5363,
|
||||
Items.CALQUAT_SEEDLING_5487,
|
||||
)
|
||||
|
||||
private val WATERING_CANS = intArrayOf(Items.WATERING_CAN8_5340,Items.WATERING_CAN7_5339,Items.WATERING_CAN6_5338,Items.WATERING_CAN5_5337,Items.WATERING_CAN4_5336,Items.WATERING_CAN3_5335,Items.WATERING_CAN2_5334,Items.WATERING_CAN1_5333)
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ class UseWithPatchHandler : InteractionListener {
|
|||
onUseWith(IntType.SCENERY, allowedNodes.toIntArray(), *FarmingPatch.patchNodes.toIntArray()) { player, used, with ->
|
||||
val patch = FarmingPatch.forObject(with.asScenery()) ?: return@onUseWith true
|
||||
val usedItem = used.asItem()
|
||||
val trimmablePatches = arrayOf(PatchType.TREE_PATCH, PatchType.BUSH_PATCH, PatchType.FRUIT_TREE_PATCH, PatchType.SPIRIT_TREE_PATCH)
|
||||
val trimmablePatches = arrayOf(PatchType.TREE_PATCH, PatchType.BUSH_PATCH, PatchType.FRUIT_TREE_PATCH, PatchType.SPIRIT_TREE_PATCH, PatchType.CALQUAT_TREE_PATCH)
|
||||
|
||||
if (patch == FarmingPatch.TROLL_STRONGHOLD_HERB) {
|
||||
if (!hasRequirement(player, Quests.MY_ARMS_BIG_ADVENTURE))
|
||||
|
|
@ -261,7 +261,7 @@ class UseWithPatchHandler : InteractionListener {
|
|||
}*/
|
||||
|
||||
val requiredItem = when (patch.type) {
|
||||
PatchType.TREE_PATCH, PatchType.FRUIT_TREE_PATCH, PatchType.SPIRIT_TREE_PATCH -> Items.SPADE_952
|
||||
PatchType.TREE_PATCH, PatchType.FRUIT_TREE_PATCH, PatchType.SPIRIT_TREE_PATCH, PatchType.CALQUAT_TREE_PATCH -> Items.SPADE_952
|
||||
PatchType.FLOWER_PATCH -> if (plantable == Plantable.SCARECROW) null else Items.SEED_DIBBER_5343
|
||||
else -> Items.SEED_DIBBER_5343
|
||||
}
|
||||
|
|
@ -284,7 +284,8 @@ class UseWithPatchHandler : InteractionListener {
|
|||
}
|
||||
animate(player, anim)
|
||||
playAudio(player, sound)
|
||||
val delay = if (patch.type == PatchType.TREE_PATCH || patch.type == PatchType.FRUIT_TREE_PATCH || patch.type == PatchType.SPIRIT_TREE_PATCH || plantable == Plantable.SCARECROW) 3 else 0
|
||||
val delay = if (patch.type == PatchType.TREE_PATCH || patch.type == PatchType.FRUIT_TREE_PATCH || patch.type == PatchType.SPIRIT_TREE_PATCH ||
|
||||
patch.type == PatchType.CALQUAT_TREE_PATCH || plantable == Plantable.SCARECROW) 3 else 0
|
||||
return@queueScript delayScript(player,anim.duration + delay)
|
||||
}
|
||||
1 -> {
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ class FishingListener : InteractionListener{
|
|||
}
|
||||
return false
|
||||
}
|
||||
return node.isActive && node.location.withinDistance(player.location, 1)
|
||||
return node.isActive && node.location.withinMaxnormDistance(player.location, 1)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
import static core.api.ContentAPIKt.*;
|
||||
import static core.api.ContentAPIKt.sendMessage;
|
||||
|
||||
/**
|
||||
* Represents a familiar.
|
||||
|
|
@ -258,7 +259,10 @@ public abstract class Familiar extends NPC implements Plugin<Object> {
|
|||
if (victim == null) {
|
||||
victim = owner.getAttribute("combat-attacker");
|
||||
}
|
||||
if (combat.getVictim() != this && victim != null && !victim.isInvisible() && getProperties().isMultiZone() && owner.getProperties().isMultiZone() && isCombatFamiliar() && !isBurdenBeast() && !isPeacefulFamiliar()) {
|
||||
if (combat.getVictim() != this && victim != null && !victim.isInvisible()
|
||||
&& getProperties().isMultiZone() && owner.getProperties().isMultiZone()
|
||||
&& victim.getProperties().isMultiZone() && isCombatFamiliar()
|
||||
&& !isBurdenBeast() && !isPeacefulFamiliar()) { // Are you serious my brotha?
|
||||
getProperties().getCombatPulse().attack(victim);
|
||||
}
|
||||
}
|
||||
|
|
@ -271,58 +275,120 @@ public abstract class Familiar extends NPC implements Plugin<Object> {
|
|||
}
|
||||
handleFamiliarTick();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isAttackable(Entity entity, CombatStyle style, boolean message) {
|
||||
if (isInvalidTarget(entity, style, message)) return false;
|
||||
if (isAttackableBy(entity, style, message)) return false;
|
||||
return super.isAttackable(entity, style, message);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean continueAttack(Entity target, CombatStyle style, boolean message) {
|
||||
return !isInvalidTarget(target, style, message);
|
||||
if (getProperties().getCombatPulse().getVictim() == target) {
|
||||
return canAttackTarget(target, style, message);
|
||||
}
|
||||
if (target == owner) {
|
||||
if (message) {
|
||||
sendMessage(owner, "You can't just betray your own familiar like that!");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isInvalidTarget(Entity entity, CombatStyle style, boolean message) {
|
||||
if (entity == owner) {
|
||||
|
||||
/**
|
||||
* Checks if the familiar can attack the target (familiar as attacker).
|
||||
* Called from continueAttack() when familiar initiates combat.
|
||||
*
|
||||
* @param target The target to attack.
|
||||
* @param style The combat style.
|
||||
* @param message Whether to send messages.
|
||||
*
|
||||
* @return true if the familiar can attack the target.
|
||||
*/
|
||||
private boolean canAttackTarget(Entity target, CombatStyle style, boolean message) {
|
||||
if (target == owner) {
|
||||
if (message) {
|
||||
sendMessage(owner, "You can't just betray your own familiar like that!");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (target instanceof Player) {
|
||||
Player targetPlayer = (Player) target;
|
||||
if (!targetPlayer.getSkullManager().isWilderness()) {
|
||||
if (message) {
|
||||
sendMessage(owner, "You have to be in the wilderness to attack a player's familiar.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!owner.getSkullManager().isWilderness()) {
|
||||
if (message) {
|
||||
sendMessage(owner, "This familiar's owner is not in the wilderness.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!owner.isAttackable(target, style, false)) {
|
||||
return false;
|
||||
}
|
||||
if (!owner.getProperties().isMultiZone()) {
|
||||
if (message) {
|
||||
sendMessage(owner, "You have to be in a multicombat zone to attack another player with your familiar.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the entity can attack this familiar (familiar as target).
|
||||
* Called from isAttackable() when someone attacks the familiar.
|
||||
*
|
||||
* @param attacker The entity trying to attack the familiar.
|
||||
* @param style The combat style.
|
||||
* @param message Whether to send messages.
|
||||
*
|
||||
* @return true if the attacker cannot attack the familiar (invalid target).
|
||||
*/
|
||||
private boolean isAttackableBy(Entity attacker, CombatStyle style, boolean message) {
|
||||
if (attacker == owner) {
|
||||
if (message) {
|
||||
sendMessage(owner, "You can't just betray your own familiar like that!");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (entity instanceof Player) {
|
||||
if (!owner.isAttackable(entity, style, message)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!getProperties().isMultiZone()) {
|
||||
if (entity instanceof Player && !((Player) entity).getProperties().isMultiZone()) {
|
||||
if (attacker instanceof Player) {
|
||||
Player attackingPlayer = (Player) attacker;
|
||||
if (!attackingPlayer.getSkullManager().isWilderness()) {
|
||||
if (message) {
|
||||
sendMessage((Player) entity, "You have to be in multicombat to attack a player's familiar.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (entity instanceof Player) {
|
||||
if (message) {
|
||||
sendMessage((Player) entity, "This familiar is not in the a multicombat zone.");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (entity instanceof Player) {
|
||||
if (!((Player) entity).getSkullManager().isWilderness()) {
|
||||
if (message) {
|
||||
sendMessage((Player) entity, "You have to be in the wilderness to attack a player's familiar.");
|
||||
sendMessage(attackingPlayer, "You have to be in the wilderness to attack a player's familiar.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (!owner.getSkullManager().isWilderness()) {
|
||||
if (message) {
|
||||
sendMessage((Player) entity, "This familiar's owner is not in the wilderness.");
|
||||
sendMessage(attackingPlayer, "This familiar's owner is not in the wilderness.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (!owner.isAttackable(attackingPlayer, style, false)) {
|
||||
return true;
|
||||
}
|
||||
if (!attackingPlayer.getProperties().isMultiZone()) {
|
||||
if (message) {
|
||||
sendMessage(attackingPlayer, "You have to be in a multicombat zone to attack a player's familiar.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (!this.getProperties().isMultiZone()) {
|
||||
if (message) {
|
||||
sendMessage(attackingPlayer, "This familiar is not in a multicombat zone.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -440,9 +506,10 @@ public abstract class Familiar extends NPC implements Plugin<Object> {
|
|||
public void visualizeSpecialMove() {
|
||||
owner.visualize(Animation.create(7660), Graphics.create(1316));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sends a familiar hit.
|
||||
*
|
||||
* @param target the target.
|
||||
* @param maxHit the max hit.
|
||||
* @param graphics the graphics.
|
||||
|
|
@ -459,6 +526,13 @@ public abstract class Familiar extends NPC implements Plugin<Object> {
|
|||
hit = RandomFunction.randomize(maxHit);
|
||||
}
|
||||
state.setEstimatedHit(hit);
|
||||
if (target instanceof NPC && ((NPC) target).getTask() != null && ((NPC) target).getTask().levelReq > owner.getSkills().getLevel(Skills.SLAYER)) {
|
||||
state.neutralizeHits();
|
||||
state.setPoisonDamage(-1);
|
||||
if (state.getStyle() == CombatStyle.MAGIC) {
|
||||
state.setEstimatedHit(-1);
|
||||
}
|
||||
}
|
||||
target.getImpactHandler().handleImpact(owner, hit, CombatStyle.MELEE, state);
|
||||
if (graphics != null) {
|
||||
target.graphics(graphics);
|
||||
|
|
@ -484,7 +558,7 @@ public abstract class Familiar extends NPC implements Plugin<Object> {
|
|||
public void sendFamiliarHit(final Entity target, final int maxHit) {
|
||||
sendFamiliarHit(target, maxHit, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if this familiar can attack the target (used mainly for special
|
||||
* moves).
|
||||
|
|
@ -495,11 +569,17 @@ public abstract class Familiar extends NPC implements Plugin<Object> {
|
|||
}
|
||||
if (target.getLocation().getDistance(getLocation()) > 8) {
|
||||
if (message) {
|
||||
owner.getPacketDispatch().sendMessage("That target is too far.");
|
||||
sendMessage(owner, "That target is too far.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (target.getLocks().isInteractionLocked() || !target.isAttackable(this, CombatStyle.MAGIC, true)) {
|
||||
if (target instanceof Player && !owner.getProperties().isMultiZone()) {
|
||||
if (message) {
|
||||
sendMessage(owner, "You have to be in a multicombat zone to attack another player with your familiar.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (target.getLocks().isInteractionLocked() || !target.isAttackable(this, CombatStyle.MAGIC, message)) {
|
||||
return false;
|
||||
}
|
||||
return isCombatFamiliar();
|
||||
|
|
@ -509,11 +589,13 @@ public abstract class Familiar extends NPC implements Plugin<Object> {
|
|||
public boolean canAttack(Entity target) {
|
||||
return canAttack(target, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if a familiar can perform a combat special attack.
|
||||
*
|
||||
* @param target the target.
|
||||
* @param message show message.
|
||||
*
|
||||
* @return {@code True} if so.
|
||||
*/
|
||||
public boolean canCombatSpecial(Entity target, boolean message) {
|
||||
|
|
@ -526,6 +608,10 @@ public abstract class Familiar extends NPC implements Plugin<Object> {
|
|||
if (getAttribute("special-delay", 0) > GameWorld.getTicks()) {
|
||||
return false;
|
||||
}
|
||||
// The special move probably should go through but with all harmful effects neutralized, but for now just block the damn thing
|
||||
if (target instanceof NPC && ((NPC) target).getTask() != null && ((NPC) target).getTask().levelReq > owner.getSkills().getLevel(Skills.SLAYER)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ public class IbisNPC extends Forager {
|
|||
* @param id The id.
|
||||
*/
|
||||
public IbisNPC(Player owner, int id) {
|
||||
super(owner, id, 3800, 12531, 12, new Item(361), new Item(373));
|
||||
super(owner, id, 3800, 12531, 12, new Item(359), new Item(371));
|
||||
boosts.add(new SkillBonus(Skills.FISHING, 3));
|
||||
}
|
||||
|
||||
|
|
@ -54,7 +54,7 @@ public class IbisNPC extends Forager {
|
|||
@Override
|
||||
public boolean produceItem(Item item) {
|
||||
if (super.produceItem(item)) {
|
||||
if (item.getId() == 373) {
|
||||
if (item.getId() == 371) {
|
||||
owner.getSkills().addExperience(Skills.FISHING, 10);
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package content.global.skill.summoning.familiar;
|
|||
import java.util.List;
|
||||
|
||||
import core.cache.def.impl.NPCDefinition;
|
||||
import core.game.node.entity.combat.equipment.WeaponInterface;
|
||||
import core.plugin.Initializable;
|
||||
import core.game.interaction.OptionHandler;
|
||||
import core.game.node.Node;
|
||||
|
|
@ -36,7 +37,7 @@ public class SmokeDevilNPC extends Familiar {
|
|||
* @param id The id.
|
||||
*/
|
||||
public SmokeDevilNPC(Player owner, int id) {
|
||||
super(owner, id, 4800, 12085, 6);
|
||||
super(owner, id, 4800, 12085, 6, WeaponInterface.STYLE_CAST);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -2,36 +2,35 @@ package content.minigame.allfiredup
|
|||
|
||||
import core.api.*
|
||||
import core.game.node.entity.player.Player
|
||||
import core.tools.SystemLogger
|
||||
import core.game.world.map.Location
|
||||
import core.tools.Log
|
||||
|
||||
/**
|
||||
* Various data for beacons, such as varp and offset, required FM level, etc
|
||||
* @author Ceikry
|
||||
* @author Ceikry, Player Name
|
||||
*/
|
||||
enum class AFUBeacon(val title: String, val fmLevel: Int, val varbit: Int, val location: Location, val experience: Double, val keeper: Int = 0) {
|
||||
RIVER_SALVE("",43,5146,Location.create(3396, 3464, 0),216.2,8065),
|
||||
RAG_AND_BONE("",43,5147,Location.create(3343, 3510, 0),235.8,8066),
|
||||
JOLLY_BOAR("",48,5148,Location.create(3278, 3525, 0), 193.8,8067),
|
||||
NORTH_VARROCK_CASTLE("",53,5149,Location.create(3236, 3527, 0),178.5,8068),
|
||||
GRAND_EXCHANGE("",59,5150,Location.create(3170, 3536, 0),194.3,8069),
|
||||
EDGEVILLE("",62,5151,Location.create(3087, 3516, 0),86.7,8070),
|
||||
MONASTERY("",68,5152,Location.create(3034, 3518, 0),224.4,8071),
|
||||
GOBLIN_VILLAGE("",72,5153,Location.create(2968, 3516, 0),194.8,8072),
|
||||
BURTHORPE("",76,5154,Location.create(2940, 3565, 0),195.3,8073),
|
||||
DEATH_PLATEAU("",79,5155,Location.create(2944, 3622, 0),249.9,8074),
|
||||
TROLLHEIM("",83,5156,Location.create(2939, 3680, 0),201.0,8075),
|
||||
GWD("",87,5157,Location.create(2937, 3773, 0),255.0,8076),
|
||||
TEMPLE("",89,5158,Location.create(2946, 3836, 0),198.9),
|
||||
PLATEAU("",92,5159,Location.create(2964, 3931, 0),147.9);
|
||||
RIVER_SALVE("near the River Salve", 43, 5146, Location.create(3396, 3464, 0), 216.2, 8065),
|
||||
RAG_AND_BONE("near the Rag and Bone Man", 43, 5147, Location.create(3343, 3510, 0), 235.8, 8066),
|
||||
JOLLY_BOAR("north of the Jolly Boar", 48, 5148, Location.create(3278, 3525, 0), 193.8, 8067),
|
||||
NORTH_VARROCK_CASTLE("north of Varrock Palace", 53, 5149, Location.create(3236, 3527, 0), 178.5, 8068),
|
||||
GRAND_EXCHANGE("north of the Grand Exchange", 59, 5150, Location.create(3170, 3536, 0), 194.3, 8069),
|
||||
EDGEVILLE("near Edgeville", 62, 5151, Location.create(3087, 3516, 0), 86.7, 8070),
|
||||
MONASTERY("near the Black Knights' Fortress", 68, 5152, Location.create(3034, 3518, 0), 224.4, 8071),
|
||||
GOBLIN_VILLAGE("near Goblin Village", 72, 5153, Location.create(2968, 3516, 0), 194.8, 8072),
|
||||
BURTHORPE("near Burthorpe", 76, 5154, Location.create(2940, 3565, 0), 195.3, 8073),
|
||||
DEATH_PLATEAU("east of Death Plateau", 79, 5155, Location.create(2944, 3622, 0), 249.9, 8074),
|
||||
TROLLHEIM("east of Trollheim", 83, 5156, Location.create(2939, 3680, 0), 201.0, 8075),
|
||||
GWD("east of the God Wars dungeon temple", 87, 5157, Location.create(2937, 3773, 0), 255.0, 8076),
|
||||
TEMPLE("north of the small temple in the Wilderness", 89, 5158, Location.create(2946, 3836, 0), 198.9),
|
||||
PLATEAU("on the Frozen Waste Plateau", 92, 5159, Location.create(2964, 3931, 0), 147.9);
|
||||
|
||||
companion object {
|
||||
fun forLocation(location: Location): AFUBeacon {
|
||||
for (beacon in values()) {
|
||||
if (beacon.location.equals(location)) return beacon
|
||||
}
|
||||
return AFUBeacon.RIVER_SALVE.also { log(this::class.java, Log.WARN, "Unhandled Beacon Location ${location.toString()}") }
|
||||
return AFUBeacon.RIVER_SALVE.also { log(this::class.java, Log.WARN, "Unhandled Beacon Location ${location.toString()}") }
|
||||
}
|
||||
|
||||
fun resetAllBeacons(player: Player){
|
||||
|
|
@ -42,19 +41,19 @@ enum class AFUBeacon(val title: String, val fmLevel: Int, val varbit: Int, val l
|
|||
}
|
||||
|
||||
fun light(player: Player){
|
||||
setVarbit(player, varbit, 2)
|
||||
setVarbit(player, varbit, 2, true)
|
||||
}
|
||||
|
||||
fun diminish(player: Player){
|
||||
setVarbit(player, varbit, 3)
|
||||
setVarbit(player, varbit, 3, true)
|
||||
}
|
||||
|
||||
fun extinguish(player: Player){
|
||||
setVarbit(player, varbit, 0)
|
||||
setVarbit(player, varbit, 0, true)
|
||||
}
|
||||
|
||||
fun lightGnomish(player: Player){
|
||||
setVarbit(player, varbit, 4)
|
||||
setVarbit(player, varbit, 4, true)
|
||||
}
|
||||
|
||||
fun fillWithLogs(player: Player){
|
||||
|
|
|
|||
|
|
@ -4,13 +4,23 @@ import core.game.node.entity.npc.NPC
|
|||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.skill.Skills
|
||||
import core.game.node.item.Item
|
||||
import core.game.system.task.Pulse
|
||||
import core.game.world.update.flag.context.Animation
|
||||
import org.rs09.consts.Items
|
||||
import core.game.interaction.InteractionListener
|
||||
import core.game.interaction.IntType
|
||||
import core.game.world.GameWorld
|
||||
import content.data.Quests
|
||||
import core.api.delayScript
|
||||
import core.api.getAttribute
|
||||
import core.api.getOrStartTimer
|
||||
import core.api.getQuestStage
|
||||
import core.api.lock
|
||||
import core.api.queueScript
|
||||
import core.api.removeAttribute
|
||||
import core.api.sendMessage
|
||||
import core.api.setAttribute
|
||||
import core.api.setQuestStage
|
||||
import core.api.stopExecuting
|
||||
import core.game.interaction.QueueStrength
|
||||
|
||||
private val VALID_LOGS = intArrayOf(Items.LOGS_1511, Items.OAK_LOGS_1521,Items.WILLOW_LOGS_1519,Items.MAPLE_LOGS_1517,Items.YEW_LOGS_1515,Items.MAGIC_LOGS_1513)
|
||||
private val FILL_ANIM = Animation(9136)
|
||||
|
|
@ -18,7 +28,7 @@ private val LIGHT_ANIM = Animation(7307)
|
|||
|
||||
/**
|
||||
* Handles interactions for beacons
|
||||
* @author Ceikry
|
||||
* @author Ceikry, Player Name
|
||||
*/
|
||||
class AFUBeaconListeners : InteractionListener {
|
||||
|
||||
|
|
@ -86,112 +96,80 @@ class AFUBeaconListeners : InteractionListener {
|
|||
|
||||
val logs = getLogs(player,20)
|
||||
if (logs.id != 0 && player.inventory.remove(logs)) {
|
||||
player.lock()
|
||||
|
||||
var session: AFUSession? = null
|
||||
if(questComplete){
|
||||
session = player.getAttribute("afu-session", null)
|
||||
if(session == null) {
|
||||
session = AFUSession(player)
|
||||
session.init()
|
||||
lock(player, FILL_ANIM.duration)
|
||||
queueScript(player, 0, QueueStrength.SOFT) { stage ->
|
||||
if (stage == 1) {
|
||||
player.animator.animate(FILL_ANIM)
|
||||
return@queueScript delayScript(player, FILL_ANIM.duration)
|
||||
}
|
||||
setAttribute(player, "/save:beacon:${beacon.ordinal}:logsId", logs.id)
|
||||
beacon.fillWithLogs(player)
|
||||
return@queueScript stopExecuting(player)
|
||||
}
|
||||
|
||||
GameWorld.Pulser.submit(object : Pulse() {
|
||||
var counter = 0
|
||||
override fun pulse(): Boolean {
|
||||
when (counter++) {
|
||||
0 -> player.animator.animate(FILL_ANIM)
|
||||
1 -> {
|
||||
beacon.fillWithLogs(player)
|
||||
if(questComplete){
|
||||
session?.setLogs(beacon.ordinal,logs)
|
||||
}
|
||||
}
|
||||
2 -> player.unlock().also {player.animator.animate(Animation.RESET); return true }
|
||||
}
|
||||
return false
|
||||
}
|
||||
})
|
||||
} else {
|
||||
player.dialogueInterpreter.sendDialogue("You need some logs to do this.")
|
||||
}
|
||||
}
|
||||
|
||||
fun lightBeacon(player: Player, beacon: AFUBeacon, questComplete: Boolean){
|
||||
var session: AFUSession? = null
|
||||
if(questComplete){
|
||||
session = player.getAttribute("afu-session",null)
|
||||
if(session == null) return
|
||||
}
|
||||
|
||||
fun lightBeacon(player: Player, beacon: AFUBeacon, questComplete: Boolean) {
|
||||
if(player.inventory.contains(Items.TINDERBOX_590,1)){
|
||||
player.lock()
|
||||
GameWorld.Pulser.submit(object: Pulse(){
|
||||
var counter = 0
|
||||
override fun pulse(): Boolean {
|
||||
when(counter++){
|
||||
0 -> player.animator.animate(LIGHT_ANIM)
|
||||
1 -> {
|
||||
beacon.light(player)
|
||||
if(questComplete){
|
||||
session?.startTimer(beacon.ordinal)
|
||||
if(session?.getLitBeacons() == 6 && !player.hasFireRing()){
|
||||
player.sendMessage("Congratulations on lighting 6 beacons at once! King Roald has something for you.")
|
||||
player.setAttribute("/save:afu-mini:ring",true)
|
||||
}
|
||||
if(session?.getLitBeacons() == 10 && !player.hasFlameGloves()){
|
||||
player.sendMessage("Congratulations on lighting 10 beacons at once! King Roald has something for you.")
|
||||
player.setAttribute("/save:afu-mini:gloves",true)
|
||||
}
|
||||
if(session?.getLitBeacons() == 14 && !player.hasInfernoAdze()){
|
||||
player.sendMessage("Congratulations on lighting all 14 beacons! King Roald has something special for you.")
|
||||
player.setAttribute("/save:afu-mini:adze",true)
|
||||
}
|
||||
var experience = beacon.experience
|
||||
experience += session?.getBonusExperience() ?: 0.0
|
||||
player.skills.addExperience(Skills.FIREMAKING,experience)
|
||||
} else {
|
||||
player.questRepository.getQuest(Quests.ALL_FIRED_UP).setStage(player, player.questRepository.getStage(Quests.ALL_FIRED_UP) + 10)
|
||||
}
|
||||
}
|
||||
2 -> player.unlock().also { return true }
|
||||
}
|
||||
return false
|
||||
lock(player, LIGHT_ANIM.duration)
|
||||
queueScript(player, 0, QueueStrength.SOFT) { stage ->
|
||||
if (stage == 1) {
|
||||
player.animator.animate(LIGHT_ANIM)
|
||||
return@queueScript delayScript(player, LIGHT_ANIM.duration)
|
||||
}
|
||||
})
|
||||
val logsId = getAttribute(player, "/save:beacon:${beacon.ordinal}:logsId", Items.LOGS_1511)
|
||||
removeAttribute(player, "/save:beacon:${beacon.ordinal}:logsId")
|
||||
beacon.light(player)
|
||||
if (!questComplete) {
|
||||
setQuestStage(player, Quests.ALL_FIRED_UP, getQuestStage(player, Quests.ALL_FIRED_UP) + 10)
|
||||
return@queueScript stopExecuting(player)
|
||||
}
|
||||
val timer = getOrStartTimer<AFUTimer>(player)
|
||||
timer.addTime(beacon.ordinal, logsId, 20)
|
||||
val lit = timer.getLitBeacons()
|
||||
if (lit == 6 && !player.hasFireRing()) {
|
||||
sendMessage(player, "Congratulations on lighting 6 beacons at once! King Roald has something for you.")
|
||||
setAttribute(player, "/save:afu-mini:ring", true)
|
||||
}
|
||||
if (lit == 10 && !player.hasFlameGloves()) {
|
||||
sendMessage(player, "Congratulations on lighting 10 beacons at once! King Roald has something for you.")
|
||||
setAttribute(player, "/save:afu-mini:gloves", true)
|
||||
}
|
||||
if (lit == 14 && !player.hasInfernoAdze()) {
|
||||
sendMessage(player, "Congratulations on lighting all 14 beacons! King Roald has something special for you.")
|
||||
setAttribute(player, "/save:afu-mini:adze", true)
|
||||
}
|
||||
val xp = beacon.experience + timer.getBonusExperience()
|
||||
player.skills.addExperience(Skills.FIREMAKING, xp)
|
||||
return@queueScript stopExecuting(player)
|
||||
}
|
||||
} else {
|
||||
player.dialogueInterpreter.sendDialogue("You need a tinderbox to light this.")
|
||||
}
|
||||
}
|
||||
|
||||
fun restoreBeacon(player: Player, beacon: AFUBeacon, questComplete: Boolean){
|
||||
var session: AFUSession? = null
|
||||
if(questComplete){
|
||||
session = player.getAttribute("afu-session",null)
|
||||
if(session == null) return
|
||||
}
|
||||
|
||||
val logs = getLogs(player, 5)
|
||||
if (logs.id != 0 && player.inventory.remove(logs)) {
|
||||
player.lock()
|
||||
GameWorld.Pulser.submit(object: Pulse(){
|
||||
var counter = 0
|
||||
override fun pulse(): Boolean {
|
||||
when(counter++){
|
||||
0 -> player.animator.animate(FILL_ANIM)
|
||||
1 -> beacon.light(player).also {
|
||||
if(questComplete){
|
||||
session?.refreshTimer(beacon,logs.id)
|
||||
} else {
|
||||
player.questRepository.getQuest(Quests.ALL_FIRED_UP).setStage(player, 80)
|
||||
}
|
||||
}
|
||||
2 -> player.unlock().also { return true }
|
||||
}
|
||||
return false
|
||||
lock(player, FILL_ANIM.duration)
|
||||
queueScript(player, 0, QueueStrength.SOFT) { stage ->
|
||||
if (stage == 1) {
|
||||
player.animator.animate(LIGHT_ANIM)
|
||||
return@queueScript delayScript(player, LIGHT_ANIM.duration)
|
||||
}
|
||||
})
|
||||
val backupLogsId = getAttribute(player, "/save:beacon:${beacon.ordinal}:backupLogsId", Items.LOGS_1511)
|
||||
removeAttribute(player, "/save:beacon:${beacon.ordinal}:backupLogsId")
|
||||
beacon.light(player)
|
||||
if (!questComplete) {
|
||||
setQuestStage(player, Quests.ALL_FIRED_UP, 80)
|
||||
return@queueScript stopExecuting(player)
|
||||
}
|
||||
val timer = getOrStartTimer<AFUTimer>(player)
|
||||
timer.addTime(beacon.ordinal, backupLogsId, 5)
|
||||
return@queueScript stopExecuting(player)
|
||||
}
|
||||
} else {
|
||||
player.dialogueInterpreter.sendDialogue("You need some logs to do this.")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,121 +0,0 @@
|
|||
package content.minigame.allfiredup
|
||||
|
||||
import core.api.LogoutListener
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.item.Item
|
||||
import core.game.system.task.Pulse
|
||||
import core.game.world.GameWorld
|
||||
import org.rs09.consts.Items
|
||||
import core.tools.colorize
|
||||
|
||||
/**
|
||||
* Handles keeping track of lit beacons and their burn time remaining
|
||||
* @author Ceikry
|
||||
*/
|
||||
class AFUSession(val player: Player? = null) : LogoutListener {
|
||||
private val beaconTimers = Array(14){i -> BeaconTimer(0, AFUBeacon.values()[i]) }
|
||||
private val logInventories = Array(14){Item(0,0)}
|
||||
private val beaconWatched = Array(14){false}
|
||||
private var isActive = false
|
||||
|
||||
fun init() {
|
||||
isActive = true
|
||||
GameWorld.Pulser.submit(object: Pulse(){
|
||||
override fun pulse(): Boolean {
|
||||
player!!.setAttribute("afu-pulse",this)
|
||||
beaconTimers.forEach {timer ->
|
||||
timer.ticks--
|
||||
if(timer.ticks == 300) timer.beacon.diminish(player).also {
|
||||
if(beaconWatched[timer.beacon.ordinal]){
|
||||
beaconWatched[timer.beacon.ordinal] = false
|
||||
timer.ticks += (getTicks(logInventories[timer.beacon.ordinal].id) * 5)
|
||||
timer.beacon.light(player)
|
||||
player.sendMessage(colorize("%RThe ${timer.beacon.name.toLowerCase().replace("_"," ")} watcher has used your backup logs."))
|
||||
} else {
|
||||
player.sendMessage(colorize("%RThe ${timer.beacon.name.toLowerCase().replace("_", " ")} beacon is dying!"))
|
||||
}
|
||||
}
|
||||
if(timer.ticks == 0) timer.beacon.extinguish(player).also { player.sendMessage(colorize("%RThe ${timer.beacon.name.toLowerCase().replace("_"," ")} beacon has gone out!")) }
|
||||
}
|
||||
return !isActive
|
||||
}
|
||||
})
|
||||
player!!.setAttribute("afu-session",this)
|
||||
}
|
||||
|
||||
fun getLitBeacons(): Int{
|
||||
return beaconTimers.count { it.ticks > 0 }
|
||||
}
|
||||
|
||||
fun end(){
|
||||
isActive = false
|
||||
}
|
||||
|
||||
fun setLogs(beaconIndex: Int, logs: Item){
|
||||
logInventories[beaconIndex] = logs
|
||||
}
|
||||
|
||||
fun startTimer(beaconIndex: Int){
|
||||
val ticks = getTicks(logInventories[beaconIndex].id) * 20
|
||||
logInventories[beaconIndex] = Item(0,0)
|
||||
beaconTimers[beaconIndex].ticks = ticks
|
||||
}
|
||||
|
||||
fun refreshTimer(beacon: AFUBeacon, logID: Int){
|
||||
val ticks = getTicks(logID) * 5
|
||||
beaconTimers.forEach {
|
||||
if(it.beacon.ordinal == beacon.ordinal) it.ticks += ticks
|
||||
}
|
||||
}
|
||||
|
||||
fun setWatcher(index: Int, logs: Item){
|
||||
beaconWatched[index] = true
|
||||
logInventories[index] = logs
|
||||
}
|
||||
|
||||
fun isWatched(index: Int): Boolean{
|
||||
return beaconWatched[index]
|
||||
}
|
||||
|
||||
fun getTicks(logID: Int): Int{
|
||||
val ticks = when(logID){
|
||||
Items.LOGS_1511 -> 65
|
||||
Items.OAK_LOGS_1521 -> 68
|
||||
Items.WILLOW_LOGS_1519 -> 73
|
||||
Items.MAPLE_LOGS_1517 -> 79
|
||||
Items.YEW_LOGS_1515 -> 83
|
||||
Items.MAGIC_LOGS_1513 -> 90
|
||||
else -> 0
|
||||
}
|
||||
return ticks
|
||||
}
|
||||
|
||||
fun getBonusExperience(): Double{
|
||||
return when(getLitBeacons()){
|
||||
1 -> 608.4
|
||||
2 -> 1622.4
|
||||
3 -> 1987.4
|
||||
4 -> 2149.6
|
||||
5 -> 2149.6
|
||||
6 -> 2514.6
|
||||
7 -> 2555.2
|
||||
8 -> 2758.0
|
||||
9 -> 2839.1
|
||||
10 -> 3041.9
|
||||
11 -> 3123.0
|
||||
12 -> 3244.7
|
||||
13 -> 3366.4
|
||||
14 -> 4867.4
|
||||
else -> 0.0
|
||||
}
|
||||
}
|
||||
|
||||
override fun logout(player: Player) {
|
||||
AFUBeacon.resetAllBeacons(player)
|
||||
val session: AFUSession? = player.getAttribute("afu-session",null)
|
||||
session?.end()
|
||||
player.removeAttribute("afu-session")
|
||||
}
|
||||
|
||||
internal class BeaconTimer(var ticks: Int, val beacon: AFUBeacon)
|
||||
}
|
||||
104
Server/src/main/content/minigame/allfiredup/AFUTimer.kt
Normal file
104
Server/src/main/content/minigame/allfiredup/AFUTimer.kt
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
package content.minigame.allfiredup
|
||||
|
||||
import core.api.getAttribute
|
||||
import core.api.log
|
||||
import core.api.removeAttribute
|
||||
import core.api.sendMessage
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.system.timer.PersistTimer
|
||||
import core.tools.Log
|
||||
import core.tools.colorize
|
||||
import org.json.simple.JSONArray
|
||||
import org.json.simple.JSONObject
|
||||
import org.rs09.consts.Items
|
||||
|
||||
class AFUTimer : PersistTimer(1, "AFU timer", isSoft = true) {
|
||||
private val burnTicks = Array(14) { 0 }
|
||||
|
||||
fun addTime(index: Int, logsId: Int, numLogs: Int) {
|
||||
val ticksPerLog = when (logsId) {
|
||||
Items.LOGS_1511 -> 65
|
||||
Items.OAK_LOGS_1521 -> 68
|
||||
Items.WILLOW_LOGS_1519 -> 73
|
||||
Items.MAPLE_LOGS_1517 -> 79
|
||||
Items.YEW_LOGS_1515 -> 83
|
||||
Items.MAGIC_LOGS_1513 -> 90
|
||||
else -> 0
|
||||
}
|
||||
burnTicks[index] += numLogs * ticksPerLog
|
||||
}
|
||||
|
||||
fun getBonusExperience(): Double {
|
||||
return when (getLitBeacons()) {
|
||||
1 -> 608.4
|
||||
2 -> 1622.4
|
||||
3 -> 1987.4
|
||||
4 -> 2149.6
|
||||
5 -> 2149.6
|
||||
6 -> 2514.6
|
||||
7 -> 2555.2
|
||||
8 -> 2758.0
|
||||
9 -> 2839.1
|
||||
10 -> 3041.9
|
||||
11 -> 3123.0
|
||||
12 -> 3244.7
|
||||
13 -> 3366.4
|
||||
14 -> 4867.4
|
||||
else -> 0.0
|
||||
}
|
||||
}
|
||||
|
||||
fun getLitBeacons(): Int {
|
||||
return burnTicks.count { it > 0 }
|
||||
}
|
||||
|
||||
override fun save(root: JSONObject, entity: Entity) {
|
||||
val beaconArray = JSONArray()
|
||||
for (i in 0..13) {
|
||||
beaconArray.add(burnTicks[i])
|
||||
}
|
||||
root["beacons"] = beaconArray
|
||||
}
|
||||
|
||||
override fun parse(root: JSONObject, entity: Entity) {
|
||||
val beacons = root["beacons"] as JSONArray
|
||||
for (i in 0..13) {
|
||||
burnTicks[i] = beacons[i].toString().toInt()
|
||||
}
|
||||
}
|
||||
|
||||
override fun run(entity: Entity) : Boolean {
|
||||
if (entity !is Player) {
|
||||
log(this::class.java, Log.ERR, "How did a non-Player light an AFU beacon?")
|
||||
return false
|
||||
}
|
||||
val player = entity
|
||||
var keepRunning = false
|
||||
for (i in 0..13) {
|
||||
val beacon = AFUBeacon.values()[i]
|
||||
if (burnTicks[i] > 0) {
|
||||
burnTicks[i]--
|
||||
if (burnTicks[i] > 0) {
|
||||
keepRunning = true
|
||||
}
|
||||
if (burnTicks[i] == 300) {
|
||||
val backupLogsId = getAttribute(player, "/save:beacon:$i:backupLogsId", 0)
|
||||
if (backupLogsId != 0) {
|
||||
addTime(i, backupLogsId, 5)
|
||||
removeAttribute(player, "/save:beacon:$i:backupLogsId")
|
||||
sendMessage(player, colorize("%RThe beacon watcher ${beacon.title} has used your backup logs."))
|
||||
} else {
|
||||
beacon.diminish(player)
|
||||
sendMessage(player, colorize("%RThe beacon ${beacon.title} is dying!"))
|
||||
}
|
||||
} else if (burnTicks[i] == 0) {
|
||||
beacon.extinguish(player)
|
||||
removeAttribute(player, "/save:beacon:$i:logsId")
|
||||
sendMessage(player, colorize("%RThe beacon ${beacon.title} has gone out!"))
|
||||
}
|
||||
}
|
||||
}
|
||||
return keepRunning
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
package content.minigame.allfiredup
|
||||
|
||||
import core.ServerConstants
|
||||
import core.game.dialogue.*
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.skill.Skills
|
||||
import core.game.node.item.Item
|
||||
import core.plugin.Initializable
|
||||
import content.region.wilderness.dialogue.*
|
||||
import core.api.getAttribute
|
||||
import core.api.setAttribute
|
||||
import org.rs09.consts.Items
|
||||
|
||||
private val VALID_LOGS = arrayOf(Items.LOGS_1511, Items.OAK_LOGS_1521, Items.WILLOW_LOGS_1519, Items.MAPLE_LOGS_1517, Items.YEW_LOGS_1515, Items.MAGIC_LOGS_1513)
|
||||
|
|
@ -41,10 +41,9 @@ class BeaconTenderDialogue(player: Player? = null) : DialoguePlugin(player) {
|
|||
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
|
||||
val beacon = AFUBeacon.values()[index]
|
||||
val logs = getLogs(player,5)
|
||||
val session: AFUSession? = player.getAttribute("afu-session",null)
|
||||
when(stage){
|
||||
0 -> player("Hello!").also { stage++ }
|
||||
1 -> if(beacon.getState(player) == BeaconState.LIT && session?.isWatched(index) == false){
|
||||
1 -> if (beacon.getState(player) == BeaconState.LIT && getAttribute(player, "/save:beacon:${beacon.ordinal}:backupLogsId", 0) == 0) {
|
||||
options("Can you watch this beacon for me?","Nevermind.").also { stage = 10 }
|
||||
} else {
|
||||
npc("Carry on, adventurer.").also { stage = 1000 }
|
||||
|
|
@ -62,7 +61,7 @@ class BeaconTenderDialogue(player: Player? = null) : DialoguePlugin(player) {
|
|||
13 -> npc("Great, hand them over.").also { stage++ }
|
||||
14 -> player("Here you go!").also {
|
||||
player.inventory.remove(logs)
|
||||
session?.setWatcher(index,logs)
|
||||
setAttribute(player, "/save:beacon:${beacon.ordinal}:backupLogsId", logs.id)
|
||||
stage = 1000
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,14 +6,14 @@ import core.game.node.entity.combat.CombatStyle;
|
|||
import core.game.node.entity.combat.CombatSwingHandler;
|
||||
import core.game.node.entity.combat.InteractionType;
|
||||
import core.game.node.entity.combat.equipment.ArmourSet;
|
||||
import core.game.node.entity.impl.Projectile;
|
||||
import core.game.node.entity.impl.Animator.Priority;
|
||||
import core.game.node.entity.impl.Projectile;
|
||||
import core.game.node.entity.player.Player;
|
||||
import core.game.world.update.flag.context.Animation;
|
||||
import core.game.world.update.flag.context.Graphics;
|
||||
import core.tools.RandomFunction;
|
||||
|
||||
import static core.api.ContentAPIKt.*;
|
||||
import static core.api.ContentAPIKt.applyPoison;
|
||||
|
||||
/**
|
||||
* Handles K'ril Tsutsaroth's combat.
|
||||
|
|
@ -62,11 +62,13 @@ public final class GWDTsutsarothSwingHandler extends CombatSwingHandler {
|
|||
if (RandomFunction.randomize(10) < 4) {
|
||||
ticks += (int) Math.ceil(entity.getLocation().getDistance(victim.getLocation()) * 0.3);
|
||||
style = CombatStyle.MAGIC;
|
||||
} else if (RandomFunction.randomize(10) == 0) {
|
||||
if (special = (victim instanceof Player)) {
|
||||
((Player) victim).getPacketDispatch().sendMessage("K'ril Tsutsaroth slams through your protection prayer, leaving you feeling drained.");
|
||||
}
|
||||
} else if (victim instanceof Player && RandomFunction.randomize(10) == 0) {
|
||||
Player player = (Player) victim;
|
||||
special = player.hasProtectionPrayer(CombatStyle.MELEE);
|
||||
if (special) {
|
||||
player.getPacketDispatch().sendMessage("K'ril Tsutsaroth slams through your protection prayer, leaving you feeling drained.");
|
||||
entity.sendChat("YARRRRRRR!");
|
||||
}
|
||||
}
|
||||
if (style.getSwingHandler().isAccurateImpact(entity, victim)) {
|
||||
int max = style.getSwingHandler().calculateHit(entity, victim, special ? 1.08 : 1.0);
|
||||
|
|
@ -76,7 +78,7 @@ public final class GWDTsutsarothSwingHandler extends CombatSwingHandler {
|
|||
applyPoison(victim, entity, 80);
|
||||
}
|
||||
if (special) {
|
||||
((Player) victim).getSkills().decrementPrayerPoints((double) hit / 2);
|
||||
victim.getSkills().decrementPrayerPoints((double) hit / 2);
|
||||
}
|
||||
}
|
||||
state.setEstimatedHit(hit);
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ public class SophanemPlugin extends OptionHandler {
|
|||
SceneryDefinition.forId(20275).getHandlers().put("option:climb-down", this);
|
||||
SceneryDefinition.forId(20391).getHandlers().put("option:open", this);
|
||||
SceneryDefinition.forId(28514).getHandlers().put("option:open", this);
|
||||
SceneryDefinition.forId(20341).getHandlers().put("option:open", this);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -53,6 +54,8 @@ public class SophanemPlugin extends OptionHandler {
|
|||
}
|
||||
DoorActionHandler.handleDoor(player, (Scenery) node);
|
||||
break;
|
||||
case 20341:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -356,9 +356,8 @@ class PlagueCityListeners : InteractionListener {
|
|||
|
||||
on(Scenery.DOOR_2054, IntType.SCENERY, "open"){ player, node ->
|
||||
if (isQuestComplete(player, Quests.PLAGUE_CITY)){
|
||||
DoorActionHandler.handleDoor(player, node as SceneryNode)
|
||||
}
|
||||
else{
|
||||
DoorActionHandler.handleAutowalkDoor(player, node as SceneryNode)
|
||||
} else {
|
||||
sendMessage(player, "This door is locked")
|
||||
}
|
||||
return@on true
|
||||
|
|
|
|||
|
|
@ -1,51 +1,110 @@
|
|||
package content.region.misc.keldagrim.dialogue
|
||||
|
||||
import core.game.dialogue.DialoguePlugin
|
||||
import core.game.dialogue.FacialExpression
|
||||
import core.game.dialogue.Topic
|
||||
import core.game.node.entity.player.Player
|
||||
import core.api.*
|
||||
import core.game.dialogue.ChatAnim
|
||||
import core.game.dialogue.DialogueLabeller
|
||||
import core.game.dialogue.DialogueOption
|
||||
import core.game.interaction.IntType
|
||||
import core.game.interaction.InteractionListener
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.item.Item
|
||||
import core.plugin.Initializable
|
||||
import core.tools.END_DIALOGUE
|
||||
import core.tools.START_DIALOGUE
|
||||
import org.rs09.consts.Items
|
||||
import org.rs09.consts.NPCs
|
||||
|
||||
|
||||
@Initializable
|
||||
class BlandebirDialogue(player: Player? = null) : DialoguePlugin(player) {
|
||||
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
|
||||
when(stage){
|
||||
START_DIALOGUE -> playerl(FacialExpression.FRIENDLY, "Hello, I wonder if you could help me on this whole brewing thing...").also { stage++ }
|
||||
1 -> npcl(FacialExpression.OLD_DEFAULT, "I might be able to - what do you need to know?").also { stage++ }
|
||||
2 -> showTopics(
|
||||
Topic(FacialExpression.FRIENDLY, "How do I brew ales?", 3),
|
||||
Topic(FacialExpression.FRIENDLY, "How do I brew cider?", 6),
|
||||
Topic(FacialExpression.FRIENDLY, "What do I do once my ale has matured?", 8),
|
||||
Topic(FacialExpression.FRIENDLY, "Do you have any spare ale yeast?", 9),
|
||||
Topic(FacialExpression.FRIENDLY, "That's all I need to know, thanks.", END_DIALOGUE),
|
||||
class BlandebirDialogue : InteractionListener {
|
||||
override fun defineListeners() {
|
||||
on(NPCs.BLANDEBIR_2321, IntType.NPC, "talk-to") { player, node ->
|
||||
DialogueLabeller.open(player, BlandebirDialogueFile(), node as NPC)
|
||||
return@on true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class BlandebirDialogueFile : DialogueLabeller() {
|
||||
override fun addConversation() {
|
||||
assignToIds(NPCs.BLANDEBIR_2321)
|
||||
|
||||
player(ChatAnim.FRIENDLY, "Hello, I wonder if you could help me on this whole brewing thing...")
|
||||
npc(ChatAnim.OLD_DEFAULT, "I might be able to - what do you need to know?")
|
||||
goto("main_menu")
|
||||
|
||||
label("main_menu") {
|
||||
options(
|
||||
DialogueOption("how_brew_ales", "How do I brew ales?", expression = ChatAnim.HALF_ASKING, spokenText = "How do I brew ales?"),
|
||||
DialogueOption("how_brew_cider", "How do I brew cider?", expression = ChatAnim.HALF_ASKING, spokenText = "How do I brew cider?"),
|
||||
DialogueOption("what_when_matured", "What do I do once my ale has matured?", expression = ChatAnim.HALF_ASKING, spokenText = "What do I do once my ale has matured?"),
|
||||
DialogueOption("buy_yeast", "Do you have any spare ale yeast?", expression = ChatAnim.HALF_ASKING, spokenText = "Do you have any spare ale yeast?"),
|
||||
DialogueOption("end", "That's all I need to know, thanks.")
|
||||
)
|
||||
3 -> npcl(FacialExpression.OLD_DEFAULT, "Well first off you need to fill the vat with water - two bucketfuls should do the trick. Then you'll need to put in two handfuls of barley malt - that's roasted barley by the way.").also { stage++ }
|
||||
4 -> npcl(FacialExpression.OLD_DEFAULT, "After that you'll be putting your main ingredient in - this will decide which ale it is you're brewing. There should be some good guides around with recipes in.").also { stage++ }
|
||||
5 -> npcl(FacialExpression.OLD_DEFAULT, "Lastly you pour a pot full of ale yeast in, which'll start it off fermenting. Then all you have to do is wait for the good stuff.").also {
|
||||
stage = 2
|
||||
}
|
||||
6 -> npcl(FacialExpression.OLD_DEFAULT, "First you'll need some apples. You'll need to crush them using this cider-press - four apples should make a full bucket of apple-mush. Take four buckets of mush and fill up the vat.").also { stage++ }
|
||||
7 -> npcl(FacialExpression.OLD_DEFAULT, "After that you pour a pot full of ale yeast in, which'll start it off fermenting. Then all you have to do is wait for the good stuff.").also {
|
||||
stage = 2
|
||||
}
|
||||
8 -> npcl(FacialExpression.OLD_DEFAULT, "Well, once you've got a full vat of the good stuff, just turn the valve and your barrel will fill up with eight pints of whatever your chosen tipple is. Mind it's an empty barrel, though.").also {
|
||||
stage = 2
|
||||
}
|
||||
9 -> npcl(FacialExpression.OLD_DEFAULT, "Well, as a matter of fact I do, although I wouldn't describe it as spare. This ale yeast I've got is the best money can buy, but if you've got a pot I'll fill it for you for 25GP - very cheap as it happens.").also {
|
||||
stage = 2
|
||||
}
|
||||
|
||||
label("how_brew_ales") {
|
||||
npc(ChatAnim.OLD_DEFAULT, "Well first off you need to fill the vat with water - two bucketfuls should do the trick. Then you'll need to put in two handfuls of barley malt - that's roasted barley by the way.")
|
||||
npc(ChatAnim.OLD_DEFAULT, "After that you'll be putting your main ingredient in - this will decide which ale it is you're brewing. There should be some good guides around with recipes in.")
|
||||
npc(ChatAnim.OLD_DEFAULT, "Lastly you pour a pot full of ale yeast in, which'll start it off fermenting. Then all you have to do is wait for the good stuff.")
|
||||
goto("main_menu")
|
||||
}
|
||||
|
||||
label("how_brew_cider") {
|
||||
npc(ChatAnim.OLD_DEFAULT, "First you'll need some apples. You'll need to crush them using this cider-press - four apples should make a full bucket of apple-mush. Take four buckets of mush and fill up the vat.")
|
||||
npc(ChatAnim.OLD_DEFAULT, "After that you pour a pot full of ale yeast in, which'll start it off fermenting. Then all you have to do is wait for the good stuff.")
|
||||
goto("main_menu")
|
||||
}
|
||||
|
||||
label("what_when_matured") {
|
||||
npc(ChatAnim.OLD_DEFAULT, "Well, once you've got a full vat of the good stuff, just turn the valve and your barrel will fill up with eight pints of whatever your chosen tipple is. Mind it's an empty barrel, though.")
|
||||
goto("main_menu")
|
||||
}
|
||||
|
||||
label("buy_yeast") {
|
||||
npc(ChatAnim.OLD_DEFAULT, "Well, as a matter of fact I do, although I wouldn't describe it as spare. This ale yeast I've got is the best money can buy, but if you've got a pot I'll fill it for you for 25GP - very cheap as it happens.")
|
||||
options(
|
||||
DialogueOption("confirm_buy", "That's a good deal - please fill my pot with ale yeast for 25GP."),
|
||||
DialogueOption("end", "No, that's too much I'm afraid.")
|
||||
)
|
||||
}
|
||||
|
||||
label("confirm_buy") {
|
||||
exec { player, npc ->
|
||||
if (!inInventory(player, Items.EMPTY_POT_1931, 1)) {
|
||||
loadLabel(player, "no_pot")
|
||||
} else if (!inInventory(player, Items.COINS_995, 25)) {
|
||||
loadLabel(player, "no_coins")
|
||||
} else {
|
||||
loadLabel(player, "process_purchase")
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun newInstance(player: Player?): DialoguePlugin {
|
||||
return BlandebirDialogue(player)
|
||||
}
|
||||
label("no_pot") {
|
||||
npc(ChatAnim.OLD_DEFAULT, "I'm afraid you'll need a pot for me to put the yeast in.")
|
||||
goto("end")
|
||||
}
|
||||
|
||||
override fun getIds(): IntArray {
|
||||
return intArrayOf(NPCs.BLANDEBIR_2321)
|
||||
label("no_coins") {
|
||||
line("You can not afford that.")
|
||||
goto("end")
|
||||
}
|
||||
|
||||
label("process_purchase") {
|
||||
exec { player, npc ->
|
||||
val emptyPots = amountInInventory(player, Items.EMPTY_POT_1931)
|
||||
val coins = amountInInventory(player, Items.COINS_995)
|
||||
val canAfford = coins / 25
|
||||
val quantity = minOf(emptyPots, canAfford)
|
||||
|
||||
if (removeItem(player, Item(Items.EMPTY_POT_1931, quantity)) && removeItem(player, Item(Items.COINS_995, quantity * 25))) {
|
||||
addItem(player, Items.ALE_YEAST_5767, quantity)
|
||||
}
|
||||
}
|
||||
goto("main_menu")
|
||||
}
|
||||
|
||||
label("end") {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,9 +52,10 @@ public final class GrandExchangeClerk extends DialoguePlugin {
|
|||
|
||||
@Override
|
||||
public boolean handle(int interfaceId, int buttonId) {
|
||||
String salutation = player.isMale() ? "sir" : "madam";
|
||||
switch (stage) {
|
||||
case 0:
|
||||
npc("Good day to you, sir, How can I help?");
|
||||
npc("Good day to you, " + salutation + ", how can I help?");
|
||||
stage = 1;
|
||||
break;
|
||||
case 1:
|
||||
|
|
@ -80,13 +81,13 @@ public final class GrandExchangeClerk extends DialoguePlugin {
|
|||
stage = 40;
|
||||
break;
|
||||
case 5:
|
||||
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "I'm fine actually.");
|
||||
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "I'm fine, actually.");
|
||||
stage = 50;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
npc("Only too happy to help you, sir.");
|
||||
npc("Only too happy to help you, " + salutation + ".");
|
||||
stage = 11;
|
||||
break;
|
||||
case 11:
|
||||
|
|
@ -94,7 +95,7 @@ public final class GrandExchangeClerk extends DialoguePlugin {
|
|||
StockMarket.openFor(player);
|
||||
break;
|
||||
case 20:
|
||||
npc("As you wish, sir.");
|
||||
npc("As you wish, " + salutation + ".");
|
||||
stage = 21;
|
||||
break;
|
||||
case 21:
|
||||
|
|
@ -110,7 +111,7 @@ public final class GrandExchangeClerk extends DialoguePlugin {
|
|||
GrandExchangeRecords.getInstance(player).openHistoryLog(player);
|
||||
break;
|
||||
case 40:
|
||||
npc("It would be my pleasure, sir.");
|
||||
npc("It would be my pleasure, " + salutation + ".");
|
||||
stage = 41;
|
||||
break;
|
||||
case 41:
|
||||
|
|
@ -118,7 +119,7 @@ public final class GrandExchangeClerk extends DialoguePlugin {
|
|||
ExchangeItemSets.openFor(player);
|
||||
break;
|
||||
case 50:
|
||||
npc("If you say so, sir.");
|
||||
npc("If you say so, " + salutation + ".");
|
||||
stage = 51;
|
||||
break;
|
||||
case 51:
|
||||
|
|
|
|||
|
|
@ -15,7 +15,10 @@ import org.rs09.consts.Items
|
|||
* @author Ceikry
|
||||
*/
|
||||
@Initializable
|
||||
class AllFiredUp : Quest(Quests.ALL_FIRED_UP, 157, 156, 1){
|
||||
class AllFiredUp : Quest(Quests.ALL_FIRED_UP, 157, 156, 1,
|
||||
1282 /*this is actually unused*/,
|
||||
5133 /*source: ::varbits 1282, after trial and error confirmed that I need ::setvarp 1282 0 QUEST_STAGE*/,
|
||||
0, 1, 90) { //not started -- in progress -- completed
|
||||
override fun newInstance(`object`: Any?): Quest {
|
||||
return this
|
||||
}
|
||||
|
|
@ -150,13 +153,6 @@ class AllFiredUp : Quest(Quests.ALL_FIRED_UP, 157, 156, 1){
|
|||
player.skills.addExperience(Skills.FIREMAKING, 5500.0)
|
||||
player.inventory.add(Item(995,20000))
|
||||
AFUBeacon.resetAllBeacons(player)
|
||||
setVarbit(player, 1283, 0)
|
||||
player.questRepository.syncronizeTab(player)
|
||||
}
|
||||
|
||||
override fun getConfig(player: Player?, stage: Int): IntArray {
|
||||
if(stage == 100) return intArrayOf(1282, 90)
|
||||
if(stage > 0) return intArrayOf(1282, 1)
|
||||
else return intArrayOf(1282, 0)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -124,10 +124,4 @@ class FamilyCrest: Quest(Quests.FAMILY_CREST, 59, 58, 1, 148, 0, 1, 11) {
|
|||
}
|
||||
setAttribute(player, "/save:family-crest:gauntlets", Items.FAMILY_GAUNTLETS_778)
|
||||
}
|
||||
|
||||
/*override fun getConfig(player: Player?, stage: Int): IntArray {
|
||||
if(stage == 100) return intArrayOf(1282, 90)
|
||||
if(stage > 0) return intArrayOf(1282, 1)
|
||||
else return intArrayOf(1282, 0)
|
||||
}*/
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,127 @@
|
|||
package content.region.morytania.phas.dialogue
|
||||
|
||||
import core.api.*
|
||||
import core.game.dialogue.ChatAnim
|
||||
import core.game.dialogue.DialogueLabeller
|
||||
import core.game.dialogue.DialogueOption
|
||||
import core.game.interaction.IntType
|
||||
import core.game.interaction.InteractionListener
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.item.Item
|
||||
import core.plugin.Initializable
|
||||
import org.rs09.consts.Items
|
||||
import org.rs09.consts.NPCs
|
||||
|
||||
|
||||
@Initializable
|
||||
class MetarialusDialogue : InteractionListener {
|
||||
override fun defineListeners() {
|
||||
on(NPCs.METARIALUS_2322, IntType.NPC, "talk-to") { player, node ->
|
||||
if (inEquipment(player, Items.GHOSTSPEAK_AMULET_552) || inEquipment(player, Items.GHOSTSPEAK_AMULET_4250)) {
|
||||
DialogueLabeller.open(player, MetarialusDialogueFile(), node as NPC)
|
||||
return@on true
|
||||
} else {
|
||||
DialogueLabeller.open(player, MetarialusDialogueNoGhostSpeakFile(), node as NPC)
|
||||
return@on true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class MetarialusDialogueFile : DialogueLabeller() {
|
||||
override fun addConversation() {
|
||||
assignToIds(NPCs.METARIALUS_2322)
|
||||
|
||||
player(ChatAnim.FRIENDLY, "Hello, I wonder if you could help me on this whole brewing thing...")
|
||||
npc(ChatAnim.NEUTRAL, "I might be able to - what do you need to know?")
|
||||
goto("main_menu")
|
||||
|
||||
label("main_menu") {
|
||||
options(
|
||||
DialogueOption("how_brew_ales", "How do I brew ales?", expression = ChatAnim.HALF_ASKING, spokenText = "How do I brew ales?"),
|
||||
DialogueOption("how_brew_cider", "How do I brew cider?", expression = ChatAnim.HALF_ASKING, spokenText = "How do I brew cider?"),
|
||||
DialogueOption("what_when_matured", "What do I do once my ale has matured?", expression = ChatAnim.HALF_ASKING, spokenText = "What do I do once my ale has matured?"),
|
||||
DialogueOption("buy_yeast", "Do you have any spare ale yeast?", expression = ChatAnim.HALF_ASKING, spokenText = "Do you have any spare ale yeast?"),
|
||||
DialogueOption("end", "That's all I need to know, thanks.")
|
||||
)
|
||||
}
|
||||
|
||||
label("how_brew_ales") {
|
||||
npc(ChatAnim.NEUTRAL, "Well first off you need to fill the vat with water - two bucketfuls should do the trick. Then you'll need to put in two handfuls of barley malt - that's roasted barley by the way.")
|
||||
npc(ChatAnim.NEUTRAL, "After that you'll be putting your main ingredient in - this will decide which ale it is you're brewing. There should be some good guides around with recipes in.")
|
||||
npc(ChatAnim.NEUTRAL, "Lastly you pour a pot full of ale yeast in, which'll start it off fermenting. Then all you have to do is wait for the good stuff.")
|
||||
goto("main_menu")
|
||||
}
|
||||
|
||||
label("how_brew_cider") {
|
||||
npc(ChatAnim.NEUTRAL, "First you'll need some apples. You'll need to crush them using this cider-press - four apples should make a full bucket of apple-mush. Take four buckets of mush and fill up the vat.")
|
||||
npc(ChatAnim.NEUTRAL, "After that you pour a pot full of ale yeast in, which'll start it off fermenting. Then all you have to do is wait for the good stuff.")
|
||||
goto("main_menu")
|
||||
}
|
||||
|
||||
label("what_when_matured") {
|
||||
npc(ChatAnim.NEUTRAL, "Well, once you've got a full vat of the good stuff, just turn the valve and your barrel will fill up with eight pints of whatever your chosen tipple is. Mind it's an empty barrel, though.")
|
||||
goto("main_menu")
|
||||
}
|
||||
|
||||
label("buy_yeast") {
|
||||
npc(ChatAnim.NEUTRAL, "Well, as a matter of fact I do, although I wouldn't describe",
|
||||
"it as spare. This ale yeast I've got is the best money can",
|
||||
"buy, but if you've got a pot I'll fill it for you for",
|
||||
"5 ecto-tokens - very cheap as it happens.")
|
||||
options(
|
||||
DialogueOption("confirm_buy", "That's a good deal - please fill my pot with ale yeast for 5 ecto-tokens."),
|
||||
DialogueOption("end", "No, that's too much I'm afraid.")
|
||||
)
|
||||
}
|
||||
|
||||
label("confirm_buy") {
|
||||
exec { player, npc ->
|
||||
if (!inInventory(player, Items.EMPTY_POT_1931, 1)) {
|
||||
loadLabel(player, "no_pot")
|
||||
} else if (!inInventory(player, Items.ECTO_TOKEN_4278, 5)) {
|
||||
loadLabel(player, "no_tokens")
|
||||
} else {
|
||||
loadLabel(player, "process_purchase")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
label("no_pot") {
|
||||
npc(ChatAnim.NEUTRAL, "I'm afraid you'll need a pot for me to put the yeast in.")
|
||||
goto("end")
|
||||
}
|
||||
|
||||
label("no_tokens") {
|
||||
line("You can not afford that.")
|
||||
goto("end")
|
||||
}
|
||||
|
||||
label("process_purchase") {
|
||||
exec { player, npc ->
|
||||
val emptyPots = amountInInventory(player, Items.EMPTY_POT_1931)
|
||||
val tokens = amountInInventory(player, Items.ECTO_TOKEN_4278)
|
||||
val canAfford = tokens / 5
|
||||
val quantity = minOf(emptyPots, canAfford)
|
||||
|
||||
if (removeItem(player, Item(Items.EMPTY_POT_1931, quantity)) && removeItem(player, Item(Items.ECTO_TOKEN_4278, quantity * 5))) {
|
||||
addItem(player, Items.ALE_YEAST_5767, quantity)
|
||||
}
|
||||
}
|
||||
goto("main_menu")
|
||||
}
|
||||
|
||||
label("end") {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class MetarialusDialogueNoGhostSpeakFile : DialogueLabeller() {
|
||||
override fun addConversation() {
|
||||
assignToIds(NPCs.METARIALUS_2322)
|
||||
|
||||
npc(ChatAnim.WORRIED, "Wooo Woo ooo wooowoo!") // Placeholder taken from restless ghost, can't find source for his no-ghostspeak text
|
||||
}
|
||||
}
|
||||
|
|
@ -418,7 +418,7 @@ fun replaceSlot(player: Player, slot: Int, item: Item, currentItem: Item? = null
|
|||
}
|
||||
|
||||
if (cont.remove(currentItem, slot, true)) {
|
||||
return cont.replace(item, slot)
|
||||
return cont.replace(item, slot) ?: currentItem
|
||||
}
|
||||
|
||||
PlayerMonitor.log(player, LogType.DUPE_ALERT, "Potential slot-replacement-based dupe attempt, slot: $slot, item: $item")
|
||||
|
|
@ -426,8 +426,9 @@ fun replaceSlot(player: Player, slot: Int, item: Item, currentItem: Item? = null
|
|||
Container.INVENTORY -> Container.EQUIPMENT
|
||||
else -> Container.INVENTORY
|
||||
}
|
||||
if (removeItem(player, currentItem, other))
|
||||
return cont.replace(item, slot)
|
||||
if (removeItem(player, currentItem, other)) {
|
||||
return cont.replace(item, slot) ?: currentItem
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
|
|
@ -3026,7 +3027,7 @@ fun queueScript(entity: Entity, delay: Int = 1, strength: QueueStrength = QueueS
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the clock to the value of WORLD_TICSK + ticks.
|
||||
* Sets the clock to the value of WORLD_TICKS + ticks.
|
||||
* @param entity the entity whose clock we are updating
|
||||
* @param clock the clock we are updating. Please use [core.game.interaction.Clocks] for this argument.
|
||||
* @param ticks the number of ticks to delay by
|
||||
|
|
|
|||
|
|
@ -221,6 +221,12 @@ public abstract class MovementPulse extends Pulse {
|
|||
clearInferiorScripts();
|
||||
|
||||
mover.face(null);
|
||||
if (canInteractWithoutMoving()) {
|
||||
if (interactImmediately()) {
|
||||
stop();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
updatePath();
|
||||
|
||||
if (tryInteract()) {
|
||||
|
|
@ -237,7 +243,24 @@ public abstract class MovementPulse extends Pulse {
|
|||
int radius = destination instanceof Entity && ((Entity)destination).getWalkingQueue().hasPath() ? 1 : 0;
|
||||
if (interactLocation == null)
|
||||
return false;
|
||||
if (Math.max(Math.abs(ml.getX() - interactLocation.getX()), Math.abs(ml.getY() - interactLocation.getY())) <= radius) {
|
||||
boolean atInteractLocation = Math.max(Math.abs(ml.getX() - interactLocation.getX()), Math.abs(ml.getY() - interactLocation.getY())) <= radius;
|
||||
// Check if already in a valid interaction position for entity destinations
|
||||
boolean canInteractFromCurrentPosition = false;
|
||||
if (!atInteractLocation && destination instanceof Entity) {
|
||||
Entity target = (Entity) destination;
|
||||
Location dl = target.getLocation();
|
||||
boolean onSameTile = ml.getX() == dl.getX() && ml.getY() == dl.getY() && ml.getZ() == dl.getZ();
|
||||
if (!onSameTile) {
|
||||
canInteractFromCurrentPosition = Pathfinder.canInteract(
|
||||
ml.getX(), ml.getY(), mover.size(),
|
||||
dl.getX(), dl.getY(), target.size(), target.size(),
|
||||
0, // walkFlag - "can interact from any unblocked direction"
|
||||
ml.getZ(),
|
||||
RegionManager::getClippingFlag
|
||||
);
|
||||
}
|
||||
}
|
||||
if (atInteractLocation || canInteractFromCurrentPosition) {
|
||||
try {
|
||||
if (near || pulse()) {
|
||||
if (mover instanceof Player) {
|
||||
|
|
@ -257,6 +280,66 @@ public abstract class MovementPulse extends Pulse {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the mover can interact with an entity destination from their
|
||||
* current position without needing to move.
|
||||
*
|
||||
* @return true if the mover can interact without moving
|
||||
*/
|
||||
private boolean canInteractWithoutMoving() {
|
||||
if (!(destination instanceof Entity)) {
|
||||
return false;
|
||||
}
|
||||
Entity target = (Entity) destination;
|
||||
Location ml = mover.getLocation();
|
||||
Location dl = target.getLocation();
|
||||
if (ml.getX() == dl.getX() && ml.getY() == dl.getY() && ml.getZ() == dl.getZ()) {
|
||||
return false;
|
||||
}
|
||||
if (isInsideEntity(mover.getLocation())) {
|
||||
return false;
|
||||
}
|
||||
if (target.getWalkingQueue().hasPath()) { // For moving entities, allow interaction from 1 tile away
|
||||
int distance = Math.max(
|
||||
Math.abs(ml.getX() - dl.getX()),
|
||||
Math.abs(ml.getY() - dl.getY())
|
||||
);
|
||||
if (distance <= target.size()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return Pathfinder.canInteract(
|
||||
ml.getX(), ml.getY(), mover.size(),
|
||||
dl.getX(), dl.getY(), target.size(), target.size(),
|
||||
0, // walkFlag - "can interact from any unblocked direction"
|
||||
ml.getZ(),
|
||||
RegionManager::getClippingFlag
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Immediately performs the interaction without pathfinding.
|
||||
* Called when the player is already in a valid interaction position.
|
||||
*
|
||||
* @return true if interaction was successful and pulse should stop
|
||||
*/
|
||||
private boolean interactImmediately() {
|
||||
if (destination instanceof Entity) {
|
||||
mover.face((Entity) destination);
|
||||
}
|
||||
try {
|
||||
if (pulse()) {
|
||||
if (mover instanceof Player) {
|
||||
PacketRepository.send(ClearMinimapFlag.class, new PlayerContext((Player) mover));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean validate() {
|
||||
if (mover == null || destination == null || mover.getViewport().getRegion() == null || hasInactiveNode()) {
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -450,6 +450,9 @@ public abstract class Entity extends Node {
|
|||
if (!entity.getZoneMonitor().continueAttack(this, style, message)) {
|
||||
return false;
|
||||
}
|
||||
if (!this.getZoneMonitor().continueAttack(entity, style, message)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ public final class ImpactHandler {
|
|||
int percentage = (int) (entity.getSkills().getStaticLevel(Skills.HITPOINTS) * 0.10);
|
||||
if (p.getSkills().getLifepoints() <= percentage) {
|
||||
Item rolItem = new Item(Items.RING_OF_LIFE_2570);
|
||||
if (EnchantedJewellery.RING_OF_LIFE.attemptTeleport(p, rolItem, 0, true)) {
|
||||
if (EnchantedJewellery.RING_OF_LIFE.attemptTeleport(p, rolItem, 0, true, true)) {
|
||||
p.sendMessage("Your ring of life saves you and in the process is destroyed.");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package core.game.node.entity.combat
|
||||
|
||||
import content.global.skill.skillcapeperks.SkillcapePerks
|
||||
import content.global.skill.summoning.SummoningPouch
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.combat.equipment.ArmourSet
|
||||
import core.game.node.entity.combat.spell.SpellType
|
||||
|
|
@ -200,6 +201,7 @@ open class MagicSwingHandler (vararg flags: SwingHandlerFlag)
|
|||
effectiveMagicLevel = floor(effectiveMagicLevel + (victim.prayer.getSkillBonus(Skills.MAGIC) * effectiveMagicLevel))
|
||||
|
||||
effectiveDefenceLevel = effectiveDefenceLevel * 0.3 + effectiveMagicLevel * 0.7 + 8
|
||||
effectiveDefenceLevel *= familiarDefenceBonus(victim)
|
||||
return effectiveDefenceLevel.toInt() * styleDefenceBonus
|
||||
}
|
||||
is NPC -> {
|
||||
|
|
@ -220,6 +222,20 @@ open class MagicSwingHandler (vararg flags: SwingHandlerFlag)
|
|||
return 1.0
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see whether the player is receiving a defensive bonus from an active familiar.
|
||||
* - Wolpertinger => +5%
|
||||
*/
|
||||
private fun familiarDefenceBonus(e: Entity?): Double {
|
||||
if (e !is Player) return 1.0
|
||||
val fam = try {
|
||||
e.familiarManager?.familiar
|
||||
} catch (ex: Exception) {
|
||||
null
|
||||
} ?: return 1.0
|
||||
return if (fam.pouchId == SummoningPouch.WOLPERTINGER_POUCH.pouchId) 1.05 else 1.0
|
||||
}
|
||||
|
||||
override fun addExperience(entity: Entity?, victim: Entity?, state: BattleState?) {
|
||||
if (state?.spell != null && entity is Player) {
|
||||
state.spell.addExperience(entity, state.totalDamage)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import content.global.skill.skillcapeperks.SkillcapePerks
|
|||
import content.global.skill.slayer.SlayerEquipmentFlags
|
||||
import content.global.skill.slayer.SlayerManager
|
||||
import content.global.skill.slayer.Tasks
|
||||
import content.global.skill.summoning.SummoningPouch
|
||||
import core.api.*
|
||||
import core.api.EquipmentSlot
|
||||
import core.game.container.impl.EquipmentContainer
|
||||
|
|
@ -235,6 +236,7 @@ open class MeleeSwingHandler (vararg flags: SwingHandlerFlag)
|
|||
else if (victim.properties.attackStyle.style == WeaponInterface.STYLE_CONTROLLED) effectiveDefenceLevel += 1
|
||||
effectiveDefenceLevel += 8
|
||||
effectiveDefenceLevel *= getSetMultiplier(victim, Skills.DEFENCE)
|
||||
effectiveDefenceLevel *= familiarDefenceBonus(victim)
|
||||
return effectiveDefenceLevel.toInt() * styleDefenceBonus
|
||||
}
|
||||
is NPC -> {
|
||||
|
|
@ -282,6 +284,25 @@ open class MeleeSwingHandler (vararg flags: SwingHandlerFlag)
|
|||
|| name == "Skeleton" || name == "Zogre" || name == "Spiritual Mage")
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see whether the player is receiving a defensive bonus from an active familiar.
|
||||
* - Iron Titan => +10%
|
||||
* - Steel Titan => +15%
|
||||
*/
|
||||
private fun familiarDefenceBonus(e: Entity?): Double {
|
||||
if (e !is Player) return 1.0
|
||||
val fam = try {
|
||||
e.familiarManager?.familiar
|
||||
} catch (ex: Exception) {
|
||||
null
|
||||
} ?: return 1.0
|
||||
return when (fam.pouchId) {
|
||||
SummoningPouch.IRON_TITAN_POUCH.pouchId -> 1.10
|
||||
SummoningPouch.STEEL_TITAN_POUCH.pouchId -> 1.15
|
||||
else -> 1.0
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Checks if the entity is using a halberd.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package core.game.node.entity.combat
|
||||
|
||||
import content.global.skill.skillcapeperks.SkillcapePerks
|
||||
import content.global.skill.summoning.SummoningPouch
|
||||
import core.api.*
|
||||
import core.game.container.impl.EquipmentContainer
|
||||
import core.game.node.entity.Entity
|
||||
|
|
@ -207,6 +208,7 @@ open class RangeSwingHandler (vararg flags: SwingHandlerFlag) : CombatSwingHandl
|
|||
effectiveRangedLevel = floor(effectiveRangedLevel + (entity.prayer.getSkillBonus(Skills.RANGE) * effectiveRangedLevel))
|
||||
if(entity.properties.attackStyle.style == WeaponInterface.STYLE_RANGE_ACCURATE) effectiveRangedLevel += 3
|
||||
effectiveRangedLevel += 8
|
||||
effectiveRangedLevel += familiarOffenceBonus(entity)
|
||||
effectiveRangedLevel *= getSetMultiplier(entity, Skills.RANGE)
|
||||
if(SkillcapePerks.isActive(SkillcapePerks.ACCURATE_MARKSMAN,entity)) effectiveRangedLevel *= 1.1
|
||||
|
||||
|
|
@ -245,6 +247,7 @@ open class RangeSwingHandler (vararg flags: SwingHandlerFlag) : CombatSwingHandl
|
|||
effectiveStrengthLevel = floor(effectiveStrengthLevel + (entity.prayer.getSkillBonus(Skills.RANGE) * effectiveStrengthLevel))
|
||||
if(entity.properties.attackStyle.style == WeaponInterface.STYLE_RANGE_ACCURATE) effectiveStrengthLevel += 3
|
||||
effectiveStrengthLevel += 8
|
||||
effectiveStrengthLevel += familiarOffenceBonus(entity)
|
||||
effectiveStrengthLevel *= getSetMultiplier(entity, Skills.RANGE)
|
||||
effectiveStrengthLevel = floor(effectiveStrengthLevel)
|
||||
if (!flags.contains(SwingHandlerFlag.IGNORE_STAT_BOOSTS_DAMAGE))
|
||||
|
|
@ -301,6 +304,22 @@ open class RangeSwingHandler (vararg flags: SwingHandlerFlag) : CombatSwingHandl
|
|||
} else super.getArmourSet(e)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see whether the player is receiving an offensive bonus from an active familiar.
|
||||
* - Geyser Titan => 1 + 3% of ranged level
|
||||
*/
|
||||
private fun familiarOffenceBonus(e: Entity?): Double {
|
||||
if (e !is Player) return 0.0
|
||||
val fam = try {
|
||||
e.familiarManager?.familiar
|
||||
} catch (ex: Exception) {
|
||||
null
|
||||
} ?: return 0.0
|
||||
return if (fam.pouchId == SummoningPouch.GEYSER_TITAN_POUCH.pouchId) {
|
||||
1.0 + ceil(e.skills.getLevel(Skills.RANGE) * 0.03)
|
||||
} else 0.0
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Checks if the entity has the ammunition needed to proceed.
|
||||
|
|
|
|||
|
|
@ -226,14 +226,22 @@ public enum BoltEffect {
|
|||
victim.graphics(graphics);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the effect can fire.
|
||||
*
|
||||
* @param state the state.
|
||||
*
|
||||
* @return {@code True} if so.
|
||||
*/
|
||||
public boolean canFire(BattleState state) {
|
||||
return RandomFunction.random(13) == 5;
|
||||
// Never fires on slayer monster that player lacks level requirement for. Inauthentic(?)
|
||||
// and should be considered a TODO: temporary abuse prevention measure (bolt effect on slayer monsters)
|
||||
boolean rollSuccess = RandomFunction.random(13) == 5;
|
||||
if (!(state.getVictim() instanceof NPC)) return rollSuccess;
|
||||
if (!(state.getAttacker() instanceof Player) && ((NPC) state.getVictim()).getTask() == null) return rollSuccess;
|
||||
if (state.getVictim().asNpc().getTask().levelReq > state.getAttacker().asPlayer().getSkills().getLevel(Skills.SLAYER)) return false;
|
||||
return rollSuccess;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -383,7 +383,7 @@ public class NPC extends Entity {
|
|||
this.movementIndex = 0;
|
||||
this.pathBoundMovement = true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void checkImpact(BattleState state) {
|
||||
super.checkImpact(state);
|
||||
|
|
@ -391,21 +391,31 @@ public class NPC extends Entity {
|
|||
behavior.beforeDamageReceived(this, entity, state);
|
||||
if (task != null && entity instanceof Player && task.levelReq > entity.getSkills().getLevel(Skills.SLAYER)) {
|
||||
state.neutralizeHits();
|
||||
state.setPoisonDamage(-1);
|
||||
if (state.getStyle() == CombatStyle.MAGIC) {
|
||||
state.setEstimatedHit(-1);
|
||||
}
|
||||
}
|
||||
if (task != null && entity instanceof Familiar && task.levelReq > ((Familiar) entity).getOwner().getSkills().getLevel(Skills.SLAYER)) {
|
||||
state.neutralizeHits();
|
||||
state.setPoisonDamage(-1);
|
||||
if (state.getStyle() == CombatStyle.MAGIC) {
|
||||
state.setEstimatedHit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isAttackable(Entity entity, CombatStyle style, boolean message) {
|
||||
if (isInvisible()) {
|
||||
return false;
|
||||
}
|
||||
if (task != null && entity instanceof Player && task.levelReq > entity.getSkills().getLevel(Skills.SLAYER)) {
|
||||
if(message) {
|
||||
((Player) entity).getPacketDispatch().sendMessage("You need a higher slayer level to know how to wound this monster.");
|
||||
}
|
||||
if (message) {
|
||||
((Player) entity).getPacketDispatch().sendMessage("You need a higher slayer level to know how to wound this monster.");
|
||||
}
|
||||
}
|
||||
if (!behavior.canBeAttackedBy(this, entity, style, message))
|
||||
return false;
|
||||
if (!behavior.canBeAttackedBy(this, entity, style, message)) return false;
|
||||
return super.isAttackable(entity, style, message);
|
||||
}
|
||||
|
||||
|
|
@ -414,13 +424,7 @@ public class NPC extends Entity {
|
|||
if (isInvisible()) {
|
||||
return false;
|
||||
}
|
||||
if (task != null && target instanceof Player && task.levelReq > target.getSkills().getLevel(Skills.SLAYER)) {
|
||||
if (message) {
|
||||
((Player) target).getPacketDispatch().sendMessage("You need a higher slayer level to know how to wound this monster.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return behavior.canBeAttackedBy(this, target, style, message);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -764,7 +764,7 @@ public class Player extends Entity {
|
|||
return false;
|
||||
if (skullManager.hasWildernessProtection())
|
||||
return false;
|
||||
return true;
|
||||
return super.isAttackable(entity, style, message);
|
||||
} else return false;
|
||||
}
|
||||
return super.isAttackable(entity, style, message);
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ public class TeleportManager {
|
|||
if (teleportType != -1) {
|
||||
if (entity instanceof Player) {
|
||||
Player p = (Player) entity;
|
||||
p.scripts.setDelay(GameWorld.getTicks() + 12);
|
||||
p.getDialogueInterpreter().close();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -224,18 +224,6 @@ public class AchievementDiary {
|
|||
drawStatus(player);
|
||||
}
|
||||
|
||||
public boolean checkComplete(DiaryLevel level){
|
||||
if(type != DiaryType.LUMBRIDGE && level == DiaryLevel.BEGINNER){
|
||||
return false;
|
||||
}
|
||||
|
||||
if(level == DiaryLevel.BEGINNER){
|
||||
return completedLevels.contains(level.ordinal());
|
||||
}
|
||||
|
||||
return completedLevels.contains(level.ordinal() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a string on the diary interface.
|
||||
* @param player the player.
|
||||
|
|
|
|||
|
|
@ -337,14 +337,6 @@ public abstract class Quest implements Plugin<Object> {
|
|||
return questPoints;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the configs.
|
||||
* @return the configs.
|
||||
*/
|
||||
public int[] getConfigs() {
|
||||
return configs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Quest [name=" + quest + ", index=" + index + ", buttonId=" + buttonId + ", questPoints=" + questPoints + ", configs=" + Arrays.toString(configs) + "]";
|
||||
|
|
|
|||
|
|
@ -3,11 +3,13 @@ package core.game.system.command.sets
|
|||
import content.global.handlers.item.SpadeDigListener
|
||||
import content.region.misc.tutisland.handlers.iface.CharacterDesign
|
||||
import core.api.*
|
||||
import core.ServerStore
|
||||
import core.game.dialogue.DialogueFile
|
||||
import core.game.node.entity.combat.ImpactHandler
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.player.info.login.PlayerSaver
|
||||
import core.game.node.item.Item
|
||||
import core.game.system.command.Privilege
|
||||
import core.game.system.task.Pulse
|
||||
import core.game.world.GameWorld
|
||||
|
|
@ -17,8 +19,9 @@ import core.game.world.repository.Repository.getPlayerByName
|
|||
import core.game.world.update.flag.context.Animation
|
||||
import core.game.world.update.flag.context.Graphics
|
||||
import core.plugin.Initializable
|
||||
import core.tools.END_DIALOGUE
|
||||
import core.tools.RandomFunction
|
||||
import core.tools.Log
|
||||
import org.json.simple.JSONArray
|
||||
import org.json.simple.JSONObject
|
||||
import org.rs09.consts.Sounds
|
||||
import java.awt.HeadlessException
|
||||
|
|
@ -30,6 +33,60 @@ import kotlin.streams.toList
|
|||
class FunCommandSet : CommandSet(Privilege.ADMIN) {
|
||||
|
||||
var npcs: List<NPC> = ArrayList()
|
||||
private val TREASURE_KEY = "fun_command_buried_treasures"
|
||||
private val treasures = ArrayList<BuriedTreasure>()
|
||||
|
||||
init {
|
||||
loadTreasures()
|
||||
}
|
||||
|
||||
/**
|
||||
* I hope ceikry doesn't punish me for this ~ used SkillcapePerks for a base idea tried to make it modular.
|
||||
* Supports persistence across reboots for bury, buryitem, and burymessage supporting all command arguments.
|
||||
*/
|
||||
private fun loadTreasures() {
|
||||
|
||||
val archive = ServerStore.getArchive(TREASURE_KEY)
|
||||
if (!archive.containsKey("data")) return
|
||||
|
||||
try {
|
||||
val array = archive["data"] as JSONArray
|
||||
|
||||
for (obj in array) {
|
||||
|
||||
val json = obj as JSONObject
|
||||
val x = (json["x"] as Long).toInt()
|
||||
val y = (json["y"] as Long).toInt()
|
||||
val z = (json["z"] as Long).toInt()
|
||||
val loc = Location.create(x, y, z)
|
||||
|
||||
val type = TreasureType.valueOf(json["type"] as String)
|
||||
val hiderName = json["hiderName"] as? String ?: "Unknown"
|
||||
val hideName = json["hideName"] as? Boolean ?: false
|
||||
val customMessage = json["customMessage"] as? String
|
||||
val message = json["message"] as? String ?: ""
|
||||
|
||||
val items = ArrayList<Item>()
|
||||
if (json.containsKey("items")) {
|
||||
val itemsJson = json["items"] as JSONArray
|
||||
for (i in itemsJson) {
|
||||
val itemObj = i as JSONObject
|
||||
val id = (itemObj["id"] as Long).toInt()
|
||||
val amount = (itemObj["amount"] as Long).toInt()
|
||||
items.add(Item(id, amount))
|
||||
}
|
||||
}
|
||||
|
||||
val treasure = BuriedTreasure(loc, type, items, message, hiderName, hideName, customMessage)
|
||||
treasures.add(treasure)
|
||||
registerTreasureListener(treasure)
|
||||
}
|
||||
log(FunCommandSet::class.java, Log.DEBUG, "Loaded ${treasures.size} buried treasures.")
|
||||
} catch (e: Exception) {
|
||||
log(FunCommandSet::class.java, Log.ERR, "Failed to load buried treasures: ${e.message}")
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun defineCommands() {
|
||||
|
|
@ -175,19 +232,39 @@ class FunCommandSet : CommandSet(Privilege.ADMIN) {
|
|||
/**
|
||||
* Bury inventory at current location
|
||||
*/
|
||||
define("bury", description = "Buries your entire inventory at your current location."){player, _ ->
|
||||
define("bury", description = "Buries your entire inventory at your current location for treasure hunters. Required true/false to hide players name and an optional custom message."){player, args ->
|
||||
if(player.inventory.isEmpty){
|
||||
reject(player, "You have no items to bury.")
|
||||
}
|
||||
|
||||
if (args.size < 2) {
|
||||
reject(player, "Usage: ::bury <lt>true | false<gt> [custom news message]")
|
||||
return@define
|
||||
}
|
||||
|
||||
val hideName = when(args[1].lowercase()) {
|
||||
"true" -> true
|
||||
"false" -> false
|
||||
else -> {
|
||||
reject(player, "Invalid argument. Usage: ::bury <lt>true | false<gt> [custom news message]")
|
||||
return@define
|
||||
}
|
||||
}
|
||||
|
||||
val customMessage = if (args.size > 2) {
|
||||
args.slice(2 until args.size).joinToString(" ")
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
player.dialogueInterpreter.open(object : DialogueFile(){
|
||||
override fun handle(componentID: Int, buttonID: Int) {
|
||||
when(stage){
|
||||
0 -> dialogue("This will bury your whole inventory in this spot.","Are you sure?").also { stage++ }
|
||||
0 -> dialogue("This will bury your whole inventory at this spot.","Are you sure?").also { stage++ }
|
||||
1 -> options("Yes","No").also { stage++ }
|
||||
2 -> when(buttonID){
|
||||
1 -> bury(player).also { end() }
|
||||
2 -> stage = END_DIALOGUE
|
||||
1 -> bury(player, hideName, customMessage).also { end() }
|
||||
2 -> end()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -195,6 +272,78 @@ class FunCommandSet : CommandSet(Privilege.ADMIN) {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Bury a secret message at current location for a player to find.
|
||||
*/
|
||||
define("burymessage", description = "Buries a secret message at your current location."){ player, args ->
|
||||
if (args.size < 2) {
|
||||
reject(player, "Usage: ::burymessage [message]")
|
||||
return@define
|
||||
}
|
||||
|
||||
val message = args.slice(1 until args.size).joinToString(" ")
|
||||
val loc = Location.create(player.location)
|
||||
|
||||
if(SpadeDigListener.listeners.containsKey(loc)){
|
||||
reject(player, "There is already something buried here.")
|
||||
return@define
|
||||
}
|
||||
|
||||
val treasure = BuriedTreasure(loc, TreasureType.MESSAGE, emptyList(), message, player.username, false, null)
|
||||
treasures.add(treasure)
|
||||
saveTreasures()
|
||||
registerTreasureListener(treasure)
|
||||
|
||||
notify(player, "You have buried the message '$message' at $loc")
|
||||
log(FunCommandSet::class.java, Log.DEBUG, "Message buried by ${player.username} at $loc: \"$message\"")
|
||||
}
|
||||
|
||||
/**
|
||||
* Bury a specific item at current location
|
||||
*/
|
||||
define("buryitem", description = "Buries a specific item at your current location."){ player, args ->
|
||||
if (args.size < 3) {
|
||||
reject(player, "Usage: ::buryitem <lt>item id<gt> <lt>true | false<gt> [custom message]")
|
||||
return@define
|
||||
}
|
||||
|
||||
val itemId = args[1].toIntOrNull()
|
||||
if (itemId == null) {
|
||||
reject(player, "Invalid item ID.")
|
||||
return@define
|
||||
}
|
||||
|
||||
val hideName = when(args[2].lowercase()) {
|
||||
"true" -> true
|
||||
"false" -> false
|
||||
else -> {
|
||||
reject(player, "Invalid argument. Usage: ::buryitem <lt>item id<gt> <lt>true | false<gt> [custom message]")
|
||||
return@define
|
||||
}
|
||||
}
|
||||
|
||||
val customMessage = if (args.size > 3) {
|
||||
args.slice(3 until args.size).joinToString(" ")
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
player.dialogueInterpreter.open(object : DialogueFile(){
|
||||
override fun handle(componentID: Int, buttonID: Int) {
|
||||
when(stage){
|
||||
0 -> dialogue("This will bury a ${Item(itemId).name} at this spot.","Are you sure?").also { stage++ }
|
||||
1 -> options("Yes","No").also { stage++ }
|
||||
2 -> when(buttonID){
|
||||
1 -> buryItem(player, itemId, hideName, customMessage).also { end() }
|
||||
2 -> end()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
|
||||
define("appearance", Privilege.ADMIN, "", "Allows you to change your appearance."){ player, _ ->
|
||||
CharacterDesign.reopen(player)
|
||||
}
|
||||
|
|
@ -249,19 +398,109 @@ class FunCommandSet : CommandSet(Privilege.ADMIN) {
|
|||
|
||||
}
|
||||
|
||||
fun bury(player: Player){
|
||||
fun bury(player: Player, hideName: Boolean = false, customMessage: String? = null){
|
||||
|
||||
val loc = Location.create(player.location)
|
||||
val inv = player.inventory.toArray().filterNotNull()
|
||||
SpadeDigListener.registerListener(player.location){ p ->
|
||||
for(item in inv){
|
||||
addItemOrDrop(p, item.id, item.amount)
|
||||
sendMessage(p, "You dig and find ${if(item.amount > 1) "some" else "a"} ${item.name}")
|
||||
}
|
||||
sendNews("${player.username} has found the hidden treasure! Congratulations!!!")
|
||||
SpadeDigListener.listeners.remove(loc)
|
||||
if(SpadeDigListener.listeners.containsKey(loc)){
|
||||
notify(player, "There is already something buried here.")
|
||||
return
|
||||
}
|
||||
|
||||
val inv = player.inventory.toArray().filterNotNull().toList()
|
||||
if (inv.isEmpty()) {
|
||||
notify(player, "You have nothing to bury.")
|
||||
return
|
||||
}
|
||||
|
||||
val treasure = BuriedTreasure(loc, TreasureType.ITEM, inv, "", player.username, hideName, customMessage)
|
||||
treasures.add(treasure)
|
||||
saveTreasures()
|
||||
registerTreasureListener(treasure)
|
||||
|
||||
player.inventory.clear()
|
||||
notify(player, "You have buried your loot at ${loc.toString()}")
|
||||
log(FunCommandSet::class.java, Log.DEBUG, "Loot buried by ${player.username} at $loc. Masked: $hideName")
|
||||
}
|
||||
|
||||
fun buryItem(player: Player, itemId: Int, hideName: Boolean, customMessage: String? = null) {
|
||||
val loc = Location.create(player.location)
|
||||
if(SpadeDigListener.listeners.containsKey(loc)){
|
||||
notify(player, "There is already something buried here.")
|
||||
return
|
||||
}
|
||||
|
||||
val treasure = BuriedTreasure(loc, TreasureType.ITEM, listOf(Item(itemId, 1)), "", player.username, hideName, customMessage)
|
||||
treasures.add(treasure)
|
||||
saveTreasures()
|
||||
registerTreasureListener(treasure)
|
||||
|
||||
notify(player, "You have buried item ${Item(itemId).name} at $loc")
|
||||
log(FunCommandSet::class.java, Log.DEBUG, "Item $itemId buried by ${player.username} at $loc. Masked: $hideName")
|
||||
}
|
||||
|
||||
private fun registerTreasureListener(t: BuriedTreasure) {
|
||||
|
||||
SpadeDigListener.registerListener(t.location) { p ->
|
||||
log(FunCommandSet::class.java, Log.DEBUG, "SpadeDigListener triggered for ${p.username} at ${t.location}")
|
||||
|
||||
if (t.type == TreasureType.ITEM) {
|
||||
for(item in t.items){
|
||||
addItemOrDrop(p, item.id, item.amount)
|
||||
sendMessage(p, "You dig and find ${if(item.amount > 1) "some" else "a"} ${item.name}")
|
||||
}
|
||||
val finderName = if (t.hideName) "Someone" else p.username
|
||||
val message = t.customMessage ?: "$finderName has found the hidden treasure! Congratulations!!!"
|
||||
sendNews(message)
|
||||
} else {
|
||||
sendMessage(p, t.message)
|
||||
}
|
||||
|
||||
SpadeDigListener.listeners.remove(t.location)
|
||||
treasures.remove(t)
|
||||
saveTreasures()
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveTreasures() {
|
||||
|
||||
val array = JSONArray()
|
||||
|
||||
for (t in treasures) {
|
||||
val json = JSONObject()
|
||||
json["x"] = t.location.x
|
||||
json["y"] = t.location.y
|
||||
json["z"] = t.location.z
|
||||
json["type"] = t.type.name
|
||||
json["hiderName"] = t.hiderName
|
||||
json["hideName"] = t.hideName
|
||||
if (t.customMessage != null) json["customMessage"] = t.customMessage
|
||||
json["message"] = t.message
|
||||
|
||||
val itemsArray = JSONArray()
|
||||
for (i in t.items) {
|
||||
val itemObj = JSONObject()
|
||||
itemObj["id"] = i.id
|
||||
itemObj["amount"] = i.amount
|
||||
itemsArray.add(itemObj)
|
||||
}
|
||||
json["items"] = itemsArray
|
||||
|
||||
array.add(json)
|
||||
}
|
||||
val archive = ServerStore.getArchive(TREASURE_KEY)
|
||||
archive["data"] = array
|
||||
}
|
||||
|
||||
private data class BuriedTreasure(
|
||||
val location: Location,
|
||||
val type: TreasureType,
|
||||
val items: List<Item>,
|
||||
val message: String,
|
||||
val hiderName: String,
|
||||
val hideName: Boolean,
|
||||
val customMessage: String?
|
||||
)
|
||||
|
||||
private enum class TreasureType { ITEM, MESSAGE }
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package core.game.system.command.sets
|
||||
|
||||
import content.global.handlers.iface.*
|
||||
import content.global.skill.cooking.fermenting.BrewGrowth
|
||||
import content.global.skill.farming.timers.*
|
||||
import content.minigame.fishingtrawler.TrawlerLoot
|
||||
import content.region.misthalin.draynor.quest.anma.AnmaCutscene
|
||||
|
|
@ -26,12 +27,14 @@ import core.game.system.communication.CommunicationInfo
|
|||
import core.game.world.map.RegionManager
|
||||
import core.game.world.map.build.DynamicRegion
|
||||
import core.game.world.repository.Repository
|
||||
import core.game.node.entity.combat.equipment.WeaponInterface
|
||||
import core.plugin.Initializable
|
||||
import core.tools.Log
|
||||
import core.tools.StringUtils
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.rs09.consts.Components
|
||||
import org.rs09.consts.Items
|
||||
import java.awt.HeadlessException
|
||||
import java.awt.Toolkit
|
||||
import java.awt.datatransfer.StringSelection
|
||||
|
|
@ -129,6 +132,58 @@ class MiscCommandSet : CommandSet(Privilege.ADMIN){
|
|||
notify(player, "max hit: ${hit} (${(swingHandler as Object).getClass().getName()})")
|
||||
}
|
||||
|
||||
define("calcdefence", Privilege.STANDARD, "::calcdefence <lt>NPC ID<gt>", "Calculates and prints your current raw defence values for Melee, Ranged and Magic against a given NPC.") { player, args ->
|
||||
val meleeHandler = core.game.node.entity.combat.MeleeSwingHandler()
|
||||
val rangeHandler = core.game.node.entity.combat.RangeSwingHandler()
|
||||
val magicHandler = core.game.node.entity.combat.MagicSwingHandler()
|
||||
var attacker: core.game.node.entity.Entity = player
|
||||
if (args.size > 1) {
|
||||
val npcId = args[1].toInt()
|
||||
val npc = NPC(npcId)
|
||||
npc.initConfig()
|
||||
attacker = npc
|
||||
notify(player, "Calculating defence against NPC: ${npc.name} (ID=$npcId)")
|
||||
val bonuses = npc.properties.bonuses
|
||||
var maxBonus = Int.MIN_VALUE
|
||||
var maxIndex = 0
|
||||
for (i in 0..4) {
|
||||
if (i in bonuses.indices) {
|
||||
val v = bonuses[i]
|
||||
if (v > maxBonus) {
|
||||
maxBonus = v
|
||||
maxIndex = i
|
||||
}
|
||||
}
|
||||
}
|
||||
if (maxBonus == Int.MIN_VALUE) {
|
||||
maxBonus = 0
|
||||
maxIndex = 0
|
||||
}
|
||||
npc.properties.attackStyle = WeaponInterface.AttackStyle(WeaponInterface.STYLE_CONTROLLED,maxIndex)
|
||||
} else {
|
||||
notify(player, "Calculating defence against yourself (no NPC specified).")
|
||||
}
|
||||
fun hitChance(accuracy: Int, defence: Int): Double {
|
||||
return if (accuracy > defence) {
|
||||
1.0 - ((defence + 2.0) / (2.0 * (accuracy + 1.0)))
|
||||
} else {
|
||||
accuracy / (2.0 * (defence + 1.0))
|
||||
}
|
||||
}
|
||||
val meleeAccuracy = meleeHandler.calculateAccuracy(attacker)
|
||||
val meleeDefence = meleeHandler.calculateDefence(player, attacker)
|
||||
val meleeChance = hitChance(meleeAccuracy, meleeDefence)
|
||||
notify(player, "Your melee defence: $meleeDefence; Attacker accuracy: $meleeAccuracy; Chance to be hit: $meleeChance")
|
||||
val rangeAccuracy = rangeHandler.calculateAccuracy(attacker)
|
||||
val rangeDefence = rangeHandler.calculateDefence(player, attacker)
|
||||
val rangeChance = hitChance(rangeAccuracy, rangeDefence)
|
||||
notify(player, "Your range defence: $rangeDefence; Attacker accuracy: $rangeAccuracy; Chance to be hit: $rangeChance")
|
||||
val magicAccuracy = magicHandler.calculateAccuracy(attacker)
|
||||
val magicDefence = magicHandler.calculateDefence(player, attacker)
|
||||
val magicChance = hitChance(magicAccuracy, magicDefence)
|
||||
notify(player, "Your magic defence: $magicDefence; Attacker accuracy: $magicAccuracy; Chance to be hit: $magicChance")
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty a player's inventory
|
||||
* ADMIN only (for obvious reasons)
|
||||
|
|
@ -698,6 +753,64 @@ class MiscCommandSet : CommandSet(Privilege.ADMIN){
|
|||
notify(player, "Setting plaques read to: ${args[1]}")
|
||||
|
||||
}
|
||||
define("brewkit", Privilege.ADMIN, "brewkit <lt>0-10<gt>",
|
||||
"Give yourself everything you need to brew ales."){ player, args ->
|
||||
if (args.size == 1) {
|
||||
sendMessage(player, "Kit numbers: 0 - Dwarven Stout, 1 - Asgarnian Ale, 2 - Greenman's Ale,")
|
||||
sendMessage(player, "Kit numbers: 3 - Wizard's Mind Bomb, 4 - Dragon Bitter, 5 - Moonlight Mead,")
|
||||
sendMessage(player, "Kit numbers: 6 - Axeman's Folly, 7 - Chef's Delight, 8 - Slayer's Respite,")
|
||||
sendMessage(player, "Kit numbers: 9 - Cider, 10 - Kelda Stout")
|
||||
return@define
|
||||
}
|
||||
val item =
|
||||
when (args[1].toInt()) {
|
||||
0 -> Items.HAMMERSTONE_HOPS_5994
|
||||
1 -> Items.ASGARNIAN_HOPS_5996
|
||||
2 -> Items.CLEAN_HARRALANDER_255
|
||||
3 -> Items.YANILLIAN_HOPS_5998
|
||||
4 -> Items.KRANDORIAN_HOPS_6000
|
||||
5 -> Items.MUSHROOM_6004
|
||||
6 -> Items.OAK_ROOTS_6043
|
||||
7 -> Items.CHOCOLATE_DUST_1975
|
||||
8 -> Items.WILDBLOOD_HOPS_6002
|
||||
9 -> Items.APPLE_MUSH_5992
|
||||
10 -> Items.KELDA_HOPS_6113
|
||||
else -> {
|
||||
reject(player, "Invalid brew kit specified.")
|
||||
return@define
|
||||
}
|
||||
}
|
||||
addItemOrDrop(player, Items.BUCKET_OF_WATER_1929, if(args[1].toInt() == 9) 0 else 2)
|
||||
addItemOrDrop(player, Items.BARLEY_MALT_6008, if(args[1].toInt() == 9) 0 else 2)
|
||||
addItemOrDrop(player, item, if(args[1].toInt() == 6 || args[1].toInt() == 10) 1 else 4)
|
||||
addItemOrDrop(player, Items.ALE_YEAST_5767)
|
||||
return@define
|
||||
}
|
||||
|
||||
define("brew", Privilege.ADMIN, "brew <lt>mode<gt>",
|
||||
"0: force natural step, 1: force good step without maturity, 2: force good step with maturity, 3: force bad step"){ player, args ->
|
||||
var forceStep = false
|
||||
var forceGood = false
|
||||
var forceMature = false
|
||||
var forceBad = false
|
||||
if (args.size == 1){
|
||||
forceStep = true
|
||||
}
|
||||
if (args.size != 1){
|
||||
when(args[1].toIntOrNull()){
|
||||
0 -> forceStep = true
|
||||
1 -> forceGood = true
|
||||
2 -> forceMature = true
|
||||
3 -> forceBad = true
|
||||
else -> reject(player, "${args[1]} is not a valid option.")
|
||||
}
|
||||
}
|
||||
|
||||
val vats = getOrStartTimer<BrewGrowth>(player).getVats()
|
||||
for (vat in vats){
|
||||
vat.brew(forceStep, forceGood, forceMature, forceBad)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setupScrollInterface(player: Player, title: String): Int {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
package core.game.system.command.sets
|
||||
|
||||
import core.api.log
|
||||
import core.game.component.Component
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.player.link.quest.QuestRepository
|
||||
import core.plugin.Initializable
|
||||
import core.game.system.command.Privilege
|
||||
import core.game.world.repository.Repository
|
||||
import core.tools.Log
|
||||
|
||||
@Initializable
|
||||
class QuestCommandSet : CommandSet(Privilege.ADMIN){
|
||||
|
|
@ -15,7 +17,12 @@ class QuestCommandSet : CommandSet(Privilege.ADMIN){
|
|||
*/
|
||||
define("allquest", description = "Instantly completes every quest for your account."){player,_->
|
||||
for (quest in QuestRepository.getQuests().values) {
|
||||
quest.finish(player)
|
||||
try {
|
||||
quest.finish(player)
|
||||
} catch (e: Exception){
|
||||
e.message?.let { log(this.javaClass, Log.WARN, it) }
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
package core.game.system.timer.impl
|
||||
|
||||
import content.global.skill.summoning.familiar.Familiar
|
||||
import core.game.system.timer.*
|
||||
import core.api.*
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.combat.ImpactHandler
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.skill.Skills
|
||||
import core.game.world.repository.Repository
|
||||
import org.json.simple.*
|
||||
|
||||
|
|
@ -30,15 +33,28 @@ class Poison : PersistTimer (30, "poison", flags = arrayOf(TimerFlag.ClearOnDeat
|
|||
damageSource = Repository.getPlayerByUid (uid) ?: entity
|
||||
severity = root["severity"].toString().toInt()
|
||||
}
|
||||
|
||||
override fun onRegister (entity: Entity) {
|
||||
if (entity is Player) {
|
||||
sendMessage(entity, "You have been poisoned.")
|
||||
entity.debug ("[Poison] -> Received for $severity severity.")
|
||||
}
|
||||
if (damageSource is Player)
|
||||
(damageSource as? Player)?.debug ("[Poison] -> Applied for $severity severity.")
|
||||
}
|
||||
|
||||
override fun onRegister(entity : Entity) {
|
||||
if (entity is Player) {
|
||||
sendMessage(entity, "You have been poisoned.")
|
||||
entity.debug("[Poison] -> Received for $severity severity.")
|
||||
}
|
||||
if (damageSource is Player) {
|
||||
(damageSource as? Player)?.debug("[Poison] -> Applied for $severity severity.")
|
||||
// this is ass, and preventing poisoning slayer monster player lacks lv req for should be done but prob not here & not like this. same for familiars
|
||||
if (entity is NPC && entity.task != null && entity.task.levelReq > damageSource.skills.getLevel(Skills.SLAYER)) {
|
||||
(damageSource as? Player)?.debug("[Poison] -> Removed poison from ${entity.name} ${entity.location} due to Slayer reqs!")
|
||||
removeTimer(entity, this)
|
||||
}
|
||||
}
|
||||
if (damageSource is Familiar) {
|
||||
val owner : Player? = (damageSource as Familiar).owner
|
||||
if (owner != null && entity is NPC && entity.task != null && entity.task.levelReq > owner.skills.getLevel(Skills.SLAYER)) {
|
||||
owner.debug("[Poison] -> Removed poison from ${entity.name} ${entity.location} due to Slayer reqs!")
|
||||
removeTimer(entity, this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun run (entity: Entity) : Boolean {
|
||||
entity.impactHandler.manualHit (
|
||||
|
|
|
|||
|
|
@ -177,14 +177,23 @@ public abstract class MapZone implements Zone {
|
|||
if (multi || e.isIgnoreMultiBoundaries(t) || e.getZoneMonitor().isIgnoreMultiBoundaries(t)) {
|
||||
return true;
|
||||
}
|
||||
Entity attacker = e instanceof Familiar ? ((Familiar) e).getOwner() : e;
|
||||
Entity target = t.getAttribute("combat-attacker", e);
|
||||
if (t.getAttribute("combat-time", -1L) > time && target != e && target.isActive()) {
|
||||
if (target instanceof Familiar) {
|
||||
target = ((Familiar) target).getOwner();
|
||||
}
|
||||
if (t.getAttribute("combat-time", -1L) > time && target != attacker && target.isActive()) {
|
||||
if (message && e instanceof Player) {
|
||||
((Player) e).getPacketDispatch().sendMessage("Someone else is already fighting this" + (t instanceof Player ? " player." : "."));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (e.getAttribute("combat-time", -1L) > time && (target = e.getAttribute("combat-attacker", t)) != t && target.isActive()) {
|
||||
Entity attackerOnE = e.getAttribute("combat-attacker", t);
|
||||
if (attackerOnE instanceof Familiar) {
|
||||
attackerOnE = ((Familiar) attackerOnE).getOwner();
|
||||
}
|
||||
Entity tResolved = t instanceof Familiar ? ((Familiar) t).getOwner() : t;
|
||||
if (e.getAttribute("combat-time", -1L) > time && attackerOnE != tResolved && attackerOnE.isActive()) {
|
||||
if (t.getId() == 1614 || t.getId() == 1613) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -263,6 +263,23 @@ public final class WildernessZone extends MapZone {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
if (e instanceof Player && target instanceof NPC && ((NPC) target).getName().contains("Revenant")) {
|
||||
Player p = (Player) e;
|
||||
NPC npc = (NPC) target;
|
||||
int level = p.getSkullManager().getLevel();
|
||||
int npcWildLevel = getWilderness(npc);
|
||||
if (npcWildLevel < level) {
|
||||
level = npcWildLevel;
|
||||
}
|
||||
int combat = p.getProperties().getCurrentCombatLevel();
|
||||
int npcCombat = npc.getDefinition().getCombatLevel();
|
||||
if (combat - level > npcCombat || combat + level < npcCombat) {
|
||||
if (message) {
|
||||
p.getPacketDispatch().sendMessage("The level difference between you and your opponent is too great.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ public class RandomFunction {
|
|||
|
||||
/**
|
||||
* Method used to ease the access of the random class.
|
||||
* In certain cases, it is inclusive from the min value and exclusive from the max values specified.
|
||||
* @param a the minimum random value.
|
||||
* @param b the maximum random value.
|
||||
* @return the value as an {@link Integer}.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue