Compare commits

..

No commits in common. "master" and "Apr-19-2026" have entirely different histories.

3504 changed files with 228098 additions and 2175873 deletions

View file

@ -1,7 +1,7 @@
variables: variables:
# This will suppress any download for dependencies and plugins or upload messages which would clutter the console log. # This will suppress any download for dependencies and plugins or upload messages which would clutter the console log.
# `showDateTime` will show the passed time in milliseconds. You need to specify `--batch-mode` to make this work. # `showDateTime` will show the passed time in milliseconds. You need to specify `--batch-mode` to make this work.
MAVEN_OPTS: "-Dhttps.protocols=TLSv1.2 -Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=WARN -Dorg.slf4j.simpleLogger.showDateTime=true -Djava.awt.headless=true -Xmx4g -Xms2g" MAVEN_OPTS: "-Dhttps.protocols=TLSv1.2 -Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=WARN -Dorg.slf4j.simpleLogger.showDateTime=true -Djava.awt.headless=true -Xmx3g"
# As of Maven 3.3.0 instead of this you may define these options in `.mvn/maven.config` so the same config is used # As of Maven 3.3.0 instead of this you may define these options in `.mvn/maven.config` so the same config is used
# when running from the command line. # when running from the command line.
MAVEN_CLI_OPTS: "--batch-mode --errors --fail-fast --show-version" MAVEN_CLI_OPTS: "--batch-mode --errors --fail-fast --show-version"

View file

@ -29,7 +29,6 @@
* [Prerequisites](#prerequisites) * [Prerequisites](#prerequisites)
* [Project Setup](#project-setup) * [Project Setup](#project-setup)
* [Running the project](#running-the-project) * [Running the project](#running-the-project)
* [Browser WebSocket Transport](#browser-websocket-transport)
* [License](#license) * [License](#license)
* [Contact](#contact) * [Contact](#contact)
@ -81,20 +80,6 @@ There are many ways everyone can contribute! From the most seasoned programmers
* **Code Contributors**: As a remake, we have massive amounts of content that need to be implemented or corrected. If you know how to program or are willing to learn, this is where you could be extremely helpful! We need everything from quests, to dialogue, to mini-games, to skills that still need to be corrected or implemented. This is perhaps one of the most valuable ways someone could help out the project! If you are interested in developing content, reach out in the development channel of the Discord. * **Code Contributors**: As a remake, we have massive amounts of content that need to be implemented or corrected. If you know how to program or are willing to learn, this is where you could be extremely helpful! We need everything from quests, to dialogue, to mini-games, to skills that still need to be corrected or implemented. This is perhaps one of the most valuable ways someone could help out the project! If you are interested in developing content, reach out in the development channel of the Discord.
### Policy on Use of AI Tools
You, the contributor, agree to submit quality code to the best of your ability which you have tested yourself and confirmed that it works as intended, and if it doesnt work, you agree to take constructive feedback and fix it.
You should be able to explain or defend how any part of your code works, without the use of AI or any other assistive tools.
2009scape reserves the right to reject your MR on grounds of poor quality, poor functionality, poor code style, poor attitudes or unethical over-reliance on assistive tools.
2009scape reserves the right to bar an individual from contributing due to patterns of aforementioned behavior, and close or delete all future MRs or issues or suggestions from said person without given explanation.
AI may not be used to generate your MR description, your issue description, or any responses to any discourse present on the Gitlab at any time or in any fashion. If you use AI in any of these places, it will be assumed that your entire contribution is AI and that you have no clue how it functions, and the remainder of the policy outlined above will be applied to you immediately.
## Content Developers: Setting Up the Project. ## Content Developers: Setting Up the Project.
### GitLab Setup ### GitLab Setup
**Note: This allows you to commit changes to the main repo (with approval)! Also, always stay up to date with the most recent updates by pulling into your copy when 2009Scape updates!** **Note: This allows you to commit changes to the main repo (with approval)! Also, always stay up to date with the most recent updates by pulling into your copy when 2009Scape updates!**
@ -140,40 +125,6 @@ Start the game server with the included run script. Use `./run -h` for more info
Start the game server with `run-server.bat` Start the game server with `run-server.bat`
#### Browser WebSocket Transport
Enable the listener in `Server/worldprops/default.conf`:
```properties
websocket_enabled = true
websocket_port = 0
```
When `websocket_port = 0`, the listener uses `53594 + world_id`. For world `1`, that is `53595`.
Both plain WebSocket (`ws://`) and secure WebSocket (`wss://`) are supported. Use `ws://` for local HTTP testing. PWA requires HTTPS/WSS.
Enable WSS with a Java keystore:
```properties
websocket_tls_enabled = true
websocket_tls_keystore_path = "certs/dev-wss.p12"
websocket_tls_keystore_password = "<keystore-password>"
```
The keystore password is optional. Leave `websocket_tls_keystore_password` blank when using a PKCS12 file exported with an empty password:
```bash
openssl pkcs12 -export \
-in fullchain.pem \
-inkey privkey.pem \
-out certs/dev-wss.p12 \
-name websocket \
-passout pass:
```
For local WSS development, create a certificate for your hostname or LAN IP that the browser will use, then point the server at a PKCS12 keystore. For production, use a normal certificate from certbot. Plain WS does not require a certificate.
#### Docker #### Docker
Make sure [Docker Engine](https://docs.docker.com/engine/install/) & [Docker Compose](https://docs.docker.com/compose/install/) plugin are installed first: Make sure [Docker Engine](https://docs.docker.com/engine/install/) & [Docker Compose](https://docs.docker.com/compose/install/) plugin are installed first:

View file

@ -1,15 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Debug Server (Docker)" type="Remote">
<option name="USE_SOCKET_TRANSPORT" value="true" />
<option name="SERVER_MODE" value="false" />
<option name="SHMEM_ADDRESS" />
<option name="HOST" value="localhost" />
<option name="PORT" value="5005" />
<option name="AUTO_RESTART" value="false" />
<RunnerSettings RunnerId="Debug">
<option name="DEBUG_PORT" value="5005" />
<option name="LOCAL" value="false" />
</RunnerSettings>
<method v="2" />
</configuration>
</component>

View file

@ -0,0 +1,27 @@
<parsing>
<ObjectAction mode="add" id="1814" x="3090" y="3475" z="0" type="4" direction="nw"/>
<ObjectAction mode="add" id="2646" x="2445" y="3413" z="0" direction="nw"/>
<ObjectAction mode="add" id="2646" x="2447" y="3414" z="0" direction="e"/>
<ObjectAction mode="add" id="2646" x="2447" y="3421" z="0" direction="nw"/>
<ObjectAction mode="remove" id="37670" x="3292" y="3299" z="0"/>
<ObjectAction mode="add" id="37304" x="3292" y="3299" z="0"/>
<ObjectAction mode="add" id="20987" x="3821" y="2996" z="0"/>
<ObjectAction mode="remove" id="356" x="2804" y="3428" z="0"/>
<ObjectAction mode="add" id="356" x="2804" y="3428" 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"/>
<ObjectAction mode="add" id="39237" x="2957" y="3266" z="0" direction="n"/>
<ObjectAction mode="add" id="39245" x="2956" y="3270" z="0" direction="se"/>
<ObjectAction mode="add" id="39242" x="2955" y="3273" z="0" direction="w"/>
<ObjectAction mode="add" id="39241" x="2955" y="3274" z="0" />
<ObjectAction mode="add" id="20987" x="2821" y="2996" z="0" direction="s"/>
<ObjectAction mode="add" id="21301" x="2662" y="3162" z="0" direction="e"/>
<ObjectAction mode="add" id="4176" x="2629" y="3661" z="2" type="4" direction="e"/>
</parsing>

View file

@ -3080,11 +3080,5 @@
"replaceId": "38142", "replaceId": "38142",
"fence": "false", "fence": "false",
"metal": "false" "metal": "false"
},
{
"id": "40108",
"replaceId": "40109",
"fence": "false",
"metal": "false"
} }
] ]

File diff suppressed because it is too large Load diff

View file

@ -111,10 +111,6 @@
"item_id": "278", "item_id": "278",
"loc_data": "{1,2604,3358,0,50}-" "loc_data": "{1,2604,3358,0,50}-"
}, },
{
"item_id": "298",
"loc_data": "{1,2569,9897,0,50}-"
},
{ {
"item_id": "301", "item_id": "301",
"loc_data": "{1,2608,3397,0,90}-" "loc_data": "{1,2608,3397,0,90}-"
@ -149,7 +145,7 @@
}, },
{ {
"item_id": "444", "item_id": "444",
"loc_data": "{1,2732,3224,0,250}-{1,3231,3739,0,250}-{1,3236,3741,0,250}-{1,3195,9821,0,150}-" "loc_data": "{1,3231,3739,0,250}-{1,3236,3741,0,250}-{1,3195,9821,0,150}-"
}, },
{ {
"item_id": "480", "item_id": "480",
@ -269,7 +265,7 @@
}, },
{ {
"item_id": "995", "item_id": "995",
"loc_data": "{2,3234,3560,0,100}-{2,3106,3547,0,100}-{1,3104,3558,0,100}-{1,3106,3534,0,100}-{2,3101,3564,0,100}-{4,3103,3579,0,100}-{384,3224,3830,0,50}-{384,3220,3824,0,50}-{2,2772,4517,0,60}-{3,2770,4516,0,60}-{4,2771,4516,0,60}-{4,2772,4515,0,60}-{1,2909,9800,0,150}-{4,2912,9801,0,150}-{8,2910,9803,0,150}-{5,2907,9807,0,150}-{6,2913,9806,0,150}-{1,2922,9820,0,150}-{1,2934,9834,0,150}-{1,2917,9850,0,150}-{1,2914,9849,0,150}-{3,3195,9834,0,150}-{4,3195,9820,0,150}-{66,3191,9821,0,150}-{56,3190,9819,0,150}-{26,3188,9819,0,150}-{26,3188,9820,0,150}-{35,3189,9819,0,150}-{4,3088,9898,0,150}-{1,3088,9899,0,150}-{1,3091,9899,0,150}-" "loc_data": "{2,3234,3560,0,100}-{2,3106,3547,0,100}-{1,3104,3558,0,100}-{1,3106,3534,0,100}-{2,3101,3564,0,100}-{4,3103,3579,0,100}-{384,3224,3830,0,50}-{384,3220,3824,0,50}-{1,2909,9800,0,150}-{4,2912,9801,0,150}-{8,2910,9803,0,150}-{5,2907,9807,0,150}-{6,2913,9806,0,150}-{1,2922,9820,0,150}-{1,2934,9834,0,150}-{1,2917,9850,0,150}-{1,2914,9849,0,150}-{3,3195,9834,0,150}-{4,3195,9820,0,150}-{66,3191,9821,0,150}-{56,3190,9819,0,150}-{26,3188,9819,0,150}-{26,3188,9820,0,150}-{35,3189,9819,0,150}-{4,3088,9898,0,150}-{1,3088,9899,0,150}-{1,3091,9899,0,150}-"
}, },
{ {
"item_id": "1005", "item_id": "1005",
@ -327,21 +323,9 @@
"item_id": "1217", "item_id": "1217",
"loc_data": "{1,3180,3821,0,60}-" "loc_data": "{1,3180,3821,0,60}-"
}, },
{
"item_id": "1237",
"loc_data": "{1,2808,4572,0,60}-"
},
{ {
"item_id": "1265", "item_id": "1265",
"loc_data": "{1,3229,3218,2,100}-{1,2963,3216,0,30}-{1,3081,3429,0,50}-{1,2801,4513,0,60}-{1,2801,4493,0,60}-{1,2795,4579,0,60}-{1,2812,4572,0,60}-{1,3288,9442,0,90}-{1,3288,9431,0,90}-" "loc_data": "{1,3229,3218,2,100}-{1,2963,3216,0,30}-{1,3081,3429,0,50}-{1,3288,9442,0,90}-{1,3288,9431,0,90}-"
},
{
"item_id": "1267",
"loc_data": "{1,2770,4515,0,60}-"
},
{
"item_id": "1269",
"loc_data": "{1,2812,4571,0,60}-"
}, },
{ {
"item_id": "1321", "item_id": "1321",
@ -429,11 +413,7 @@
}, },
{ {
"item_id": "1755", "item_id": "1755",
"loc_data": "{1,2935,3286,0,90}-{1,2800,4500,0,60}-{1,2803,4491,0,60}-" "loc_data": "{1,2935,3286,0,90}-"
},
{
"item_id": "1773",
"loc_data": "{1,2563,3261,0,100}-"
}, },
{ {
"item_id": "1785", "item_id": "1785",
@ -691,10 +671,6 @@
"item_id": "7510", "item_id": "7510",
"loc_data": "{1,2867,9875,0,44}-" "loc_data": "{1,2867,9875,0,44}-"
}, },
{
"item_id": "10587",
"loc_data": "{1,3184,4634,0,60}-{1,3147,4666,0,60}-"
},
{ {
"item_id": "11065", "item_id": "11065",
"loc_data": "{1,2928,3289,0,90}-" "loc_data": "{1,2928,3289,0,90}-"

View file

@ -203,12 +203,6 @@
"walkable": "false", "walkable": "false",
"tabIndex": "-1" "tabIndex": "-1"
}, },
{
"id": "144",
"interfaceType": "1",
"walkable": "false",
"tabIndex": "-1"
},
{ {
"id": "149", "id": "149",
"interfaceType": "2", "interfaceType": "2",
@ -221,12 +215,6 @@
"walkable": "true", "walkable": "true",
"tabIndex": "-1" "tabIndex": "-1"
}, },
{
"id": "170",
"interfaceType": "1",
"walkable": "true",
"tabIndex": "-1"
},
{ {
"id": "172", "id": "172",
"interfaceType": "4", "interfaceType": "4",
@ -551,12 +539,6 @@
"walkable": "true", "walkable": "true",
"tabIndex": "-1" "tabIndex": "-1"
}, },
{
"id": "375",
"interfaceType": "3",
"walkable": "false",
"tabIndex": "-1"
},
{ {
"id": "377", "id": "377",
"interfaceType": "8", "interfaceType": "8",
@ -641,12 +623,6 @@
"walkable": "true", "walkable": "true",
"tabIndex": "6" "tabIndex": "6"
}, },
{
"id": "433",
"interfaceType": "3",
"walkable": "false",
"tabIndex": "-1"
},
{ {
"id": "464", "id": "464",
"interfaceType": "2", "interfaceType": "2",
@ -863,12 +839,6 @@
"walkable": "false", "walkable": "false",
"tabIndex": "-1" "tabIndex": "-1"
}, },
{
"id": "683",
"interfaceType": "3",
"walkable": "true",
"tabIndex": "-1"
},
{ {
"id": "695", "id": "695",
"interfaceType": "7", "interfaceType": "7",

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -157,7 +157,7 @@
}, },
{ {
"npc_id": "47", "npc_id": "47",
"loc_data": "{2821,3170,0,1,1}-{3076,3282,0,1,5}-{3089,3266,0,1,4}-{3091,3266,0,1,4}-{3341,3267,0,1,5}-{3097,3364,0,1,3}-{3102,3363,0,1,5}-{3127,3487,0,1,4}-{3125,3486,0,1,6}-{3127,3486,0,1,4}-{2339,9356,0,1,0}-{2354,9390,0,1,0}-{2361,9403,0,1,0}-{2362,9347,0,1,0}-{2603,9480,0,1,1}-{2600,9477,0,1,0}-{2579,9496,0,1,4}-{2580,9508,0,1,0}-{2571,9522,0,1,4}-{2565,9505,0,1,1}-{2566,9510,0,1,6}-{2594,9497,0,1,4}-{2852,9642,0,1,6}-{2858,9632,0,1,3}-{2568,9620,0,1,0}-{2573,9612,0,1,0}-{2579,9631,0,1,0}-{2580,9600,0,1,0}-{2580,9614,0,1,0}-{2580,9620,0,1,0}-{2580,9626,0,1,0}-{2583,9632,0,1,0}-{2584,9625,0,1,0}-{2584,9637,0,1,0}-{2589,9644,0,1,0}-{2590,9601,0,1,0}-{2590,9638,0,1,0}-{2591,9601,0,1,0}-{2591,9621,0,1,0}-{2594,9636,0,1,0}-{2594,9644,0,1,0}-{2597,9604,0,1,0}-{2607,9615,0,1,0}-{2608,9628,0,1,0}-{2614,9651,0,1,0}-{2614,9656,0,1,0}-{2615,9647,0,1,0}-{2615,9661,0,1,0}-{2616,9633,0,1,0}-{2618,9630,0,1,0}-{3108,9754,0,1,5}-{3110,9754,0,1,5}-{3108,9750,0,1,5}-{2592,9831,0,1,3}-{2588,9825,0,1,6}-{2583,9829,0,1,4}-{2581,9841,0,1,0}-{2597,9823,0,1,2}-{2579,9805,0,1,3}-{2576,9804,0,1,0}-{2573,9805,0,1,5}-{2571,9808,0,1,3}-{2576,9810,0,1,2}-{2587,9802,0,1,2}-{2592,9800,0,1,4}-{2596,9805,0,1,6}-{2601,9802,0,1,5}-{2585,9801,0,1,7}-{2594,9803,0,1,0}-{2590,9806,0,1,3}-{2612,9808,0,1,6}-{2604,9810,0,1,6}-{2579,9821,0,1,2}-{2576,9812,0,1,6}-{2580,9813,0,1,6}-{2600,9813,0,1,4}-{2599,9809,0,1,4}-{3158,3226,0,1,5}-{3160,3202,0,1,4}-{3192,3203,0,1,0}-{3194,3204,0,1,0}-{3196,3206,0,1,0}-{3197,3204,0,1,0}-{2654,9640,0,1,6}-{2655,9637,0,1,4}-{2656,9639,0,1,7}-{2651,9636,0,1,5}-{2648,9637,0,1,4}-{2651,9642,0,1,1}-{2654,9640,0,1,0}-{2654,9635,0,1,6}-{2655,9635,0,1,3}-{2664,9626,0,1,6}-{2664,9624,0,1,1}-{2661,9623,0,1,1}-{2663,9623,0,1,3}-{2664,9626,0,1,6}-{2930,9699,0,1,0}-{2933,9697,0,1,0}-{2932,9685,0,1,0}-{2930,9693,0,1,0}-{3001,3202,0,1,5}-{3235,3224,0,1,3}-{3229,3220,0,1,4}-{3211,3211,0,1,3}-{3225,3220,0,1,1}-{3237,3215,0,1,5}-{3211,3210,0,1,7}-{3227,3220,0,1,7}-{3233,3227,0,1,5}-{3227,3210,0,1,6}-{3228,3222,0,1,4}-{3229,3226,0,1,0}-{3236,3217,0,1,4}-{3259,3230,0,1,4}-{3233,3237,0,1,7}-{3205,3204,0,1,0}-{3206,3204,0,1,0}-{3205,3203,0,1,0}-{3206,3202,0,1,0}-{3207,3202,0,1,0}-{3208,3203,0,1,0}-{3243,3687,0,1,5}-{3249,3669,0,1,3}-{3252,3675,0,1,4}-{3252,3680,0,1,3}-{3259,3683,0,1,0}-{3475,9840,0,1,6}-{3481,9842,0,1,1}-{3486,9843,0,1,7}-{3483,9824,0,1,4}-{3490,9815,0,1,1}-{3490,9824,0,1,4}-{3478,9834,0,1,0}-{3496,9808,0,1,0}-{3225,9862,0,1,4}-{3222,9861,0,1,6}-{3220,9860,0,1,6}-{3219,9865,0,1,6}-{3237,9862,0,1,4}-{2536,2982,0,1,3}-{2531,2980,0,1,0}-{2522,2981,0,1,4}-{2545,2989,0,1,4}-{2523,2970,0,1,2}-{2801,3158,0,1,2}-{3026,3174,0,1,5}-{3019,3176,0,1,7}-{2514,3193,0,1,6}-{2518,3192,0,1,3}-{2507,3181,0,1,3}-{2508,3178,0,1,6}-{2511,3183,0,1,3}-{2515,3182,0,1,1}-{3021,3205,0,1,6}-{3019,3292,0,1,7}-{3018,3295,0,1,7}-{2531,3325,0,1,3}-{2530,3327,0,1,5}-{2521,3331,0,1,3}-{2526,3328,0,1,3}-{2523,3331,0,1,4}-{2523,3334,0,1,1}-{2531,3329,0,1,5}-{2532,3333,0,1,5}-{2798,4531,0,1,0}-{2800,4526,0,1,0}-{2803,4526,0,1,0}-{2780,4592,0,1,0}-{2783,4593,0,1,0}-{2777,4582,0,1,0}-{2785,4580,0,1,0}-{2786,4578,0,1,0}-{2787,4579,0,1,0}-{2812,4577,0,1,0}-{2802,4599,0,1,0}-{3276,9871,0,1,1}-{3277,9871,0,1,3}-" "loc_data": "{2821,3170,0,1,1}-{3076,3282,0,1,5}-{3089,3266,0,1,4}-{3091,3266,0,1,4}-{3341,3267,0,1,5}-{3097,3364,0,1,3}-{3102,3363,0,1,5}-{3127,3487,0,1,4}-{3125,3486,0,1,6}-{3127,3486,0,1,4}-{2339,9356,0,1,0}-{2354,9390,0,1,0}-{2361,9403,0,1,0}-{2362,9347,0,1,0}-{2603,9480,0,1,1}-{2600,9477,0,1,0}-{2579,9496,0,1,4}-{2580,9508,0,1,0}-{2571,9522,0,1,4}-{2565,9505,0,1,1}-{2566,9510,0,1,6}-{2594,9497,0,1,4}-{2852,9642,0,1,6}-{2858,9632,0,1,3}-{2568,9620,0,1,0}-{2573,9612,0,1,0}-{2579,9631,0,1,0}-{2580,9600,0,1,0}-{2580,9614,0,1,0}-{2580,9620,0,1,0}-{2580,9626,0,1,0}-{2583,9632,0,1,0}-{2584,9625,0,1,0}-{2584,9637,0,1,0}-{2589,9644,0,1,0}-{2590,9601,0,1,0}-{2590,9638,0,1,0}-{2591,9601,0,1,0}-{2591,9621,0,1,0}-{2594,9636,0,1,0}-{2594,9644,0,1,0}-{2597,9604,0,1,0}-{2607,9615,0,1,0}-{2608,9628,0,1,0}-{2614,9651,0,1,0}-{2614,9656,0,1,0}-{2615,9647,0,1,0}-{2615,9661,0,1,0}-{2616,9633,0,1,0}-{2618,9630,0,1,0}-{3108,9754,0,1,5}-{3110,9754,0,1,5}-{3108,9750,0,1,5}-{2592,9831,0,1,3}-{2588,9825,0,1,6}-{2583,9829,0,1,4}-{2581,9841,0,1,0}-{2597,9823,0,1,2}-{2579,9805,0,1,3}-{2576,9804,0,1,0}-{2573,9805,0,1,5}-{2571,9808,0,1,3}-{2576,9810,0,1,2}-{2587,9802,0,1,2}-{2592,9800,0,1,4}-{2596,9805,0,1,6}-{2601,9802,0,1,5}-{2585,9801,0,1,7}-{2594,9803,0,1,0}-{2590,9806,0,1,3}-{2612,9808,0,1,6}-{2604,9810,0,1,6}-{2579,9821,0,1,2}-{2576,9812,0,1,6}-{2580,9813,0,1,6}-{2600,9813,0,1,4}-{2599,9809,0,1,4}-{3158,3226,0,1,5}-{3160,3202,0,1,4}-{3192,3203,0,1,0}-{3194,3204,0,1,0}-{3196,3206,0,1,0}-{3197,3204,0,1,0}-{2654,9640,0,1,6}-{2655,9637,0,1,4}-{2656,9639,0,1,7}-{2651,9636,0,1,5}-{2648,9637,0,1,4}-{2651,9642,0,1,1}-{2654,9640,0,1,0}-{2654,9635,0,1,6}-{2655,9635,0,1,3}-{2664,9626,0,1,6}-{2664,9624,0,1,1}-{2661,9623,0,1,1}-{2663,9623,0,1,3}-{2664,9626,0,1,6}-{2930,9699,0,1,0}-{2933,9697,0,1,0}-{2932,9685,0,1,0}-{2930,9693,0,1,0}-{3235,3224,0,1,3}-{3229,3220,0,1,4}-{3211,3211,0,1,3}-{3225,3220,0,1,1}-{3237,3215,0,1,5}-{3211,3210,0,1,7}-{3227,3220,0,1,7}-{3233,3227,0,1,5}-{3227,3210,0,1,6}-{3228,3222,0,1,4}-{3229,3226,0,1,0}-{3236,3217,0,1,4}-{3259,3230,0,1,4}-{3233,3237,0,1,7}-{3205,3204,0,1,0}-{3206,3204,0,1,0}-{3205,3203,0,1,0}-{3206,3202,0,1,0}-{3207,3202,0,1,0}-{3208,3203,0,1,0}-{3001,3202,0,1,5}-{3243,3687,0,1,5}-{3249,3669,0,1,3}-{3252,3675,0,1,4}-{3252,3680,0,1,3}-{3259,3683,0,1,0}-{3475,9840,0,1,6}-{3481,9842,0,1,1}-{3486,9843,0,1,7}-{3483,9824,0,1,4}-{3496,9808,0,0,5}-{3490,9815,0,1,1}-{3478,9834,0,0,3}-{3490,9824,0,1,4}-{3225,9862,0,1,4}-{3222,9861,0,1,6}-{3220,9860,0,1,6}-{3219,9865,0,1,6}-{3237,9862,0,1,4}-{2536,2982,0,1,3}-{2531,2980,0,1,0}-{2522,2981,0,1,4}-{2545,2989,0,1,4}-{2523,2970,0,1,2}-{3026,3174,0,1,5}-{3019,3176,0,1,7}-{2801,3158,0,1,2}-{2514,3193,0,1,6}-{2518,3192,0,1,3}-{2507,3181,0,1,3}-{2508,3178,0,1,6}-{2511,3183,0,1,3}-{2515,3182,0,1,1}-{3021,3205,0,1,6}-{3019,3292,0,1,7}-{3018,3295,0,1,7}-{2531,3325,0,1,3}-{2530,3327,0,1,5}-{2521,3331,0,1,3}-{2526,3328,0,1,3}-{2523,3331,0,1,4}-{2523,3334,0,1,1}-{2531,3329,0,1,5}-{2532,3333,0,1,5}-{3276,9871,0,1,1}-{3277,9871,0,1,3}-"
}, },
{ {
"npc_id": "48", "npc_id": "48",
@ -245,7 +245,7 @@
}, },
{ {
"npc_id": "78", "npc_id": "78",
"loc_data": "{2585,3479,0,1,1}-{2589,3480,0,1,2}-{2582,3476,0,1,3}-{2588,3485,0,1,4}-{2580,3490,0,1,5}-{2577,3482,0,1,6}-{2583,3484,0,1,7}-{3073,3961,0,1,0}-{3074,3952,0,1,0}-{3075,3955,0,1,0}-{3076,3961,0,1,0}-{3077,3949,0,1,0}-{3079,3957,0,1,0}-{3080,3961,0,1,0}-{2568,9528,0,1,5}-{2573,9530,0,1,3}-{2575,9525,0,1,6}-{2571,9528,0,1,7}-{2862,9569,0,1,4}-{2857,9571,0,1,7}-{2837,9561,0,1,1}-{2608,9818,0,1,7}-{2609,9825,0,1,5}-{2607,9830,0,1,1}-{2605,9837,0,1,1}-{2607,9833,0,1,6}-{2905,9832,0,1,0}-{2907,9831,0,1,0}-{2913,9828,0,1,0}-{2921,9826,0,1,0}-{2924,9831,0,1,0}-{2921,9834,0,1,0}-{2918,9831,0,1,0}-{2908,9838,0,1,0}-{2913,9841,0,1,0}-{2672,9805,0,1,3}-{2663,9804,0,1,4}-{2658,9809,0,1,5}-{3725,9369,0,1,1}-{3737,9390,0,1,4}-{3738,9399,0,1,0}-{3740,9407,0,1,1}-{3765,9407,0,1,1}-{3762,9395,0,1,3}-{3725,9390,0,1,3}-{3753,9387,0,1,0}-{3728,9382,0,1,3}-{3729,9360,0,1,6}-{3755,9424,0,1,0}-{3760,9440,0,1,4}-{3737,9425,0,1,7}-{3720,9430,0,1,4}-{3736,9451,0,1,3}-{3728,9463,0,1,2}-{3740,9462,0,1,4}-{3770,9463,0,1,1}-{3752,9450,0,1,6}-{3762,9432,0,1,1}-{3733,9421,0,1,7}-{2759,3402,0,1,2}-{2756,3400,0,1,0}-{2788,4503,0,1,0}-{2789,4499,0,1,0}-{3787,9459,0,1,1}-{3803,9447,0,1,4}-{3778,9438,0,1,1}-{3786,9422,0,1,4}-{3800,9419,0,1,3}-{3797,9427,0,1,4}-{3820,9432,0,1,5}-{3825,9414,0,1,3}-{3833,9415,0,1,0}-{3825,9449,0,1,3}-{3827,9459,0,1,1}-{3818,9466,0,1,4}-{3799,9460,0,1,1}-{3794,9451,0,1,1}-{2543,9564,0,1,1}-{2543,9562,0,1,1}-{2542,9557,0,1,1}-{2542,9569,0,1,4}-{2540,9566,0,1,0}-{2549,9568,0,1,6}-{2538,9568,0,1,3}-" "loc_data": "{2585,3479,0,1,1}-{2589,3480,0,1,2}-{2582,3476,0,1,3}-{2588,3485,0,1,4}-{2580,3490,0,1,5}-{2577,3482,0,1,6}-{2583,3484,0,1,7}-{3073,3961,0,1,0}-{3074,3952,0,1,0}-{3075,3955,0,1,0}-{3076,3961,0,1,0}-{3077,3949,0,1,0}-{3079,3957,0,1,0}-{3080,3961,0,1,0}-{2568,9528,0,1,5}-{2573,9530,0,1,3}-{2575,9525,0,1,6}-{2571,9528,0,1,7}-{2862,9569,0,1,4}-{2857,9571,0,1,7}-{2837,9561,0,1,1}-{2608,9818,0,1,7}-{2609,9825,0,1,5}-{2607,9830,0,1,1}-{2605,9837,0,1,1}-{2607,9833,0,1,6}-{2905,9832,0,1,0}-{2907,9831,0,1,0}-{2913,9828,0,1,0}-{2921,9826,0,1,0}-{2924,9831,0,1,0}-{2921,9834,0,1,0}-{2918,9831,0,1,0}-{2908,9838,0,1,0}-{2913,9841,0,1,0}-{2672,9805,0,1,3}-{2663,9804,0,1,4}-{2658,9809,0,1,5}-{3725,9369,0,1,1}-{3737,9390,0,1,4}-{3738,9399,0,1,0}-{3740,9407,0,1,1}-{3765,9407,0,1,1}-{3762,9395,0,1,3}-{3725,9390,0,1,3}-{3753,9387,0,1,0}-{3728,9382,0,1,3}-{3729,9360,0,1,6}-{3755,9424,0,1,0}-{3760,9440,0,1,4}-{3737,9425,0,1,7}-{3720,9430,0,1,4}-{3736,9451,0,1,3}-{3728,9463,0,1,2}-{3740,9462,0,1,4}-{3770,9463,0,1,1}-{3752,9450,0,1,6}-{3762,9432,0,1,1}-{3733,9421,0,1,7}-{2759,3402,0,1,2}-{2756,3400,0,1,0}-{3787,9459,0,1,1}-{3803,9447,0,1,4}-{3778,9438,0,1,1}-{3786,9422,0,1,4}-{3800,9419,0,1,3}-{3797,9427,0,1,4}-{3820,9432,0,1,5}-{3825,9414,0,1,3}-{3833,9415,0,1,0}-{3825,9449,0,1,3}-{3827,9459,0,1,1}-{3818,9466,0,1,4}-{3799,9460,0,1,1}-{3794,9451,0,1,1}-{2543,9564,0,1,1}-{2543,9562,0,1,1}-{2542,9557,0,1,1}-{2542,9569,0,1,4}-{2540,9566,0,1,0}-{2549,9568,0,1,6}-{2538,9568,0,1,3}-"
}, },
{ {
"npc_id": "80", "npc_id": "80",
@ -269,7 +269,7 @@
}, },
{ {
"npc_id": "86", "npc_id": "86",
"loc_data": "{3105,9517,0,1,7}-{3101,9517,0,1,6}-{3102,9521,0,1,4}-{3106,9519,0,1,1}-{3104,9514,0,1,4}-{3104,9518,0,1,1}-{3107,9519,0,1,1}-{3109,9516,0,1,1}-{3107,9515,0,1,7}-{3105,9512,0,1,6}-{3102,9513,0,1,3}-{3100,9514,0,1,1}-{3100,9516,0,1,7}-{3099,9521,0,1,0}-{3103,9523,0,1,1}-{3098,9880,0,1,5}-{3094,9883,0,1,1}-{3119,9891,0,1,4}-{3188,3181,0,1,7}-{3181,3191,0,1,7}-{3185,3199,0,1,4}-{3176,3198,0,1,6}-{3168,3188,0,1,4}-{3172,3178,0,1,1}-{3179,3174,0,1,1}-{3189,3168,0,1,5}-{3196,3208,0,1,1}-{3196,3205,0,1,0}-{3195,3212,0,1,0}-{2632,9696,0,1,1}-{2639,9697,0,1,3}-{2646,9696,0,1,3}-{2650,9697,0,1,4}-{2646,9702,0,1,6}-{2647,9713,0,1,3}-{2641,9719,0,1,1}-{2650,9716,0,1,1}-{3212,3191,0,1,6}-{3207,3192,0,1,2}-{3216,3184,0,1,2}-{3224,3174,0,1,4}-{3229,3183,0,1,5}-{3222,3185,0,1,3}-{3216,3177,0,1,4}-{3200,3182,0,1,5}-{3202,3189,0,1,6}-{2977,3700,0,1,0}-{2967,3694,0,1,0}-{2973,3694,0,1,0}-{3495,9812,0,1,1}-{3502,9807,0,1,0}-{3249,9868,0,1,4}-{3237,9868,0,1,3}-{3221,9873,0,1,6}-{3225,9862,0,1,2}-{3237,9866,0,1,6}-{3232,9867,0,1,7}-{3219,9862,0,1,7}-{3227,9875,0,1,4}-{2518,3187,0,1,3}-{3291,3388,0,1,6}-{3049,3691,0,1,0}-{3276,9870,0,1,3}-" "loc_data": "{3105,9517,0,1,7}-{3101,9517,0,1,6}-{3102,9521,0,1,4}-{3106,9519,0,1,1}-{3104,9514,0,1,4}-{3104,9518,0,1,1}-{3107,9519,0,1,1}-{3109,9516,0,1,1}-{3107,9515,0,1,7}-{3105,9512,0,1,6}-{3102,9513,0,1,3}-{3100,9514,0,1,1}-{3100,9516,0,1,7}-{3099,9521,0,1,0}-{3103,9523,0,1,1}-{3098,9880,0,1,5}-{3094,9883,0,1,1}-{3119,9891,0,1,4}-{3188,3181,0,1,7}-{3181,3191,0,1,7}-{3185,3199,0,1,4}-{3176,3198,0,1,6}-{3168,3188,0,1,4}-{3172,3178,0,1,1}-{3179,3174,0,1,1}-{3189,3168,0,1,5}-{3196,3208,0,1,1}-{3196,3205,0,1,0}-{3195,3212,0,1,0}-{2632,9696,0,1,1}-{2639,9697,0,1,3}-{2646,9696,0,1,3}-{2650,9697,0,1,4}-{2646,9702,0,1,6}-{2647,9713,0,1,3}-{2641,9719,0,1,1}-{2650,9716,0,1,1}-{3212,3191,0,1,6}-{3207,3192,0,1,2}-{3216,3184,0,1,2}-{3224,3174,0,1,4}-{3229,3183,0,1,5}-{3222,3185,0,1,3}-{3216,3177,0,1,4}-{3200,3182,0,1,5}-{3202,3189,0,1,6}-{2977,3700,0,1,0}-{2967,3694,0,1,0}-{2973,3694,0,1,0}-{3495,9812,0,1,1}-{3502,9807,0,0,4}-{3249,9868,0,1,4}-{3237,9868,0,1,3}-{3221,9873,0,1,6}-{3225,9862,0,1,2}-{3237,9866,0,1,6}-{3232,9867,0,1,7}-{3219,9862,0,1,7}-{3227,9875,0,1,4}-{2518,3187,0,1,3}-{3291,3388,0,1,6}-{3049,3691,0,1,0}-{3276,9870,0,1,3}-"
}, },
{ {
"npc_id": "87", "npc_id": "87",
@ -297,7 +297,7 @@
}, },
{ {
"npc_id": "93", "npc_id": "93",
"loc_data": "{2566,9507,0,1,3}-{2562,9505,0,1,1}-{2568,9509,0,1,3}-{2571,9509,0,1,1}-{2564,9504,0,1,1}-{2566,9505,0,1,1}-{2841,9625,0,1,4}-{2845,9628,0,1,3}-{2841,9638,0,1,6}-{2845,9645,0,1,1}-{3101,9956,0,1,3}-{3104,9948,0,1,0}-{3104,9955,0,1,4}-{3108,9951,0,1,4}-{3108,9954,0,1,1}-{3111,9954,0,1,6}-{3112,9958,0,1,4}-{3194,5460,0,1,6}-{3192,5466,0,1,7}-{3185,5493,0,1,4}-{3182,5494,0,1,6}-{3185,5486,0,1,7}-{3175,5492,0,1,3}-{3169,5496,0,1,4}-{3170,5492,0,1,3}-{3186,5487,0,1,4}-{3169,5491,0,1,2}-{2655,9824,0,1,1}-{2669,9824,0,1,4}-{2667,9823,0,1,5}-{2658,9830,0,1,6}-{2666,9829,0,1,6}-{2637,9891,0,1,0}-{2645,9891,0,1,0}-{2653,9892,0,1,0}-{2653,9892,0,1,0}-{2544,9841,0,1,1}-{2536,9844,0,1,6}-{2530,9842,0,1,4}-{2543,9815,0,1,3}-" "loc_data": "{2566,9507,0,1,3}-{2562,9505,0,1,1}-{2568,9509,0,1,3}-{2571,9509,0,1,1}-{2564,9504,0,1,1}-{2566,9505,0,1,1}-{2841,9625,0,1,4}-{2845,9628,0,1,3}-{2841,9638,0,1,6}-{2845,9645,0,1,1}-{3101,9956,0,1,3}-{3104,9948,0,1,0}-{3104,9955,0,1,4}-{3108,9951,0,1,4}-{3108,9954,0,1,1}-{3111,9954,0,1,6}-{3112,9958,0,1,4}-{3194,5460,0,1,6}-{3192,5466,0,1,7}-{3185,5493,0,1,4}-{3182,5494,0,1,6}-{3185,5486,0,1,7}-{3175,5492,0,1,3}-{3169,5496,0,1,4}-{3170,5492,0,1,3}-{3186,5487,0,1,4}-{3169,5491,0,1,2}-{2655,9824,0,1,1}-{2669,9824,0,1,4}-{2667,9823,0,1,5}-{2658,9830,0,1,6}-{2666,9829,0,1,6}-{2637,9891,0,1,0}-{2645,9891,0,1,0}-{2653,9892,0,1,0}-{2653,9892,0,1,0}-{2544,9841,0,1,1}-{2536,9844,0,1,6}-{2527,9844,0,1,3}-{2530,9842,0,1,4}-{2543,9815,0,1,3}-"
}, },
{ {
"npc_id": "94", "npc_id": "94",
@ -373,11 +373,11 @@
}, },
{ {
"npc_id": "112", "npc_id": "112",
"loc_data": "{2825,3249,0,1,6}-{2560,3406,0,1,3}-{3144,3822,0,1,0}-{3165,9880,0,1,3}-{3168,9880,0,1,1}-{3159,9903,0,1,4}-{3156,9907,0,1,0}-{2699,3206,0,1,1}-{3202,5490,0,1,4}-{3237,5555,0,1,5}-{2554,3411,0,1,3}-{2554,3400,0,1,3}-{2551,3401,0,1,4}-" "loc_data": "{2825,3249,0,1,6}-{2560,3406,0,1,3}-{3144,3822,0,1,0}-{3165,9880,0,1,3}-{3168,9880,0,1,1}-{3159,9903,0,1,4}-{3156,9907,0,1,0}-{2699,3206,0,1,1}-{3202,5490,0,1,4}-{3237,5555,0,1,5}-{2554,3411,0,1,3}-{2554,3400,0,1,3}-{2551,3401,0,1,4}-{2543,9823,0,1,3}-{2540,9819,0,1,5}-{2543,9817,0,1,4}-"
}, },
{ {
"npc_id": "113", "npc_id": "113",
"loc_data": "{2622,3272,0,0,0}-{2835,9526,0,1,4}-{2832,9514,0,1,4}-{2825,9521,0,1,5}-{2846,9520,0,1,3}-{2838,9508,0,1,0}-{2832,9495,0,1,6}-{2838,9492,0,1,6}-{2851,9485,0,1,3}-{2847,9481,0,1,3}-{2865,9494,0,1,3}-{2855,9502,0,1,2}-{2870,9496,0,1,1}-{2851,9511,0,1,2}-{2853,9519,0,1,3}-{2857,9520,0,1,6}-{2863,9525,0,1,1}-{2869,9530,0,1,5}-{2865,9515,0,1,4}-{2868,9507,0,1,3}-{2874,9512,0,1,6}-{2896,2946,0,1,0}-{2918,2961,0,1,0}-{2926,2986,0,1,0}-{2930,3044,0,1,0}-{2926,3056,0,1,0}-{2916,3065,0,1,0}-" "loc_data": "{2622,3272,0,0,0}-{2835,9526,0,1,4}-{2832,9514,0,1,4}-{2825,9521,0,1,5}-{2846,9520,0,1,3}-{2838,9508,0,1,0}-{2832,9495,0,1,6}-{2838,9492,0,1,6}-{2851,9485,0,1,3}-{2847,9481,0,1,3}-{2865,9494,0,1,3}-{2855,9502,0,1,2}-{2870,9496,0,1,1}-{2851,9511,0,1,2}-{2853,9519,0,1,3}-{2857,9520,0,1,6}-{2863,9525,0,1,1}-{2869,9530,0,1,5}-{2865,9515,0,1,4}-{2868,9507,0,1,3}-{2874,9512,0,1,6}-{2896,2946,0,0,0}-{2918,2961,0,0,0}-{2926,2986,0,0,0}-{2930,3044,0,0,0}-{2926,3056,0,0,0}-{2916,3065,0,0,0}-"
}, },
{ {
"npc_id": "115", "npc_id": "115",
@ -1221,7 +1221,7 @@
}, },
{ {
"npc_id": "412", "npc_id": "412",
"loc_data": "{3341,3478,0,1,0}-{3343,3484,0,1,0}-{3345,3484,0,1,0}-{3350,3493,0,1,0}-{3353,3494,0,1,0}-{3361,3484,0,1,0}-{3364,3489,0,1,0}-{3370,3497,0,1,0}-{3379,3478,0,1,0}-{3379,3484,0,1,0}-{3387,3483,0,1,0}-{3388,3494,0,1,0}-{3389,3483,0,1,0}-{3588,3472,0,1,0}-{3598,3509,0,1,0}-{3599,3486,0,1,0}-{3607,3462,0,1,0}-{3611,3499,0,1,0}-{3613,3482,0,1,0}-{3627,3511,0,1,0}-{3628,3473,0,1,0}-{3636,3466,0,1,0}-{3639,3510,0,1,0}-{3411,3536,0,1,0}-{3418,3522,0,1,0}-{3425,3525,0,1,0}-{3429,3522,0,1,0}-{3432,3527,0,1,0}-{3434,3521,0,1,0}-{3445,3526,0,1,0}-{3419,9646,0,1,0}-{3418,9642,0,1,0}-{3414,9643,0,1,0}-{3411,9644,0,1,0}-{3410,9641,0,1,0}-{3409,9638,0,1,0}-{3419,9630,0,1,0}-{3421,9629,0,1,0}-{3433,9638,0,1,0}-{3434,9636,0,1,0}-{3436,9636,0,1,0}-{3423,9625,0,1,0}-{2728,10122,0,1,1}-{2735,10123,0,1,3}-{2733,10129,0,1,1}-{2728,10133,0,1,6}-{2722,10133,0,1,6}-{2736,10137,0,1,1}-{2732,10142,0,1,0}-{2726,10142,0,1,6}-{2729,10140,0,1,3}-{2720,10144,0,1,6}-{2712,10142,0,1,3}-{3565,3503,0,1,0}-{3567,3481,0,1,0}-{3580,3491,0,1,0}-{2761,4500,0,1,0}-{2759,4498,0,1,0}-{2761,4496,0,1,0}-{2783,4490,0,1,0}-{2784,4487,0,1,0}-{2792,4488,0,1,0}-" "loc_data": "{3341,3478,0,1,0}-{3343,3484,0,1,0}-{3345,3484,0,1,0}-{3350,3493,0,1,0}-{3353,3494,0,1,0}-{3361,3484,0,1,0}-{3364,3489,0,1,0}-{3370,3497,0,1,0}-{3379,3478,0,1,0}-{3379,3484,0,1,0}-{3387,3483,0,1,0}-{3388,3494,0,1,0}-{3389,3483,0,1,0}-{3588,3472,0,1,0}-{3598,3509,0,1,0}-{3599,3486,0,1,0}-{3607,3462,0,1,0}-{3611,3499,0,1,0}-{3613,3482,0,1,0}-{3627,3511,0,1,0}-{3628,3473,0,1,0}-{3636,3466,0,1,0}-{3639,3510,0,1,0}-{3411,3536,0,1,0}-{3418,3522,0,1,0}-{3425,3525,0,1,0}-{3429,3522,0,1,0}-{3432,3527,0,1,0}-{3434,3521,0,1,0}-{3445,3526,0,1,0}-{2728,10122,0,1,1}-{2735,10123,0,1,3}-{2733,10129,0,1,1}-{2728,10133,0,1,6}-{2722,10133,0,1,6}-{2736,10137,0,1,1}-{2732,10142,0,1,0}-{2726,10142,0,1,6}-{2729,10140,0,1,3}-{2720,10144,0,1,6}-{2712,10142,0,1,3}-{3565,3503,0,1,0}-{3567,3481,0,1,0}-{3580,3491,0,1,0}-"
}, },
{ {
"npc_id": "419", "npc_id": "419",
@ -1323,10 +1323,6 @@
"npc_id": "462", "npc_id": "462",
"loc_data": "{2590,3084,0,1,5}-" "loc_data": "{2590,3084,0,1,5}-"
}, },
{
"npc_id": "464",
"loc_data": "{2668,3162,0,1,0}-"
},
{ {
"npc_id": "469", "npc_id": "469",
"loc_data": "{2542,3169,0,1,4}-" "loc_data": "{2542,3169,0,1,4}-"
@ -2101,7 +2097,7 @@
}, },
{ {
"npc_id": "708", "npc_id": "708",
"loc_data": "{2595,3125,0,1,1}-{2601,3135,0,1,3}-{2598,3120,0,1,6}-{2615,3120,0,1,4}-{2598,3108,0,1,4}-{2865,3175,0,1,0}-{2855,3188,0,1,1}-{2838,3194,0,1,3}-{2827,3170,0,1,5}-{2598,3145,0,1,1}-{2588,3145,0,1,7}-{2603,3221,0,1,7}-{2604,3212,0,1,3}-{2612,3230,0,1,0}-{2611,3204,0,1,7}-{2942,3247,0,1,7}-{2627,3231,0,1,4}-{2932,3322,0,0,5}-{2934,3301,0,1,5}-{2934,3301,0,1,3}-{2935,3343,0,1,1}-{2941,3356,0,0,7}-{3162,3410,0,1,2}-{3189,3503,0,1,6}-{2977,3202,0,1,7}-{3219,3221,0,1,4}-{2997,3300,0,1,3}-{2957,3308,0,1,0}-{2973,3274,0,1,3}-{2994,3270,0,1,0}-{3215,3282,0,1,1}-{3242,3306,0,1,1}-{2980,3337,0,1,6}-{2977,3377,0,0,3}-{3208,3357,0,1,3}-{2962,3424,0,1,6}-{3240,3393,0,1,3}-{2715,3451,0,1,4}-{2715,3436,0,1,3}-{2733,3459,0,1,3}-{2732,3457,0,1,6}-{3239,3523,0,1,4}-{3262,3523,0,1,2}-{2806,3181,0,1,3}-{2788,3179,0,1,3}-{2753,3178,0,1,3}-{2759,3155,0,1,0}-{2544,3184,0,1,3}-{3068,3251,0,1,6}-{3031,3322,0,1,1}-{3010,3271,0,1,6}-{3011,3513,0,1,1}-" "loc_data": "{2595,3125,0,1,1}-{2601,3135,0,1,3}-{2598,3120,0,1,6}-{2615,3120,0,1,4}-{2598,3108,0,1,4}-{2865,3175,0,1,0}-{2855,3188,0,1,1}-{2838,3194,0,1,3}-{2827,3170,0,1,5}-{2598,3145,0,1,1}-{2588,3145,0,1,7}-{2603,3221,0,1,7}-{2604,3212,0,1,3}-{2612,3230,0,1,0}-{2611,3204,0,1,7}-{2942,3247,0,1,7}-{2627,3231,0,1,4}-{2932,3322,0,0,5}-{2934,3301,0,1,5}-{2934,3301,0,1,3}-{2935,3343,0,1,1}-{2941,3356,0,0,7}-{3162,3410,0,1,2}-{3189,3503,0,1,6}-{3219,3221,0,1,4}-{2977,3202,0,1,7}-{2997,3300,0,1,3}-{2957,3308,0,1,0}-{2973,3274,0,1,3}-{2994,3270,0,1,0}-{3215,3282,0,1,1}-{3242,3306,0,1,1}-{2980,3337,0,1,6}-{2977,3377,0,0,3}-{3208,3357,0,1,3}-{2962,3424,0,1,6}-{3240,3393,0,1,3}-{2715,3451,0,1,4}-{2715,3436,0,1,3}-{2733,3459,0,1,3}-{2732,3457,0,1,6}-{3239,3523,0,1,4}-{3262,3523,0,1,2}-{2806,3181,0,1,3}-{2788,3179,0,1,3}-{2753,3178,0,1,3}-{2759,3155,0,1,0}-{2544,3184,0,1,3}-{3068,3251,0,1,6}-{3031,3322,0,1,1}-{3010,3271,0,1,6}-{3011,3513,0,1,1}-"
}, },
{ {
"npc_id": "710", "npc_id": "710",
@ -2799,10 +2795,6 @@
"npc_id": "1013", "npc_id": "1013",
"loc_data": "{2593,2971,0,1,0}-{2594,2971,0,1,0}-{2596,2961,0,1,0}-{2598,2971,0,1,0}-{2599,2960,0,1,0}-{2598,2960,0,1,0}-{2603,2966,0,1,0}-{2603,2970,0,1,0}-{2598,2960,0,1,0}-{2596,2963,0,1,0}-{2595,2964,0,1,0}-{2594,2964,0,1,0}-{2601,2964,0,1,0}-{2598,2969,0,1,0}-{2604,2971,0,1,0}-{2601,2972,0,1,0}-{2392,3057,0,1,0}-{2395,3056,0,1,0}-{2395,3052,0,1,0}-{2397,3048,0,1,0}-{2400,3050,0,1,0}-{2400,3053,0,1,0}-{2391,3052,0,1,0}-{2393,3047,0,1,0}-{2399,3046,0,1,0}-{2402,3044,0,1,0}-{2399,3040,0,1,0}-{2395,3042,0,1,0}-{2391,3045,0,1,0}-{2464,2912,0,1,0}-{2544,2904,0,1,0}-{2544,2988,0,1,0}-{2532,2983,0,1,0}-{2549,2983,0,1,0}-{2545,2983,0,1,0}-{2528,2986,0,1,0}-{2550,2979,0,1,0}-{2522,2978,0,1,0}-{2523,2976,0,1,0}-{2526,2974,0,1,0}-{2548,2990,0,1,0}-{2552,2988,0,1,0}-{2548,2979,0,1,0}-{2547,2991,0,1,0}-{2525,2975,0,1,0}-" "loc_data": "{2593,2971,0,1,0}-{2594,2971,0,1,0}-{2596,2961,0,1,0}-{2598,2971,0,1,0}-{2599,2960,0,1,0}-{2598,2960,0,1,0}-{2603,2966,0,1,0}-{2603,2970,0,1,0}-{2598,2960,0,1,0}-{2596,2963,0,1,0}-{2595,2964,0,1,0}-{2594,2964,0,1,0}-{2601,2964,0,1,0}-{2598,2969,0,1,0}-{2604,2971,0,1,0}-{2601,2972,0,1,0}-{2392,3057,0,1,0}-{2395,3056,0,1,0}-{2395,3052,0,1,0}-{2397,3048,0,1,0}-{2400,3050,0,1,0}-{2400,3053,0,1,0}-{2391,3052,0,1,0}-{2393,3047,0,1,0}-{2399,3046,0,1,0}-{2402,3044,0,1,0}-{2399,3040,0,1,0}-{2395,3042,0,1,0}-{2391,3045,0,1,0}-{2464,2912,0,1,0}-{2544,2904,0,1,0}-{2544,2988,0,1,0}-{2532,2983,0,1,0}-{2549,2983,0,1,0}-{2545,2983,0,1,0}-{2528,2986,0,1,0}-{2550,2979,0,1,0}-{2522,2978,0,1,0}-{2523,2976,0,1,0}-{2526,2974,0,1,0}-{2548,2990,0,1,0}-{2552,2988,0,1,0}-{2548,2979,0,1,0}-{2547,2991,0,1,0}-{2525,2975,0,1,0}-"
}, },
{
"npc_id": "1015",
"loc_data": "{2716,4443,0,0,0}-{2719,4442,0,0,0}-{2724,4442,0,0,0}-{2729,4447,0,0,0}-{2728,4445,0,0,0}-{2735,4435,0,0,0}-{2738,4439,0,0,0}-{2713,4438,0,0,0}-{2792,4597,0,0,0}-{2785,4594,0,0,0}-{2783,4591,0,0,0}-{2774,4592,0,0,0}-{2770,4591,0,0,0}-{2769,4593,0,0,0}-"
},
{ {
"npc_id": "1017", "npc_id": "1017",
"loc_data": "{3191,3277,0,1,0}-{3188,3279,0,1,0}-{3187,3277,0,1,0}-{3190,3278,0,1,0}-{3187,3277,0,1,0}-{3189,3278,0,1,3}-{3198,3359,0,1,0}-{3198,3355,0,1,0}-{2677,3656,0,1,2}-{2672,3654,0,1,2}-{2676,3652,0,1,4}-{2681,3652,0,1,4}-{2675,3652,0,1,3}-{3231,3296,0,1,6}-{3233,3300,0,1,4}-{3235,3293,0,1,3}-{3232,3288,0,1,0}-{3234,3298,0,1,6}-{3234,3297,0,1,3}-{3234,3292,0,1,4}-{3235,3289,0,1,1}-{2693,3271,0,1,3}-{2692,3272,0,1,3}-{2785,3069,0,1,4}-{2800,3072,0,1,6}-" "loc_data": "{3191,3277,0,1,0}-{3188,3279,0,1,0}-{3187,3277,0,1,0}-{3190,3278,0,1,0}-{3187,3277,0,1,0}-{3189,3278,0,1,3}-{3198,3359,0,1,0}-{3198,3355,0,1,0}-{2677,3656,0,1,2}-{2672,3654,0,1,2}-{2676,3652,0,1,4}-{2681,3652,0,1,4}-{2675,3652,0,1,3}-{3231,3296,0,1,6}-{3233,3300,0,1,4}-{3235,3293,0,1,3}-{3232,3288,0,1,0}-{3234,3298,0,1,6}-{3234,3297,0,1,3}-{3234,3292,0,1,4}-{3235,3289,0,1,1}-{2693,3271,0,1,3}-{2692,3272,0,1,3}-{2785,3069,0,1,4}-{2800,3072,0,1,6}-"
@ -3409,7 +3401,7 @@
}, },
{ {
"npc_id": "1223", "npc_id": "1223",
"loc_data": "{3585,3478,0,1,0}-{3586,3480,0,1,0}-{3586,3496,0,1,0}-{3592,3477,0,1,0}-{3593,3458,0,1,0}-{3593,3508,0,1,0}-{3595,3491,0,1,0}-{3597,3479,0,1,0}-{3607,3466,0,1,0}-{3617,3477,0,1,0}-{3618,3514,0,1,0}-{3631,3471,0,1,0}-{3631,3499,0,1,0}-{3632,3459,0,1,0}-{3632,3475,0,1,0}-{3638,3472,0,1,0}-{3646,3467,0,1,0}-{3460,3241,0,1,0}-{3459,3237,0,1,0}-{3456,3234,0,1,0}-{3458,3230,0,1,0}-{3457,3227,0,1,0}-{3456,3223,0,1,0}-" "loc_data": "{3585,3478,0,1,0}-{3586,3480,0,1,0}-{3586,3496,0,1,0}-{3592,3477,0,1,0}-{3593,3458,0,1,0}-{3593,3508,0,1,0}-{3595,3491,0,1,0}-{3597,3479,0,1,0}-{3607,3466,0,1,0}-{3617,3477,0,1,0}-{3618,3514,0,1,0}-{3631,3471,0,1,0}-{3631,3499,0,1,0}-{3632,3459,0,1,0}-{3632,3475,0,1,0}-{3638,3472,0,1,0}-{3646,3467,0,1,0}-"
}, },
{ {
"npc_id": "1227", "npc_id": "1227",
@ -3661,39 +3653,31 @@
}, },
{ {
"npc_id": "1335", "npc_id": "1335",
"loc_data": "{2518,4633,0,0,1}" "loc_data": "{2518,4633,0,1,1}-"
}, },
{ {
"npc_id": "1336", "npc_id": "1336",
"loc_data": "{2508,3635,0,1,3}" "loc_data": "{2508,3635,0,1,3}-"
}, },
{ {
"npc_id": "1337", "npc_id": "1337",
"loc_data": "{2445,4599,0,1,3}" "loc_data": "{2445,4599,1,1,3}-"
}, },
{ {
"npc_id": "1338", "npc_id": "1338",
"loc_data": "{3151,5559,0,1,2}-{3157,5548,0,1,3}-{3155,5553,0,1,4}-{3145,5559,0,1,6}-{3152,5556,0,1,3}-{3149,5544,0,1,0}-{3145,5548,0,1,3}-{2514,10012,0,1,3}-{2515,10016,0,1,2}-{2519,10031,0,1,4}-{2527,10024,0,1,3}" "loc_data": "{3151,5559,0,1,2}-{3157,5548,0,1,3}-{3155,5553,0,1,4}-{3145,5559,0,1,6}-{3152,5556,0,1,3}-{3149,5544,0,1,0}-{3145,5548,0,1,3}-"
}, },
{ {
"npc_id": "1339", "npc_id": "1339",
"loc_data": "{3153,5547,0,1,0}-{3150,5545,0,1,1}-{2521,10015,0,1,1}-{2523,10019,0,1,3}-{2514,10027,0,1,2}-{2534,10025,0,1,4}" "loc_data": "{3153,5547,0,1,0}-{3150,5545,0,1,1}-"
}, },
{ {
"npc_id": "1340", "npc_id": "1340",
"loc_data": "{3147,5557,0,1,3}-{3154,5559,0,1,4}-{2511,10020,0,1,3}-{2526,10035,0,1,1}-{2522,10028,0,1,4}-" "loc_data": "{3147,5557,0,1,3}-{3154,5559,0,1,4}-"
},
{
"npc_id": "1341",
"loc_data": "{2518,10013,0,1,6}-{2520,10018,0,1,4}-{2515,10030,0,1,3}-{2532,10023,0,1,2}"
},
{
"npc_id": "1342",
"loc_data": "{2524,10014,0,1,6}-{2527,10019,0,1,2}-{2518,10027,0,1,4}-{2535,10030,0,1,1}"
}, },
{ {
"npc_id": "1343", "npc_id": "1343",
"loc_data": "{3145,5548,0,1,6}-{2512,10018,0,1,4}-{2524,10033,0,1,2}-{2522,10023,0,1,3}-" "loc_data": "{3145,5548,0,1,6}-"
}, },
{ {
"npc_id": "1357", "npc_id": "1357",
@ -3887,46 +3871,10 @@
"npc_id": "1526", "npc_id": "1526",
"loc_data": "{2443,3089,0,0,0}-" "loc_data": "{2443,3089,0,0,0}-"
}, },
{
"npc_id": "1528",
"loc_data": "{3443,3256,0,1,0}-"
},
{
"npc_id": "1537",
"loc_data": "{2803,4595,0,0,0}-{2786,4571,0,1,0}-{2792,4567,0,1,0}-{2791,4560,0,1,0}-{2796,4587,0,1,0}-{2798,4592,0,1,0}-{2802,4591,0,1,0}-{2798,4597,0,1,0}-{2808,4598,0,1,0}-{2808,4601,0,1,0}-"
},
{
"npc_id": "1538",
"loc_data": "{2804,4525,0,0,0}-{2772,4516,0,0,0}-{2773,4515,0,0,0}-{2801,4580,0,0,0}-{2802,4580,0,0,0}-{2800,4573,0,0,0}-{2807,4572,0,0,0}-{2810,4573,0,0,0}-{2813,4571,0,0,0}-{2811,4567,0,0,0}-"
},
{
"npc_id": "1542",
"loc_data": "{2793,4458,0,0,7}-{2782,4458,0,0,2}-{2787,4451,0,0,1}-{2787,4446,0,0,2}-"
},
{
"npc_id": "1543",
"loc_data": "{2788,4455,0,0,0}-"
},
{ {
"npc_id": "1544", "npc_id": "1544",
"loc_data": "{2911,10175,0,0,4}-{2912,10175,0,0,4}-{2913,10175,0,0,4}-{2914,10175,0,0,4}-{2909,10173,0,0,4}-{2910,10173,0,0,4}-{2911,10173,0,0,4}-{2912,10173,0,0,4}-{2913,10173,0,0,4}-{2909,10171,0,0,4}-{2910,10171,0,0,4}-{2911,10169,0,0,4}-{2912,10169,0,0,4}-{2913,10169,0,0,4}-" "loc_data": "{2911,10175,0,0,4}-{2912,10175,0,0,4}-{2913,10175,0,0,4}-{2914,10175,0,0,4}-{2909,10173,0,0,4}-{2910,10173,0,0,4}-{2911,10173,0,0,4}-{2912,10173,0,0,4}-{2913,10173,0,0,4}-{2909,10171,0,0,4}-{2910,10171,0,0,4}-{2911,10169,0,0,4}-{2912,10169,0,0,4}-{2913,10169,0,0,4}-"
}, },
{
"npc_id": "1545",
"loc_data": "{2727,4509,0,0,1}-"
},
{
"npc_id": "1546",
"loc_data": "{2697,4498,0,0,4}-"
},
{
"npc_id": "1547",
"loc_data": "{2715,4517,0,0,1}-"
},
{
"npc_id": "1548",
"loc_data": "{2739,4528,0,0,1}-"
},
{ {
"npc_id": "1553", "npc_id": "1553",
"loc_data": "{2828,10065,1,0,0}-" "loc_data": "{2828,10065,1,0,0}-"
@ -3971,38 +3919,6 @@
"npc_id": "1566", "npc_id": "1566",
"loc_data": "{2786,10199,0,1,0}-{2790,10222,0,1,0}-{2799,10214,0,1,0}-" "loc_data": "{2786,10199,0,1,0}-{2790,10222,0,1,0}-{2799,10214,0,1,0}-"
}, },
{
"npc_id": "1567",
"loc_data": "{3521,3284,0,1,0}-"
},
{
"npc_id": "1568",
"loc_data": "{3507,3437,0,1,0}-"
},
{
"npc_id": "1569",
"loc_data": "{3506,9838,0,0,4}-{3506,9838,2,0,4}-"
},
{
"npc_id": "1570",
"loc_data": "{3508,9837,2,0,3}-"
},
{
"npc_id": "1571",
"loc_data": "{3504,9837,2,0,4}-"
},
{
"npc_id": "1572",
"loc_data": "{3512,9834,0,1,0}-{3512,9834,2,1,0}-"
},
{
"npc_id": "1573",
"loc_data": "{3513,9838,0,1,0}-{3513,9838,2,1,0}-"
},
{
"npc_id": "1574",
"loc_data": "{3512,9842,0,1,0}-{3512,9842,2,1,0}-"
},
{ {
"npc_id": "1582", "npc_id": "1582",
"loc_data": "{2568,9889,0,1,6}-{2578,9898,0,1,1}-{2657,9500,0,0,1}-{2632,9589,2,0,1}-{2628,9549,2,0,5}-{2629,9543,2,0,2}-{3249,5517,0,1,3}-" "loc_data": "{2568,9889,0,1,6}-{2578,9898,0,1,1}-{2657,9500,0,0,1}-{2632,9589,2,0,1}-{2628,9549,2,0,5}-{2629,9543,2,0,2}-{3249,5517,0,1,3}-"
@ -4227,26 +4143,6 @@
"npc_id": "1658", "npc_id": "1658",
"loc_data": "{2595,3087,1,1,1}-" "loc_data": "{2595,3087,1,1,1}-"
}, },
{
"npc_id": "1660",
"loc_data": "{3549,9867,0,0,6}-"
},
{
"npc_id": "1661",
"loc_data": "{3540,9873,0,0,1}-"
},
{
"npc_id": "1662",
"loc_data": "{3554,9886,0,1,0}-{3560,9908,0,1,0}-{3565,9865,0,1,0}-{3572,9908,0,1,0}-{3573,9891,0,1,0}-{3577,9875,0,1,0}-"
},
{
"npc_id": "1663",
"loc_data": "{3527,9909,0,1,0}-{3533,9912,0,1,0}-{3540,9892,0,1,0}-{3540,9902,0,1,0}-"
},
{
"npc_id": "1664",
"loc_data": "{3528,9865,0,1,0}-"
},
{ {
"npc_id": "1665", "npc_id": "1665",
"loc_data": "{3544,3462,0,0,1}-" "loc_data": "{3544,3462,0,0,1}-"
@ -4293,7 +4189,7 @@
}, },
{ {
"npc_id": "1681", "npc_id": "1681",
"loc_data": "{3202,5483,0,1,4}-{2544,9843,0,1,3}-{2528,9844,0,1,4}-{2543,9820,0,1,1}-" "loc_data": "{3202,5483,0,1,4}-{2544,9843,0,1,3}-"
}, },
{ {
"npc_id": "1683", "npc_id": "1683",
@ -4433,7 +4329,7 @@
}, },
{ {
"npc_id": "1770", "npc_id": "1770",
"loc_data": "{2595,9826,0,1,1}-{3189,3246,0,1,0}-{3143,3231,0,1,0}-{3140,3263,0,1,0}-{2999,3212,0,1,1}-{3262,3253,0,1,6}-{3259,3254,0,1,3}-" "loc_data": "{2595,9826,0,1,1}-{3189,3246,0,1,0}-{3143,3231,0,1,0}-{3140,3263,0,1,0}-{3262,3253,0,1,6}-{3259,3254,0,1,3}-{2999,3212,0,1,1}-"
}, },
{ {
"npc_id": "1771", "npc_id": "1771",
@ -4441,11 +4337,11 @@
}, },
{ {
"npc_id": "1772", "npc_id": "1772",
"loc_data": "{3194,3255,0,1,0}-{3143,3234,0,1,0}-{2993,3203,0,1,0}-{3251,3231,0,1,1}-{3260,3241,0,1,0}-{3259,3222,0,0,4}-" "loc_data": "{3194,3255,0,1,0}-{3143,3234,0,1,0}-{3251,3231,0,1,1}-{3260,3241,0,1,0}-{3259,3222,0,0,4}-{2993,3203,0,1,0}-"
}, },
{ {
"npc_id": "1773", "npc_id": "1773",
"loc_data": "{2991,3219,0,1,1}-{3252,3227,0,1,1}-{3263,3219,0,1,0}-" "loc_data": "{3252,3227,0,1,1}-{3263,3219,0,1,0}-{2991,3219,0,1,1}-"
}, },
{ {
"npc_id": "1774", "npc_id": "1774",
@ -4853,7 +4749,7 @@
}, },
{ {
"npc_id": "1973", "npc_id": "1973",
"loc_data": "{3166,4598,0,1,0}-{3167,4577,0,1,0}-{2626,5065,0,1,0}-{2637,5099,0,1,0}-{2638,5058,0,1,0}-{2644,5090,0,1,0}-{2658,5082,0,1,0}-{2666,5097,0,1,0}-{2680,5074,0,1,0}-{2693,5075,0,1,0}-{2695,5089,0,1,0}-{2697,5096,0,1,0}-{2703,5064,0,1,0}-{2710,5105,0,1,0}-{2719,5078,0,1,0}-{2719,5112,0,1,0}-{2720,5096,0,1,0}-{2726,5086,0,1,0}-{2729,5096,0,1,0}-{2735,5061,0,1,0}-{2740,5069,0,1,0}-{2740,5085,0,1,0}-{2746,5092,0,1,0}-{2746,5114,0,1,0}-" "loc_data": "{2626,5065,0,1,0}-{2637,5099,0,1,0}-{2638,5058,0,1,0}-{2644,5090,0,1,0}-{2658,5082,0,1,0}-{2666,5097,0,1,0}-{2680,5074,0,1,0}-{2693,5075,0,1,0}-{2695,5089,0,1,0}-{2697,5096,0,1,0}-{2703,5064,0,1,0}-{2710,5105,0,1,0}-{2719,5078,0,1,0}-{2719,5112,0,1,0}-{2720,5096,0,1,0}-{2726,5086,0,1,0}-{2729,5096,0,1,0}-{2735,5061,0,1,0}-{2740,5069,0,1,0}-{2740,5085,0,1,0}-{2746,5092,0,1,0}-{2746,5114,0,1,0}-"
}, },
{ {
"npc_id": "1976", "npc_id": "1976",
@ -6055,14 +5951,6 @@
"npc_id": "2580", "npc_id": "2580",
"loc_data": "{2918,3535,0,1,0}-" "loc_data": "{2918,3535,0,1,0}-"
}, },
{
"npc_id": "2581",
"loc_data": "{3228,3477,0,1,0}-"
},
{
"npc_id": "2588",
"loc_data": "{3049,3505,0,1,0}-"
},
{ {
"npc_id": "2591", "npc_id": "2591",
"loc_data": "{4786,5106,0,1,6}-{2474,5145,0,1,2}-" "loc_data": "{4786,5106,0,1,6}-{2474,5145,0,1,2}-"
@ -6777,7 +6665,7 @@
}, },
{ {
"npc_id": "3108", "npc_id": "3108",
"loc_data": "{2549,3100,0,1,4}-" "loc_data": "{2549,3100,0,0,4}-"
}, },
{ {
"npc_id": "3109", "npc_id": "3109",
@ -6785,11 +6673,11 @@
}, },
{ {
"npc_id": "3110", "npc_id": "3110",
"loc_data": "{2788,3176,0,0,6}-" "loc_data": "{2789,3175,0,0,4}-"
}, },
{ {
"npc_id": "3111", "npc_id": "3111",
"loc_data": "{2788,3176,0,0,6}-" "loc_data": "{2788,3176,0,0,0}-"
}, },
{ {
"npc_id": "3114", "npc_id": "3114",
@ -9213,7 +9101,11 @@
}, },
{ {
"npc_id": "5383", "npc_id": "5383",
"loc_data": "{3194,4569,0,1,0}-" "loc_data": "{3194,4569,0,0,0}-"
},
{
"npc_id": "5384",
"loc_data": "{3165,4598,0,0,0}-{3167,4577,0,0,0}-"
}, },
{ {
"npc_id": "5385", "npc_id": "5385",
@ -9317,19 +9209,11 @@
}, },
{ {
"npc_id": "5413", "npc_id": "5413",
"loc_data": "{3187,5450,0,1,6}-{3177,5453,0,1,6}-{3423,9658,0,1,0}-" "loc_data": "{3187,5450,0,1,6}-{3177,5453,0,1,6}-"
}, },
{ {
"npc_id": "5414", "npc_id": "5414",
"loc_data": "{3176,5454,0,1,3}-{3182,5447,0,1,3}-{3429,9648,0,1,0}-{3420,9657,0,1,0}-" "loc_data": "{3176,5454,0,1,3}-{3182,5447,0,1,3}-"
},
{
"npc_id": "5417",
"loc_data": "{3146,4649,0,1,0}-{3148,4645,0,1,0}-{3152,4648,0,1,0}-"
},
{
"npc_id": "5418",
"loc_data": "{3140,4653,0,1,0}-{3140,4647,0,1,0}-{3158,4647,0,1,0}-{3158,4653,0,1,0}-{3147,4657,0,1,0}-{3150,4654,0,1,0}-"
}, },
{ {
"npc_id": "5423", "npc_id": "5423",
@ -11481,7 +11365,7 @@
}, },
{ {
"npc_id": "6917", "npc_id": "6917",
"loc_data": "{2916,3082,0,1,0}-{2917,3089,0,1,0}-{2912,3090,0,1,0}-" "loc_data": "{2916,3082,0,0,0}-{2917,3089,0,0,0}-{2912,3090,0,0,0}-"
}, },
{ {
"npc_id": "6918", "npc_id": "6918",
@ -11489,11 +11373,15 @@
}, },
{ {
"npc_id": "6921", "npc_id": "6921",
"loc_data": "{2954,3273,0,1,6}-{2970,3300,0,1,0}-{2974,3448,0,1,4}-{2971,3442,0,1,6}-{2968,3451,0,1,1}-{2967,3439,0,1,4}-{2965,3451,0,1,5}-{3017,3402,0,1,0}-{3024,3405,0,1,0}-{3313,3440,0,1,0}-" "loc_data": "{2954,3273,0,1,6}-{2974,3448,0,1,4}-{2971,3442,0,1,6}-{2968,3451,0,1,1}-{2967,3439,0,1,4}-{2965,3451,0,1,5}-"
},
{
"npc_id": "6942",
"loc_data": "{2890,3100,0,1,4}-"
}, },
{ {
"npc_id": "6944", "npc_id": "6944",
"loc_data": "{2855,3028,0,1,0}-{2841,3039,0,1,0}-{2838,3031,0,1,0}-{2839,3022,0,1,0}-{2836,3014,0,1,0}-{2840,3008,0,1,0}-" "loc_data": "{2855,3028,0,0,0}-{2841,3039,0,0,0}-{2838,3031,0,0,0}-{2836,3014,0,0,0}-{2839,3022,0,0,0}-"
}, },
{ {
"npc_id": "6962", "npc_id": "6962",
@ -11565,7 +11453,7 @@
}, },
{ {
"npc_id": "6997", "npc_id": "6997",
"loc_data": "{2927,3382,0,1,0}-{2931,3378,0,1,0}-{3007,3261,0,1,0}-{3002,3257,0,1,0}-{3049,3429,0,1,0}-{3058,3429,0,1,0}-{3059,3425,0,1,0}-{3059,3420,0,1,0}-{3309,3420,0,1,0}-{3305,3423,0,1,0}-" "loc_data": "{3002,3257,0,0,0}-{3007,3261,0,0,0}-{3058,3429,0,0,0}-{3059,3420,0,0,0}-{3059,3425,0,0,0}-{3049,3429,0,0,0}-"
}, },
{ {
"npc_id": "7003", "npc_id": "7003",
@ -12033,63 +11921,59 @@
}, },
{ {
"npc_id": "7228", "npc_id": "7228",
"loc_data": "{2862,3101,0,1,0}-{2874,3098,0,1,0}-{2879,3109,0,1,0}-{2882,3104,0,1,0}-{2882,3098,0,1,0}-{2890,3100,0,1,0}-" "loc_data": "{2862,3101,0,0,0}-{2879,3109,0,0,0}-{2874,3098,0,0,0}-{2882,3104,0,0,0}-{2882,3098,0,0,0}-"
}, },
{ {
"npc_id": "7229", "npc_id": "7229",
"loc_data": "{2831,3086,0,1,0}-{2833,3089,0,1,0}-{2844,3089,0,1,0}-{2836,3085,0,1,0}-{2840,3076,0,1,0}-" "loc_data": "{2833,3088,0,0,0}-{2830,3085,0,0,0}-{2844,3089,0,0,0}-{2837,3084,0,0,0}-{2840,3076,0,0,0}-"
}, },
{ {
"npc_id": "7230", "npc_id": "7230",
"loc_data": "{2887,3051,0,1,0}-{2890,3052,0,1,0}-{2894,3058,0,1,0}-{2897,3035,0,1,0}-" "loc_data": "{2840,3008,0,0,0}-{2887,3051,0,0,0}-{2890,3052,0,0,0}-{2894,3058,0,0,0}-{2897,3035,0,0,0}-"
}, },
{ {
"npc_id": "7231", "npc_id": "7231",
"loc_data": "{2930,2961,0,1,0}-{2942,2964,0,1,0}-{2933,2964,0,1,0}-{2932,2967,0,1,0}-{2936,2973,0,1,0}-" "loc_data": "{2930,2961,0,0,0}-{2942,2964,0,0,0}-{2933,2964,0,0,0}-{2932,2967,0,0,0}-{2936,2973,0,0,0}-"
}, },
{ {
"npc_id": "7232", "npc_id": "7232",
"loc_data": "{2802,3106,0,1,0}-{2806,3108,0,1,0}-{2808,3106,0,1,0}-{2807,3101,0,1,0}-{2814,3100,0,1,0}-" "loc_data": "{2802,3106,0,0,0}-{2807,3101,0,0,0}-{2806,3108,0,0,0}-{2808,3105,0,0,0}-{2814,3100,0,0,0}-"
}, },
{ {
"npc_id": "7233", "npc_id": "7233",
"loc_data": "{2922,3070,0,1,0}-{2919,3080,0,1,0}-{2924,3080,0,1,0}-{2923,3081,0,1,0}-{2929,3075,0,1,0}-" "loc_data": "{2922,3070,0,0,0}-{2929,3075,0,0,0}-{2919,3080,0,0,0}-{2924,3080,0,0,0}-{2923,3081,0,0,0}-"
}, },
{ {
"npc_id": "7234", "npc_id": "7234",
"loc_data": "{2900,3107,0,1,0}-{2904,3107,0,1,0}-{2905,3107,0,1,0}-{2908,3104,0,1,0}-{2902,3101,0,1,0}-{2903,3098,0,1,0}-" "loc_data": "{2900,3107,0,0,0}-{2903,3098,0,0,0}-{2908,3104,0,0,0}-{2905,3107,0,0,0}-{2904,3107,0,0,0}-"
}, },
{ {
"npc_id": "7235", "npc_id": "7235",
"loc_data": "{2820,3065,0,1,0}-{2830,3059,0,1,0}-{2825,3057,0,1,0}-{2827,3050,0,1,0}-{2822,3053,0,1,0}-" "loc_data": "{2820,3065,0,0,0}-{2830,3059,0,0,0}-{2825,3057,0,0,0}-{2827,3050,0,0,0}-{2822,3053,0,0,0}-"
}, },
{ {
"npc_id": "7236", "npc_id": "7236",
"loc_data": "{2801,2995,0,1,0}-{2804,3001,0,1,0}-{2803,2986,0,1,0}-{2811,2999,0,1,0}-{2800,3006,0,1,0}-" "loc_data": "{2799,3005,0,0,0}-{2801,2995,0,0,0}-{2804,3001,0,0,0}-{2803,2986,0,0,0}-{2811,2999,0,0,0}-"
}, },
{ {
"npc_id": "7275", "npc_id": "7275",
"loc_data": "{2916,3382,0,1,0}-{2914,3373,0,1,0}-{2995,3252,0,1,0}-{2996,3259,0,1,0}-{2993,3250,0,1,0}-{3000,3258,0,1,0}-{3306,3424,0,1,0}-{3306,3419,0,1,0}-" "loc_data": "{2995,3252,0,0,0}-{2996,3259,0,0,0}-{2993,3250,0,0,0}-{3000,3258,0,0,0}-"
}, },
{ {
"npc_id": "7276", "npc_id": "7276",
"loc_data": "{2909,3381,0,1,0}-{2994,3256,0,1,0}-{3002,3250,0,1,0}-{2992,3252,0,1,0}-{3000,3250,0,1,0}-{2728,3422,0,1,1}-{2718,3413,0,1,4}-{2729,3420,0,1,4}-{2727,3414,0,1,6}-{2714,3419,0,1,3}-{2719,3427,0,1,7}-{3311,3420,0,1,0}-{3306,3421,0,1,0}-" "loc_data": "{2994,3256,0,0,0}-{3002,3250,0,0,0}-{2992,3252,0,0,0}-{3000,3250,0,0,0}-{2728,3422,0,1,1}-{2718,3413,0,1,4}-{2729,3420,0,1,4}-{2727,3414,0,1,6}-{2714,3419,0,1,3}-{2719,3427,0,1,7}-"
}, },
{ {
"npc_id": "7285", "npc_id": "7285",
"loc_data": "{2835,3107,0,1,0}-{2836,3101,0,1,0}-{2836,3110,0,1,0}-{2837,3112,0,1,0}-{2841,3107,0,1,0}-{2885,3019,0,1,0}-{2885,3018,0,1,0}-{2891,3018,0,1,0}-" "loc_data": "{2835,3107,0,0,0}-{2836,3101,0,0,0}-{2836,3110,0,0,0}-{2837,3112,0,0,0}-{2841,3107,0,0,0}-{2885,3018,0,0,0}-{2885,3019,0,0,0}-{2891,3018,0,0,0}-"
}, },
{ {
"npc_id": "7286", "npc_id": "7286",
"loc_data": "{2924,3102,0,1,0}-{2925,3097,0,1,0}-{2933,3104,0,1,0}-{2936,3096,0,1,0}-{2931,3090,0,1,0}-" "loc_data": "{2931,3090,0,0,0}-{2925,3097,0,0,0}-{2936,3096,0,0,0}-{2924,3102,0,0,0}-{2933,3104,0,0,0}-"
},
{
"npc_id": "7287",
"loc_data": "{2833,3055,0,1,0}-{2838,3054,0,1,0}-{2839,3047,0,1,0}-{2832,3047,0,1,0}-{2839,3063,0,1,0}-"
}, },
{ {
"npc_id": "7288", "npc_id": "7288",
"loc_data": "{2834,3045,0,1,0}-{2826,3048,0,1,0}-{2824,3043,0,1,0}-{2822,3045,0,1,0}-{2822,3045,0,1,0}-" "loc_data": "{2834,3045,0,0,0}-{2826,3048,0,0,0}-{2824,3043,0,0,0}-{2822,3045,0,0,0}-{2818,3049,0,0,0}-"
}, },
{ {
"npc_id": "7289", "npc_id": "7289",
@ -12105,19 +11989,19 @@
}, },
{ {
"npc_id": "7309", "npc_id": "7309",
"loc_data": "{2946,3280,0,1,0}-{2966,3295,0,1,0}-{3023,3410,0,1,0}-{3023,3410,0,1,0}-{3317,3445,0,1,0}-" "loc_data": "{2946,3280,0,0,0}-{3023,3410,0,0,0}-"
}, },
{ {
"npc_id": "7310", "npc_id": "7310",
"loc_data": "{2947,3273,0,1,0}-{2972,3298,0,1,0}-{2729,3425,0,1,0}-{3015,3409,0,1,0}-{3018,3407,0,1,0}-{3312,3442,0,1,0}-" "loc_data": "{2946,3272,0,0,0}-{3015,3409,0,0,0}-"
}, },
{ {
"npc_id": "7311", "npc_id": "7311",
"loc_data": "{2956,3273,0,1,0}-{2967,3305,0,1,0}-{2731,3420,0,1,0}-{2722,3424,0,1,0}-{3024,3402,0,1,0}-{3021,3405,0,1,0}-{3308,3445,0,1,0}-" "loc_data": "{2956,3273,0,0,0}-"
}, },
{ {
"npc_id": "7312", "npc_id": "7312",
"loc_data": "{2951,3267,0,1,0}-{2964,3297,0,1,0}-{2722,3418,0,1,0}-{2716,3423,0,1,0}-{3017,3412,0,1,0}-{3026,3409,0,1,0}-{3308,3440,0,1,0}-" "loc_data": "{2950,3268,0,0,0}-"
}, },
{ {
"npc_id": "7420", "npc_id": "7420",
@ -12335,54 +12219,6 @@
"npc_id": "8000", "npc_id": "8000",
"loc_data": "{2987,3691,0,1,3}-" "loc_data": "{2987,3691,0,1,3}-"
}, },
{
"npc_id": "8029",
"loc_data": "{1697,5463,2,1,0}-"
},
{
"npc_id": "8030",
"loc_data": "{1698,5462,2,1,0}-"
},
{
"npc_id": "8031",
"loc_data": "{1694,5473,2,1,0}-"
},
{
"npc_id": "8032",
"loc_data": "{1691,5469,2,1,0}-"
},
{
"npc_id": "8033",
"loc_data": "{1700,5463,2,1,0}-"
},
{
"npc_id": "8034",
"loc_data": "{1692,5465,2,1,0}-"
},
{
"npc_id": "8035",
"loc_data": "{1692,5472,2,1,0}-"
},
{
"npc_id": "8036",
"loc_data": "{1696,5473,2,1,0}-"
},
{
"npc_id": "8037",
"loc_data": "{1701,5472,2,1,0}-"
},
{
"npc_id": "8038",
"loc_data": "{1702,5470,2,1,0}-"
},
{
"npc_id": "8039",
"loc_data": "{1702,5468,2,1,0}-"
},
{
"npc_id": "8040",
"loc_data": "{1694,5462,2,1,0}-"
},
{ {
"npc_id": "8041", "npc_id": "8041",
"loc_data": "{2794,3100,0,1,0}-" "loc_data": "{2794,3100,0,1,0}-"

File diff suppressed because it is too large Load diff

View file

@ -1,165 +0,0 @@
[
{
"mode": "add",
"id": "1814",
"location": "3090, 3475, 0",
"type": "4",
"direction": "nw"
},
{
"mode": "add",
"id": "2646",
"location": "2445, 3413, 0",
"direction": "nw"
},
{
"mode": "add",
"id": "2646",
"location": "2447, 3414, 0",
"direction": "e"
},
{
"mode": "add",
"id": "2646",
"location": "2447, 3421, 0",
"direction": "nw"
},
{
"comment": "Prison Pete Random",
"mode": "add",
"id": "36788",
"location": "2094, 4465, 0",
"type": "10",
"direction": "e"
},
{
"comment": "Green Portal",
"mode": "remove",
"id": "11371",
"location": "2085, 4457, 0"
},
{
"comment": "Lever",
"mode": "remove",
"id": "10817",
"location": "2083, 4460, 0"
},
{
"comment": "Lever",
"mode": "add",
"id": "26191",
"location": "2083, 4460, 0",
"type": "10",
"direction": "e"
},
{
"comment": "Window",
"mode": "add",
"id": "26184",
"location": "2084, 4459, 0",
"type": "0",
"direction": "n"
},
{
"comment": "Door",
"mode": "add",
"id": "26186",
"location": "2085, 4459, 0",
"type": "0",
"direction": "n"
},
{
"comment": "Door",
"mode": "add",
"id": "26188",
"location": "2086, 4459, 0",
"type": "0",
"direction": "n"
},
{
"comment": "Window",
"mode": "add",
"id": "26184",
"location": "2087, 4459, 0",
"type": "0",
"direction": "n"
},
{
"mode": "remove",
"id": "37670",
"location": "3292, 3299, 0"
},
{
"mode": "add",
"id": "37304",
"location": "3292, 3299, 0"
},
{
"mode": "add",
"id": "20987",
"location": "3821, 2996, 0"
},
{
"mode": "remove",
"id": "356",
"location": "2804, 3428, 0"
},
{
"mode": "add",
"id": "356",
"location": "2804, 3428, 0"
},
{
"mode": "remove",
"id": "20228",
"location": "2537, 3573, 0"
},
{
"mode": "add",
"id": "27663",
"location": "2537, 3573, 0",
"direction": "w"
},
{
"mode": "add",
"id": "39237",
"location": "2957, 3266, 0",
"direction": "n"
},
{
"mode": "add",
"id": "39245",
"location": "2956, 3270, 0",
"direction": "se"
},
{
"mode": "add",
"id": "39242",
"location": "2955, 3273, 0",
"direction": "w"
},
{
"mode": "add",
"id": "39241",
"location": "2955, 3274, 0"
},
{
"mode": "add",
"id": "20987",
"location": "2821, 2996, 0",
"direction": "s"
},
{
"mode": "add",
"id": "21301",
"location": "2662, 3162, 0",
"direction": "e"
},
{
"mode": "add",
"id": "4176",
"location": "2629, 3661, 2",
"type": "4",
"direction": "e"
}
]

View file

@ -1546,41 +1546,5 @@
"animation": "426", "animation": "426",
"drop_ammo": "true", "drop_ammo": "true",
"ammunition": "14202,14203,14204,14205,14206" "ammunition": "14202,14203,14204,14205,14206"
},
{
"itemId": "10149",
"name": "Swamp lizard",
"ammo_slot": "13",
"weapon_type": "0",
"animation": "5247",
"drop_ammo": "false",
"ammunition": "10142"
},
{
"itemId": "10146",
"name": "Orange salamander",
"ammo_slot": "13",
"weapon_type": "0",
"animation": "5247",
"drop_ammo": "false",
"ammunition": "10143"
},
{
"itemId": "10147",
"name": "Red salamander",
"ammo_slot": "13",
"weapon_type": "0",
"animation": "5247",
"drop_ammo": "false",
"ammunition": "10144"
},
{
"itemId": "10148",
"name": "Black salamander",
"ammo_slot": "13",
"weapon_type": "0",
"animation": "5247",
"drop_ammo": "false",
"ammunition": "10145"
} }
] ]

View file

@ -186,7 +186,7 @@
"general_store": "true", "general_store": "true",
"id": "22", "id": "22",
"title": "The Lighthouse Store", "title": "The Lighthouse Store",
"stock": "{954,10,200}-{2347,10,500}-{1755,10,500}-{946,10,500}-{952,10,500}-{590,5,500}-{36,10,500}-{273,10,200}-{233,10,500}-{1931,10,500}-{1925,5,500}-{1929,5,500}-{1935,5,200}-{1937,5,500}-{229,10,500}-{227,10,500}-{2019,5,500}-{2021,5,500}-{2015,5,2}-{1915,5,500}-{2017,5,500}-{1909,5,500}-{1913,5,500}-{1907,5,500}" "stock": "{1931,30,100}-{1935,30,100}-{1735,10,100}-{1925,10,100}-{1923,10,100}-{1887,10,100}-{590,10,100}-{1755,10,100}-{2347,10,100}-{550,10,100}-{9003,10,100}"
}, },
{ {
"npcs": "2352", "npcs": "2352",
@ -2195,14 +2195,5 @@
"id": "256", "id": "256",
"title": "Uglug's Stuffsies", "title": "Uglug's Stuffsies",
"stock": "{4844,100,10}-{10927,0,100}-{2862,100,100}-{1777,10,200}-{2876,0,500}-{2878,10,100}-{4850,0,100}-{946,5,100}-{4773,0,1000}-{4778,0,1000}-{4783,0,1000}-{4788,0,1500}-{4793,0,2000}-{4798,0,3000}-{4803,0,4000}-{4827,0,2000}" "stock": "{4844,100,10}-{10927,0,100}-{2862,100,100}-{1777,10,200}-{2876,0,500}-{2878,10,100}-{4850,0,100}-{946,5,100}-{4773,0,1000}-{4778,0,1000}-{4783,0,1000}-{4788,0,1500}-{4793,0,2000}-{4798,0,3000}-{4803,0,4000}-{4827,0,2000}"
},
{
"npcs": "",
"high_alch": "0",
"currency": "995",
"general_store": "false",
"id": "257",
"title": "Magic Guild Store",
"stock": "{4089,1000,100}-{4091,1000,100}-{4093,1000,100}-{4095,1000,100}-{4097,1000,100}-{9762,1000,100}"
} }
] ]

View file

@ -6,7 +6,6 @@
<version>1.0.0</version> <version>1.0.0</version>
<properties> <properties>
<project.mainClassName>core.Server</project.mainClassName> <project.mainClassName>core.Server</project.mainClassName>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<kotlin.compiler.incremental>true</kotlin.compiler.incremental> <kotlin.compiler.incremental>true</kotlin.compiler.incremental>
<kotlin.version>1.8.20</kotlin.version> <kotlin.version>1.8.20</kotlin.version>
<kotlin.compiler.jvmTarget>11</kotlin.compiler.jvmTarget> <kotlin.compiler.jvmTarget>11</kotlin.compiler.jvmTarget>
@ -91,11 +90,6 @@
<version>2.9.0</version> <version>2.9.0</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency>
<groupId>org.java-websocket</groupId>
<artifactId>Java-WebSocket</artifactId>
<version>1.5.7</version>
</dependency>
</dependencies> </dependencies>
<build> <build>
@ -252,7 +246,6 @@
<configuration> <configuration>
<useFile>false</useFile> <useFile>false</useFile>
<trimStackTrace>false</trimStackTrace> <trimStackTrace>false</trimStackTrace>
<argLine>-Xmx4g -Xms2g</argLine>
</configuration> </configuration>
<version>2.22.0</version> <version>2.22.0</version>
</plugin> </plugin>

View file

@ -0,0 +1,172 @@
package content.data;
import core.game.node.entity.player.Player;
/**
* The BossKillcounter keeps track of the amount of bosses the player has slain.
* addtoKillcount(player, npcId) should be added in the finalizeDeath() method of the combat handler for the boss.
* @author Splinter
*/
public enum BossKillCounter {
/* ORDINAL BOUND */
KING_BLACK_DRAGON(new int[] { 50 }, "King Black Dragon", 14649),
BORK(new int[] { 7133, 7134 }, "Bork", -1),
DAGANNOTH_SUPREME(new int[] { 2881 }, "Dagannoth Supreme", 14639),
DAGANNOTH_PRIME(new int[] { 2882 }, "Dagannoth Prime", 14640),
DAGANNOTH_REX(new int[] { 2883 }, "Dagannoth Rex", 14641),
CHAOS_ELEMENTAL(new int[] { 3200 }, "Chaos Elemental", 14638),
GIANT_MOLE(new int[] { 3340 }, "Giant Mole", 14642),
SARADOMIN(new int[] { 6247 }, "Commander Zilyana", 14647),
ZAMORAK(new int[] { 6203 }, "K'ril Tsutsaroth", 14648),
BANDOS(new int[] { 6260 }, "General Graardor", 14646),
ARMADYL(new int[] { 6222 }, "Kree'arra", 14645),
JAD(new int[] { 2745 }, "Tz-Tok Jad", 14828),
KALPHITE_QUEEN(new int[] { 1160 }, "Kalphite Queen", 14650),
CORPOREAL_BEAST(new int[] { 8133 }, "Corporeal Beast", 14653),
TORMENTED_DEMONS(new int[] {
8349, 8350, 8351, 8352, 8353, 8354,
8355, 8356, 8357, 8358, 8359, 8360,
8361, 8362, 8363, 8364, 8365, 8366,
}, "Tormented demon", -1),
;
/**
* The npcs that can increase the killcounter
*/
private final int[] npc;
/**
* The name of the NPC, to be displayed as a sendMessage
*/
private final String name;
/**
* The item ID of the pet relating to the boss.
*/
private final int petId;
/**
* Constructs a new {@code BossKillCounter} {@code Object}.
* @param npc the npc.
* @param name the npc's string name
*/
BossKillCounter(final int[] npc, final String name, final int petId) {
this.npc = npc;
this.name = name;
this.petId = petId;
}
/**
* Gets the npc.
* @return The npc.
*/
public int[] getNpc() {
return npc;
}
/**
* Gets the NPC's name
* @return their name
*/
public String getName() {
return name;
}
/**
* Gets the petId
* @return The petId
*/
public int getPetId() {
return petId;
}
/**
* Gets the type for the npc.
* @param npc the npc.
* @return the BossKillcounter
*/
public static BossKillCounter forNPC(final int npc) {
for (BossKillCounter kc : BossKillCounter.values()) {
for (int i : kc.getNpc()) {
if (npc == i) {
return kc;
}
}
}
return null;
}
/**
* Adds to the player's killcount for that particular boss.
* @param killer The player who killed the npc
* @param npcid the ID of the npc that just died
*/
public static void addtoKillcount(Player killer, int npcid) {
if (killer == null) {
return;
}
BossKillCounter boss = BossKillCounter.forNPC(npcid);
if (boss == null) {
return;
}
killer.getSavedData().getGlobalData().getBossCounters()[boss.ordinal()]++;
killer.getPacketDispatch().sendMessage("Your " + boss.getName() + " killcount is now: <col=ff0000>" + killer.getSavedData().getGlobalData().getBossCounters()[boss.ordinal()] + "</col>.");
// addBossPet(killer, npcid, boss);
}
// /**
// * Gives the player the pet if they killed a certain boss.
// * The chance by default is 1/5000. This rate lowers to 1/2200 if the <GlobalEvents> for Boss Pets is active.
// * Note: Not all bosses have pet versions of themselves.
// */
// private static void addBossPet(Player killer, int npcid, BossKillCounter boss){
// if(boss.getPetId() == -1){ //The boss does not have a pet version.
// return;
// }
// int number = 5000;
// if (npcid == 2745) {
// number = 200;
// if (killer.getSlayer().getTask() == Tasks.JAD) {
// number = 100;
// }
// } else if (npcid == 3200) {
// number = 300;
// }
// int rand = number;
// if(rand == 10){
// for (int i = 0; i < killer.getFamiliarManager().getInsuredPets().size(); i++) {
// if (killer.getFamiliarManager().getInsuredPets().get(i).getBabyItemId() == boss.getPetId()) {
// return;
// }
// }
// if(killer.getFamiliarManager().hasFamiliar() && killer.getInventory().freeSlots() < 1){
// return;
// }
// if(!killer.getFamiliarManager().hasFamiliar()){
// killer.getFamiliarManager().summon(new Item(boss.getPetId()), true);
// killer.sendNotificationMessage("You have a funny feeling like you're being followed.");
// } else if (killer.getInventory().freeSlots() > 0){
// killer.getInventory().add(new Item(boss.getPetId(), 1));
// killer.sendNotificationMessage("You feel something weird sneaking into your backpack.");
// }
// Repository.sendNews(killer.getUsername()+" now commands a miniature "+(boss.equals(CORPOREAL_BEAST) ? "Dark core" : boss.getName())+"!");
// }
// }
/**
* Increments the player's Barrows chest counter.
* @param player the player
*/
public static void addtoBarrowsCount(Player player) {
if (player == null) {
return;
}
player.getSavedData().getGlobalData().setBarrowsLoots(player.getSavedData().getGlobalData().getBarrowsLoots() + 1);
player.getPacketDispatch().sendMessage("Your Barrows chest count is: <col=ff0000>" + player.getSavedData().getGlobalData().getBarrowsLoots() + "</col>.");
}
}

View file

@ -1,72 +0,0 @@
package content.data
import core.api.sendMessage
import core.game.node.entity.player.Player
import org.rs09.consts.NPCs
/**
* Enumerates the bosses that have their kill counts tracked in a player's statistics (::stats).
* addToBossKillCount(player, npcId) should be added in the finalizeDeath() method of the combat handler for the boss.
* ORDINAL BOUND
* @author Bishop
*/
enum class BossKillCounter(val bossId: IntArray, val bossName: String) {
KING_BLACK_DRAGON(intArrayOf(NPCs.KING_BLACK_DRAGON_50), "King Black Dragon"),
BORK(intArrayOf(NPCs.BORK_7133, NPCs.BORK_7134), "Bork"),
DAGANNOTH_SUPREME(intArrayOf(NPCs.DAGANNOTH_SUPREME_2881), "Dagannoth Supreme"),
DAGANNOTH_PRIME(intArrayOf(NPCs.DAGANNOTH_PRIME_2882), "Dagannoth Prime"),
DAGANNOTH_REX(intArrayOf(NPCs.DAGANNOTH_REX_2883), "Dagannoth Rex"),
CHAOS_ELEMENTAL(intArrayOf(NPCs.CHAOS_ELEMENTAL_3200), "Chaos Elemental"),
GIANT_MOLE(intArrayOf(NPCs.GIANT_MOLE_3340), "Giant Mole"),
SARADOMIN(intArrayOf(NPCs.COMMANDER_ZILYANA_6247), "Commander Zilyana"),
ZAMORAK(intArrayOf(NPCs.KRIL_TSUTSAROTH_6203), "K'ril Tsutsaroth"),
BANDOS(intArrayOf(NPCs.GENERAL_GRAARDOR_6260), "General Graardor"),
ARMADYL(intArrayOf(NPCs.KREEARRA_6222), "Kree'arra"),
JAD(intArrayOf(NPCs.TZTOK_JAD_2745), "Tz-Tok Jad"),
KALPHITE_QUEEN(intArrayOf(NPCs.KALPHITE_QUEEN_1160), "Kalphite Queen"),
CORPOREAL_BEAST(intArrayOf(NPCs.CORPOREAL_BEAST_8133), "Corporeal Beast"),
TORMENTED_DEMONS(
intArrayOf(
NPCs.TORMENTED_DEMON_8349, NPCs.TORMENTED_DEMON_8350, NPCs.TORMENTED_DEMON_8351,
NPCs.TORMENTED_DEMON_8352, NPCs.TORMENTED_DEMON_8353, NPCs.TORMENTED_DEMON_8354,
NPCs.TORMENTED_DEMON_8355, NPCs.TORMENTED_DEMON_8356, NPCs.TORMENTED_DEMON_8357,
NPCs.TORMENTED_DEMON_8358, NPCs.TORMENTED_DEMON_8359, NPCs.TORMENTED_DEMON_8360,
NPCs.TORMENTED_DEMON_8361, NPCs.TORMENTED_DEMON_8362, NPCs.TORMENTED_DEMON_8363,
NPCs.TORMENTED_DEMON_8364, NPCs.TORMENTED_DEMON_8365, NPCs.TORMENTED_DEMON_8366),
"Tormented demon"
),
PENANCE_QUEEN(intArrayOf(NPCs.PENANCE_QUEEN_5247), "Penance Queen");
companion object {
private fun forBossId(npc: Int): BossKillCounter? {
for (kc in values()) {
for (i in kc.bossId) {
if (npc == i) {
return kc
}
}
}
return null
}
@JvmStatic
fun addToBossKillCount(killer: Player?, bossId: Int) {
if (killer == null) {
return
}
val boss: BossKillCounter = forBossId(bossId) ?: return
killer.getSavedData().globalData.bossCounters[boss.ordinal]++
sendMessage(killer, "Your ${boss.bossName} killcount is now: <col=ff0000>${killer.getSavedData().globalData.bossCounters[boss.ordinal]}</col>.")
}
fun addToBarrowsChestCount(player: Player?) {
if (player == null) {
return
}
player.getSavedData().globalData.barrowsLoots++
sendMessage(player, "Your Barrows chest count is: <col=ff0000>${player.getSavedData().globalData.barrowsLoots}</col>.")
}
}
}

View file

@ -9,14 +9,15 @@ import core.game.event.TeleportEvent
import core.game.interaction.QueueStrength import core.game.interaction.QueueStrength
import core.game.node.entity.player.Player import core.game.node.entity.player.Player
import core.game.node.entity.player.link.TeleportManager import core.game.node.entity.player.link.TeleportManager
import core.game.node.entity.player.link.diary.DiaryType
import core.game.node.item.Item import core.game.node.item.Item
import core.game.system.task.Pulse
import core.game.world.GameWorld import core.game.world.GameWorld
import core.game.world.map.Location import core.game.world.map.Location
import core.game.world.update.flag.context.Animation import core.game.world.update.flag.context.Animation
import core.game.world.update.flag.context.Graphics import core.game.world.update.flag.context.Graphics
import core.tools.Log
import org.rs09.consts.Items import org.rs09.consts.Items
import core.game.world.GameWorld.Pulser
import core.tools.Log
import org.rs09.consts.Sounds import org.rs09.consts.Sounds
import java.util.* import java.util.*
@ -33,14 +34,12 @@ enum class EnchantedJewellery(
"Sumona in Pollnivneach.", "Sumona in Pollnivneach.",
"Morytania Slayer Tower.", "Morytania Slayer Tower.",
"Rellekka Slayer Caves.", "Rellekka Slayer Caves.",
"Tarn's Lair.",
"Nowhere. Give me a slayer update." "Nowhere. Give me a slayer update."
), ),
arrayOf( arrayOf(
Location.create(3361, 2994, 0), Location.create(3361, 2994, 0),
Location.create(3428, 3535, 0), Location.create(3428, 3535, 0),
Location.create(2792, 3615, 0), Location.create(2792, 3615, 0),
Location.create(3187, 4601, 0),
), ),
true, true,
Items.RING_OF_SLAYING8_13281, Items.RING_OF_SLAYING8_13281,
@ -195,7 +194,7 @@ enum class EnchantedJewellery(
), ),
RING_OF_LIFE(arrayOf<String>(), RING_OF_LIFE(arrayOf<String>(),
arrayOf( arrayOf(
Location.create(ServerConstants.HOME_LOCATION!!) Location.create(ServerConstants.HOME_LOCATION)
), ),
true, true,
Items.RING_OF_LIFE_2570 Items.RING_OF_LIFE_2570
@ -242,26 +241,13 @@ enum class EnchantedJewellery(
if (!canTeleport(player, nextJewellery)) { if (!canTeleport(player, nextJewellery)) {
return false return false
} }
// Access to Tarn's Lair has a quest prereq.
if (this == RING_OF_SLAYING && buttonID == 3
&& !isQuestComplete(player, Quests.HAUNTED_MINE)
) {
sendMessage(player, "You must complete the Haunted Mine quest to access Tarn's Lair.")
return false
}
val location = getLocation(buttonID) val location = getLocation(buttonID)
player.scripts.delay = GameWorld.ticks + 4 player.scripts.delay = GameWorld.ticks + 4
queueScript(player, 0, QueueStrength.SOFT) { stage -> queueScript(player, 0, QueueStrength.SOFT) { stage ->
when (stage) { when (stage) {
0 -> { 0 -> {
lock(player, 4) lock(player, 4)
// This is an intentional teleport animation & graphics difference as these two jewellery
// animations are authentic to 2009 while others are currently unknown.
if (this == RING_OF_DUELING || this == GAMES_NECKLACE) {
visualize(player, JEWELLERY_ANIMATION, JEWELLERY_GRAPHICS)
} else {
visualize(player, ANIMATION, GRAPHICS) visualize(player, ANIMATION, GRAPHICS)
}
playGlobalAudio(player.location, Sounds.TELEPORT_ALL_200) playGlobalAudio(player.location, Sounds.TELEPORT_ALL_200)
player.impactHandler.disabledTicks = 4 player.impactHandler.disabledTicks = 4
closeInterface(player) closeInterface(player)
@ -270,16 +256,8 @@ enum class EnchantedJewellery(
1 -> { 1 -> {
teleport(player, location) teleport(player, location)
resetAnimator(player) resetAnimator(player)
if (this == RING_OF_DUELING || this == GAMES_NECKLACE) {
player.graphics(JEWELLERY_GRAPHICS)
}
unlock(player) unlock(player)
player.dispatch(TeleportEvent(TeleportManager.TeleportType.NORMAL, TeleportMethod.JEWELRY, item, location)) player.dispatch(TeleportEvent(TeleportManager.TeleportType.NORMAL, TeleportMethod.JEWELRY, item, location))
if (DIGSITE_PENDANT.ids.contains(item.id)) {
player.achievementDiaryManager.finishTask(player, DiaryType.VARROCK, 1, 10)
}
if (!replace) { if (!replace) {
return@queueScript stopExecuting(player) return@queueScript stopExecuting(player)
} }
@ -388,8 +366,6 @@ enum class EnchantedJewellery(
companion object { companion object {
private val ANIMATION = Animation(714) private val ANIMATION = Animation(714)
private val GRAPHICS = Graphics(308, 100, 50) private val GRAPHICS = Graphics(308, 100, 50)
private val JEWELLERY_ANIMATION = Animation(9603)
private val JEWELLERY_GRAPHICS = Graphics(1684)
val idMap = HashMap<Int, EnchantedJewellery>() val idMap = HashMap<Int, EnchantedJewellery>()
init { init {

View file

@ -3,7 +3,7 @@ package content.data;
import core.game.node.entity.player.Player; import core.game.node.entity.player.Player;
import core.game.node.item.Item; import core.game.node.item.Item;
import static core.api.ContentAPIKt.isQuestComplete; import static core.api.ContentAPIKt.hasRequirement;
/** /**
* A god book. * A god book.
@ -100,7 +100,7 @@ public enum GodBook {
* @param page the page. * @param page the page.
*/ */
public void insertPage(Player player, Item book, Item page) { public void insertPage(Player player, Item book, Item page) {
if (!isQuestComplete(player, Quests.HORROR_FROM_THE_DEEP)) if (!hasRequirement(player, Quests.HORROR_FROM_THE_DEEP))
return; return;
if (hasPage(player, book, page)) { if (hasPage(player, book, page)) {
player.sendMessage("The book already has that page."); player.sendMessage("The book already has that page.");

View file

@ -16,9 +16,9 @@ public enum LightSource {
CANDLE(1, new Item(CANDLE_36, 1), new Item(LIT_CANDLE_33, 1), true, Components.DARKNESS_MEDIUM_98), CANDLE(1, new Item(CANDLE_36, 1), new Item(LIT_CANDLE_33, 1), true, Components.DARKNESS_MEDIUM_98),
BLACK_CANDLE(1, new Item(BLACK_CANDLE_38, 1), new Item(LIT_BLACK_CANDLE_32, 1), true, Components.DARKNESS_MEDIUM_98), BLACK_CANDLE(1, new Item(BLACK_CANDLE_38, 1), new Item(LIT_BLACK_CANDLE_32, 1), true, Components.DARKNESS_MEDIUM_98),
TORCH(1, new Item(UNLIT_TORCH_596, 1), new Item(LIT_TORCH_594, 1), true, Components.DARKNESS_MEDIUM_98), TORCH(1, new Item(UNLIT_TORCH_596, 1), new Item(LIT_TORCH_594, 1), true, Components.DARKNESS_MEDIUM_98),
CANDLE_LANTERN(4, new Item(CANDLE_LANTERN_4529, 1), new Item(CANDLE_LANTERN_4531, 1), false, Components.DARKNESS_MEDIUM_98), CANDLE_LANTERN(4, new Item(CANDLE_LANTERN_4527, 1), new Item(CANDLE_LANTERN_4531, 1), false, Components.DARKNESS_MEDIUM_98),
OIL_LAMP(12, new Item(OIL_LAMP_4522, 1), new Item(OIL_LAMP_4524, 1), true, Components.DARKNESS_LIGHT_97), OIL_LAMP(12, new Item(OIL_LAMP_4522, 1), new Item(OIL_LAMP_4524, 1), true, Components.DARKNESS_LIGHT_97),
OIL_LANTERN(26, new Item(OIL_LANTERN_4537, 1), new Item(OIL_LANTERN_4539, 1), false, Components.DARKNESS_LIGHT_97), OIL_LANTERN(26, new Item(OIL_LANTERN_4535, 1), new Item(OIL_LANTERN_4539, 1), false, Components.DARKNESS_LIGHT_97),
BULLSEYE_LANTERN(49, new Item(BULLSEYE_LANTERN_4548, 1), new Item(BULLSEYE_LANTERN_4550, 1), false, -1), BULLSEYE_LANTERN(49, new Item(BULLSEYE_LANTERN_4548, 1), new Item(BULLSEYE_LANTERN_4550, 1), false, -1),
SAPPHIRE_LANTERN(49, new Item(SAPPHIRE_LANTERN_4701, 1), new Item(SAPPHIRE_LANTERN_4702, 1), false, -1), SAPPHIRE_LANTERN(49, new Item(SAPPHIRE_LANTERN_4701, 1), new Item(SAPPHIRE_LANTERN_4702, 1), false, -1),
EMERALD_LANTERN(49, new Item(EMERALD_LANTERN_9064, 1), new Item(EMERALD_LANTERN_9065, 1), false, -1), EMERALD_LANTERN(49, new Item(EMERALD_LANTERN_9064, 1), new Item(EMERALD_LANTERN_9065, 1), false, -1),

View file

@ -118,8 +118,6 @@ public enum Consumables {
EGG_AND_TOMATO(new Food(new int[] {7064, 1923}, new HealingEffect(8))), EGG_AND_TOMATO(new Food(new int[] {7064, 1923}, new HealingEffect(8))),
SWEET_CORN(new Food(new int[] {5988}, new MultiEffect(new HealingEffect(1), new PercentageHealthEffect(10)))), SWEET_CORN(new Food(new int[] {5988}, new MultiEffect(new HealingEffect(1), new PercentageHealthEffect(10)))),
SWEETCORN_BOWL(new Food(new int[] {7088, 1923}, new MultiEffect(new HealingEffect(1), new PercentageHealthEffect(10)))), SWEETCORN_BOWL(new Food(new int[] {7088, 1923}, new MultiEffect(new HealingEffect(1), new PercentageHealthEffect(10)))),
CHOPPED_TUNA(new Food(new int[] {7086, 1923}, new HealingEffect(10))),
CHOPPED_ONION(new Food(new int[] {1871, 1923}, new HealingEffect(1))),
POTATO_WITH_BUTTER(new Food(new int[] {6703}, new HealingEffect(7))), POTATO_WITH_BUTTER(new Food(new int[] {6703}, new HealingEffect(7))),
CHILLI_POTATO(new Food(new int[] {7054}, new HealingEffect(14))), CHILLI_POTATO(new Food(new int[] {7054}, new HealingEffect(14))),
FRIED_ONIONS(new Food(new int[] {7084, 1923}, new HealingEffect(5))), FRIED_ONIONS(new Food(new int[] {7084, 1923}, new HealingEffect(5))),
@ -319,7 +317,6 @@ public enum Consumables {
TCHIKI_MONKEY_PASTE(new Food(new int[] {7575}, new HealingEffect(5), "You eat the Tchiki monkey nut paste. It sticks to the roof of your mouth.")), TCHIKI_MONKEY_PASTE(new Food(new int[] {7575}, new HealingEffect(5), "You eat the Tchiki monkey nut paste. It sticks to the roof of your mouth.")),
OOMLIE_WRAP(new Food(new int[] {Items.COOKED_OOMLIE_WRAP_2343}, new MultiEffect(new HealingEffect(14), new AchievementEffect(DiaryType.KARAMJA, 2, 2)))), OOMLIE_WRAP(new Food(new int[] {Items.COOKED_OOMLIE_WRAP_2343}, new MultiEffect(new HealingEffect(14), new AchievementEffect(DiaryType.KARAMJA, 2, 2)))),
ROE(new Food(new int[]{11324}, new HealingEffect(3))), ROE(new Food(new int[]{11324}, new HealingEffect(3))),
CAVIAR(new Food(new int[]{11326}, new HealingEffect(5))),
EQUA_LEAVES(new Food(new int[]{2128}, new HealingEffect(1))), EQUA_LEAVES(new Food(new int[]{2128}, new HealingEffect(1))),
CHOC_ICE(new Food(new int[]{6794}, new HealingEffect(7))), CHOC_ICE(new Food(new int[]{6794}, new HealingEffect(7))),
EDIBLE_SEAWEED(new Food(new int[] {403}, new HealingEffect(4))), EDIBLE_SEAWEED(new Food(new int[] {403}, new HealingEffect(4))),
@ -346,14 +343,14 @@ public enum Consumables {
AGILITY(new Potion(new int[] {3032, 3034, 3036, 3038}, new SkillEffect(Skills.AGILITY, 3, 0))), AGILITY(new Potion(new int[] {3032, 3034, 3036, 3038}, new SkillEffect(Skills.AGILITY, 3, 0))),
HUNTER(new Potion(new int[] {9998, 10000, 10002, 10004}, new SkillEffect(Skills.HUNTER, 3, 0))), HUNTER(new Potion(new int[] {9998, 10000, 10002, 10004}, new SkillEffect(Skills.HUNTER, 3, 0))),
RESTORE(new Potion(new int[] {2430, 127, 129, 131}, new RestoreEffect(10, 0.3))), RESTORE(new Potion(new int[] {2430, 127, 129, 131}, new RestoreEffect(10, 0.3))),
SARA_BREW(new Potion(new int[] {6685, 6687, 6689, 6691}, new MultiEffect(new PercentHeal(2, .15), new SkillEffect(Skills.ATTACK, 0, -0.10), new SkillEffect(Skills.STRENGTH, 0, -0.10), new SkillEffect(Skills.MAGIC, 0, -0.10), new SkillEffect(Skills.RANGE, 0, -0.10), new SkillEffect(Skills.DEFENCE, 2, 0.2)))), SARA_BREW(new Potion(new int[] {6685, 6687, 6689, 6691}, new MultiEffect(new PercentHeal(0, .15), new SkillEffect(Skills.ATTACK, 0, -0.10), new SkillEffect(Skills.STRENGTH, 0, -0.10), new SkillEffect(Skills.MAGIC, 0, -0.10), new SkillEffect(Skills.RANGE, 0, -0.10), new SkillEffect(Skills.DEFENCE, 0, 0.25)))),
SUMMONING(new Potion(new int[] {12140, 12142, 12144, 12146}, new MultiEffect(new RestoreSummoningSpecial(), new SummoningEffect(7, 0.25)))), SUMMONING(new Potion(new int[] {12140, 12142, 12144, 12146}, new MultiEffect(new RestoreSummoningSpecial(), new SummoningEffect(7, 0.25)))),
COMBAT(new Potion(new int[] {9739, 9741, 9743, 9745}, new MultiEffect(new SkillEffect(Skills.STRENGTH, 3, .1), new SkillEffect(Skills.ATTACK, 3, .1)))), COMBAT(new Potion(new int[] {9739, 9741, 9743, 9745}, new MultiEffect(new SkillEffect(Skills.STRENGTH, 3, .1), new SkillEffect(Skills.ATTACK, 3, .1)))),
ENERGY(new Potion(new int[] {3008, 3010, 3012, 3014}, new EnergyEffect(10))), ENERGY(new Potion(new int[] {3008, 3010, 3012, 3014}, new EnergyEffect(10))),
FISHING(new Potion(new int[] {2438, 151, 153, 155}, new SkillEffect(Skills.FISHING, 3, 0))), FISHING(new Potion(new int[] {2438, 151, 153, 155}, new SkillEffect(Skills.FISHING, 3, 0))),
PRAYER(new Potion(new int[] {2434, 139, 141, 143}, new PrayerEffect(7, 0.25))), PRAYER(new Potion(new int[] {2434, 139, 141, 143}, new PrayerEffect(7, 0.25))),
SUPER_RESTO(new Potion(new int[] {3024, 3026, 3028, 3030}, new RestoreEffect(8, 0.25, true))), SUPER_RESTO(new Potion(new int[] {3024, 3026, 3028, 3030}, new RestoreEffect(8, 0.25, true))),
ZAMMY_BREW(new Potion(new int[] {2450, 189, 191, 193}, new MultiEffect(new DamageEffect(10, true, 2), new SkillEffect(Skills.ATTACK, 2, 0.20), new SkillEffect(Skills.STRENGTH, 2, 0.12), new SkillEffect(Skills.DEFENCE, -2, -0.10), new PrayerEffect(0.0, 0.10, true)))), ZAMMY_BREW(new Potion(new int[] {2450, 189, 191, 193}, new MultiEffect(new DamageEffect(10, true), new SkillEffect(Skills.ATTACK, 0, 0.25), new SkillEffect(Skills.STRENGTH, 0, 0.15), new SkillEffect(Skills.DEFENCE, 0, -0.1)))),
ANTIFIRE(new Potion(new int[] {2452, 2454, 2456, 2458}, new AddTimerEffect("dragonfire:immunity", 600, true))), ANTIFIRE(new Potion(new int[] {2452, 2454, 2456, 2458}, new AddTimerEffect("dragonfire:immunity", 600, true))),
GUTH_REST(new Potion(new int[] {4417, 4419, 4421, 4423}, new MultiEffect(new RemoveTimerEffect("poison"), new EnergyEffect(5), new HealingEffect(5)))), GUTH_REST(new Potion(new int[] {4417, 4419, 4421, 4423}, new MultiEffect(new RemoveTimerEffect("poison"), new EnergyEffect(5), new HealingEffect(5)))),
MAGIC_ESS(new Potion(new int[] {9021, 9022, 9023, 9024}, new SkillEffect(Skills.MAGIC,3,0))), MAGIC_ESS(new Potion(new int[] {9021, 9022, 9023, 9024}, new SkillEffect(Skills.MAGIC,3,0))),
@ -363,7 +360,7 @@ public enum Consumables {
/** Barbarian Mixes */ /** Barbarian Mixes */
PRAYERMIX(new BarbarianMix(new int[] {11465, 11467}, new MultiEffect(new PrayerEffect(7, 0.25), new HealingEffect(6)))), PRAYERMIX(new BarbarianMix(new int[] {11465, 11467}, new MultiEffect(new PrayerEffect(7, 0.25), new HealingEffect(6)))),
ZAMMY_MIX(new BarbarianMix(new int[]{11521, 11523}, new MultiEffect(new ZamorakMixEffect(), new SkillEffect(Skills.ATTACK, 2, 0.20), new SkillEffect(Skills.STRENGTH, 2, 0.12), new SkillEffect(Skills.DEFENCE, -2, -0.10)))), ZAMMY_MIX(new BarbarianMix(new int[] {11521, 11523}, new MultiEffect(new DamageEffect(10, true), new SkillEffect(Skills.ATTACK, 0, 0.15), new SkillEffect(Skills.STRENGTH, 0, 0.25), new SkillEffect(Skills.DEFENCE, 0, -0.1)))),
ATT_MIX(new BarbarianMix(new int[] {11429, 11431}, new MultiEffect(new SkillEffect(Skills.ATTACK, 3, 0.1), new HealingEffect(3)))), ATT_MIX(new BarbarianMix(new int[] {11429, 11431}, new MultiEffect(new SkillEffect(Skills.ATTACK, 3, 0.1), new HealingEffect(3)))),
ANTIP_MIX(new BarbarianMix(new int[] {11433, 11435}, new MultiEffect(new AddTimerEffect("poison:immunity", secondsToTicks(90)), new HealingEffect(3)))), ANTIP_MIX(new BarbarianMix(new int[] {11433, 11435}, new MultiEffect(new AddTimerEffect("poison:immunity", secondsToTicks(90)), new HealingEffect(3)))),
RELIC_MIX(new BarbarianMix(new int[] {11437, 11439}, new MultiEffect(new CureDiseaseEffect(), new HealingEffect(3)))), RELIC_MIX(new BarbarianMix(new int[] {11437, 11439}, new MultiEffect(new CureDiseaseEffect(), new HealingEffect(3)))),

View file

@ -7,21 +7,15 @@ import core.game.node.entity.player.Player;
public class DamageEffect extends ConsumableEffect { public class DamageEffect extends ConsumableEffect {
final double amt; final double amt;
final boolean isPercent; final boolean isPercent;
final int baseAmount;
public DamageEffect(double amt, boolean isPercent) { public DamageEffect(double amt,boolean isPercent){
this(amt, isPercent, 0);
}
public DamageEffect(double amt, boolean isPercent, int baseAmount) {
this.amt = amt; this.amt = amt;
this.isPercent = isPercent; this.isPercent = isPercent;
this.baseAmount = baseAmount;
} }
@Override @Override
public void activate(Player p) { public void activate(Player p) {
p.getImpactHandler().manualHit(p, -getHealthEffectValue(p), ImpactHandler.HitsplatType.NORMAL); p.getImpactHandler().manualHit(p,-getHealthEffectValue(p), ImpactHandler.HitsplatType.NORMAL);
} }
@Override @Override
@ -29,8 +23,8 @@ public class DamageEffect extends ConsumableEffect {
double amount = amt; double amount = amt;
if (isPercent) { if (isPercent) {
amount /= 100; amount /= 100;
return (int) -(amount * player.getSkills().getLifepoints() + baseAmount); return (int) -(amount * player.getSkills().getLifepoints());
} }
return (int) -(amt + baseAmount); return (int) -amt;
} }
} }

View file

@ -5,18 +5,16 @@ import core.game.consumable.ConsumableEffect
import core.game.node.entity.player.Player import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills import core.game.node.entity.skill.Skills
import org.rs09.consts.Items import org.rs09.consts.Items
import kotlin.math.ceil
import kotlin.math.floor import kotlin.math.floor
class PrayerEffect @JvmOverloads constructor(var base: Double, var bonus: Double, private val roundUp: Boolean = false) : ConsumableEffect() { class PrayerEffect(var base: Double, var bonus: Double) : ConsumableEffect() {
override fun activate(player: Player?) { override fun activate(player: Player?) {
if(player == null) return if(player == null) return
val level = getStatLevel(player, Skills.PRAYER) val level = getStatLevel(player, Skills.PRAYER)
var b = bonus var b = bonus
if(inInventory(player, Items.HOLY_WRENCH_6714)) if(inInventory(player, Items.HOLY_WRENCH_6714))
b += 0.02 // Leaving this in for futureproofing. Current update is for properly rounding down. b += 0.02 // Leaving this in for futureproofing. Current update is for properly rounding down.
val rawAmount = base + (level * b) val amount = floor(base + (level * b))
val amount = if (roundUp) ceil(rawAmount) else floor(rawAmount)
modPrayerPoints(player, amount) modPrayerPoints(player, amount)
} }
} }

View file

@ -1,25 +0,0 @@
package content.data.consumables.effects;
import core.game.consumable.ConsumableEffect;
import core.game.node.entity.combat.ImpactHandler;
import core.game.node.entity.player.Player;
/**
* The Zamorak mix shows the regular Zamorak brew hitsplat (10% of pre-drink lifepoints + 2, rounded down)
* but also heals 6 lifepoints. The heal must be applied before the hit so the net change can never kill
* the player, while the hitsplat still reflects the pre-heal lifepoints.
*/
public class ZamorakMixEffect extends ConsumableEffect {
@Override
public void activate(Player p) {
int damage = (int) (p.getSkills().getLifepoints() * 0.10 + 2);
p.getSkills().heal(6);
p.getImpactHandler().manualHit(p, damage, ImpactHandler.HitsplatType.NORMAL);
}
@Override
public int getHealthEffectValue(Player player) {
return 6 - (int) (player.getSkills().getLifepoints() * 0.10 + 2);
}
}

View file

@ -1,6 +1,8 @@
package content.global.activity.cchallange.npc package content.global.activity.cchallange.npc
import core.api.* import core.api.*
import core.game.container.impl.EquipmentContainer
import core.game.global.action.EquipHandler
import core.game.node.entity.Entity import core.game.node.entity.Entity
import core.game.node.entity.combat.BattleState import core.game.node.entity.combat.BattleState
import core.game.node.entity.npc.AbstractNPC import core.game.node.entity.npc.AbstractNPC
@ -60,11 +62,12 @@ class LesserDemonChampionNPC(id: Int = 0, location: Location? = null) : Abstract
super.checkImpact(state) super.checkImpact(state)
val player = state.attacker val player = state.attacker
if (player is Player) { if (player is Player) {
if (player.equipment.isEmpty) { if (!player.equipment[3].hasItemPlugin()) {
state.neutralizeHits() state.neutralizeHits()
state.estimatedHit = state.maximumHit state.estimatedHit = state.maximumHit
} else { } else {
sendMessage(player, "You cannot wear any equipment in this challenge.") EquipHandler.unequip(player, EquipmentContainer.SLOT_WEAPON, id)
sendMessage(player, "You cannot use weapons in this challenge.")
if (state.estimatedHit > -1) { if (state.estimatedHit > -1) {
state.estimatedHit = 0 state.estimatedHit = 0
return return

View file

@ -63,8 +63,8 @@ class ZombieChampionNPC(id: Int = 0, location: Location? = null) : AbstractNPC(i
val player = state.attacker val player = state.attacker
if (player is Player) { if (player is Player) {
if (state.style == CombatStyle.MELEE || state.style == CombatStyle.RANGE) { if (state.style == CombatStyle.MELEE || state.style == CombatStyle.RANGE) {
state.neutralizeHits()
state.estimatedHit = state.maximumHit state.estimatedHit = state.maximumHit
state.neutralizeHits()
} }
if (state.style == CombatStyle.MAGIC) { if (state.style == CombatStyle.MAGIC) {
sendMessage(player, "You cannot use spells in this challenge.") sendMessage(player, "You cannot use spells in this challenge.")

View file

@ -30,7 +30,7 @@ class PenguinManager{
return tagMapping[Penguin.forLocation(location)?.ordinal]?.contains(player.username.toLowerCase()) ?: false return tagMapping[Penguin.forLocation(location)?.ordinal]?.contains(player.username.toLowerCase()) ?: false
} }
fun updateStoreFile(){ private fun updateStoreFile(){
val jsonTags = JSONArray() val jsonTags = JSONArray()
tagMapping.filter { it.value.isNotEmpty() }.forEach { (ordinal,taggers) -> tagMapping.filter { it.value.isNotEmpty() }.forEach { (ordinal,taggers) ->
log(this::class.java, Log.FINE, "$ordinal - ${taggers.first()}") log(this::class.java, Log.FINE, "$ordinal - ${taggers.first()}")

View file

@ -44,65 +44,18 @@ enum class Penguin(val id: Int, val hint: String, val location: Location){
BUSH_8(NPCs.BUSH_8105,"located in the kingdom of Asgarnia.",Location.create(2951, 3511, 0)), BUSH_8(NPCs.BUSH_8105,"located in the kingdom of Asgarnia.",Location.create(2951, 3511, 0)),
BUSH_9(NPCs.BUSH_8105,"located in the northern desert.",Location.create(3350, 3311, 0)), BUSH_9(NPCs.BUSH_8105,"located in the northern desert.",Location.create(3350, 3311, 0)),
BUSH_10(NPCs.BUSH_8105,"located somewhere in the kingdom of Kandarin.",Location.create(2633, 3501, 0)), BUSH_10(NPCs.BUSH_8105,"located somewhere in the kingdom of Kandarin.",Location.create(2633, 3501, 0)),
BUSH_11(NPCs.BUSH_8105,"located where wizards study.",Location.create(3112, 3149, 0)), BUSH_11(NPCs.BUSH_8105,"located south of Ardougne.",Location.create(2440, 3206, 0)),
BUSH_12(NPCs.BUSH_8105,"located where wizards study.",Location.create(3112, 3149, 0)),
ROCK_1(NPCs.ROCK_8109,"located where the Imperial Guard train.",Location.create(2852, 3578, 0)), ROCK_1(NPCs.ROCK_8109,"located where the Imperial Guard train.",Location.create(2852, 3578, 0)),
ROCK_2(NPCs.ROCK_8109,"located in the kingdom of Misthalin.",Location.create(3356, 3416, 0)), ROCK_2(NPCs.ROCK_8109,"located in the kingdom of Misthalin.",Location.create(3356, 3416, 0)),
ROCK_3(NPCs.ROCK_8109,"located near some ogres.",Location.create(2631, 2980, 0)), //potentially incorrect location ROCK_3(NPCs.ROCK_8109,"located near some ogres.",Location.create(2631, 2980, 0)),
ROCK_4(NPCs.ROCK_8109,"located in the Kingdom of Asgarnia.",Location.create(3013, 3501, 0)), ROCK_4(NPCs.ROCK_8109,"located in the Kingdom of Asgarnia.",Location.create(3013, 3501, 0)),
ROCK_5(NPCs.ROCK_8109,"located between Fremennik and barbarians.",Location.create(2532, 3630, 0)), ROCK_5(NPCs.ROCK_8109,"located between Fremennik and barbarians.",Location.create(2532, 3630, 0)),
CRATE_1(NPCs.CRATE_8108,"located in the kingdom of Misthalin.",Location.create(3112, 3332, 0)), CRATE_1(NPCs.CRATE_8108,"located in the kingdom of Misthalin.",Location.create(3112, 3332, 0)),
CRATE_2(NPCs.CRATE_8108,"located in the Kingdom of Misthalin.",Location.create(3305, 3508, 0)), CRATE_2(NPCs.CRATE_8108,"located in the Kingdom of Misthalin.",Location.create(3305, 3508, 0)),
CRATE_3(NPCs.CRATE_8108,"located south of Ardougne.",Location.create(2440, 3206, 0)), BARREL_1(NPCs.CRATE_8108,"located where no weapons may go.",Location.create(2806, 3383, 0)),
BARREL_1(NPCs.BARREL_8104,"located where no weapons may go.",Location.create(2806, 3383, 0)),
TOADSTOOL_1(NPCs.TOADSTOOL_8110,"located in the kingdom of Misthalin.",Location.create(3156, 3178, 0)), TOADSTOOL_1(NPCs.TOADSTOOL_8110,"located in the kingdom of Misthalin.",Location.create(3156, 3178, 0)),
TOADSTOOL_2(NPCs.TOADSTOOL_8110,"located in the fairy realm.",Location.create(2409, 4462, 0)), //potentially a spawn from 2010 TOADSTOOL_2(NPCs.TOADSTOOL_8110,"located in the fairy realm.",Location.create(2409, 4462, 0));
BUSH_12(NPCs.BUSH_8105,"located on an island.",Location.create(2534, 3871, 0)),
BARREL_2(NPCs.BARREL_8104,"located near the ghost town.",Location.create(3654, 3491, 0)),
BUSH_13(NPCs.BUSH_8105,"located where bloodsuckers rule.",Location.create(3600, 3487, 0)),
BUSH_14(NPCs.BUSH_8105,"located on islands where brothers quarrel.",Location.create(2355, 3848, 0)),
ROCK_6(NPCs.ROCK_8109,"located on a large crescent island.",Location.create(2118, 3943, 0)),
ROCK_7(NPCs.ROCK_8109,"located on islands where brothers quarrel.",Location.create(2357, 3797, 0)),
ROCK_8(NPCs.ROCK_8109,"located in the Wilderness.",Location.create(3169, 3650, 0)),
BARREL_3(NPCs.BARREL_8104,"located where pirates feel mostly harmless.",Location.create(3738, 3001, 0)),
CACTUS_3(NPCs.CACTUS_8107,"located in the southern desert.",Location.create(3276, 2797, 0)),
TOADSTOOL_3(NPCs.TOADSTOOL_8110,"located near the pointy-eared ones.",Location.create(2314, 3174, 0)),
BUSH_15(NPCs.BUSH_8105,"located deep in the jungle.",Location.create(2938, 2978, 0)),
TOADSTOOL_4(NPCs.TOADSTOOL_8110,"located near the pointy-eared ones.",Location.create(2219, 3227, 0)),
BARREL_4(NPCs.BARREL_8104,"located south of Ardougne.",Location.create(2662, 3152, 0)),
//BARREL_5(NPCs.BARREL_8104,"located where monkeys rule.",Location.create(2751, 2700, 0)),
//currently not well accessible, will need to add when Ape Atoll is sorted.
//BUSH_16(NPCs.BUSH_8105,"located on islands where brothers quarrel.",Location.create(2353, 3834, 0)),
//currently not well accessible, will need to add when Neitiznot bridges are fixed.
ROCK_9(NPCs.ROCK_8109,"located near a mountain of wolves.",Location.create(2852, 3504, 0)),
ROCK_10(NPCs.ROCK_8109,"located on islands where brothers quarrel.",Location.create(2413, 3846, 0)),
BUSH_17(NPCs.BUSH_8105,"located near some ogres.",Location.create(2578, 2909, 0)),
CRATE_4(NPCs.CRATE_8108,"located where banana smugglers dwell.",Location.create(2869, 3157, 0)),
//CRATE_5(NPCs.CRATE_8108,"located near the island of Dragontooth.",Location.create(3824, 3562, 0)),
//current not accessible, will need to add when Dragontooth island is sorted.
ROCK_11(NPCs.ROCK_8109,"located where bloodsuckers rule.",Location.create(3550, 3439, 0)),
TOADSTOOL_5(NPCs.TOADSTOOL_8110,"located near the pointy-eared ones.",Location.create(2181, 3172, 0)),
BUSH_18(NPCs.BUSH_8105,"located where bloodsuckers rule.",Location.create(3472, 3392, 0)),
BUSH_19(NPCs.BUSH_8105,"located near Port Sarim.",Location.create(2989, 3121, 0)),
CRATE_6(NPCs.CRATE_8108,"located where fishers colonise.",Location.create(2322, 3658, 0)),
ROCK_12(NPCs.ROCK_8109,"located between Fremennik and barbarians.",Location.create(2675, 3717, 0)),
ROCK_13(NPCs.ROCK_8109,"located near the pointy-eared ones.",Location.create(2296, 3270, 0)),
CRATE_7(NPCs.CRATE_8108,"located where bloodsuckers rule.",Location.create(3637, 3486, 0)),
TOADSTOOL_6(NPCs.TOADSTOOL_8110,"located where bloodsuckers rule.",Location.create(3416, 3437, 0)),
BUSH_20(NPCs.BUSH_8105,"located where monkeys rule.",Location.create(2802, 2806, 0)),
ROCK_14(NPCs.ROCK_8109,"located near some ogres.",Location.create(2438, 3050, 0)),
CACTUS_4(NPCs.CACTUS_8107,"located in the southern desert.",Location.create(3252, 2963, 0)),
ROCK_15(NPCs.ROCK_8109,"located near some ogres.",Location.create(2340, 3064, 0)),
ROCK_16(NPCs.ROCK_8109,"located in the Wilderness.",Location.create(3108, 3837, 0)),
CACTUS_5(NPCs.CACTUS_8107,"located in the southern desert.",Location.create(3433, 3000, 0)),
CACTUS_6(NPCs.CACTUS_8107,"located in the southern desert.",Location.create(3274, 2813, 0)),
ROCK_17(NPCs.ROCK_8109,"located in the Wilderness.",Location.create(3019, 3866, 0)),
ROCK_18(NPCs.ROCK_8109,"located in the Wilderness.",Location.create(2991, 3824, 0)),
BUSH_21(NPCs.BUSH_8105,"located north of Ardougne.",Location.create(2398, 3361, 0)),
ROCK_19(NPCs.ROCK_8109,"located near the coast.",Location.create(2733, 3283, 0)),
ROCK_20(NPCs.ROCK_8109,"located in the Wilderness.",Location.create(3236, 3927, 0));
companion object { companion object {
private val locationMap = values().map { it.location.toString() to it }.toMap() private val locationMap = values().map { it.location.toString() to it }.toMap()

View file

@ -99,18 +99,12 @@ class ShootingStar(var level: ShootingStarType = ShootingStarType.values().rando
return ShootingStarType.values()[level.ordinal - 1] return ShootingStarType.values()[level.ordinal - 1]
} }
/**
* Clears the current star object or sprite
*/
fun clear() {
SceneryBuilder.remove(starObject)
clearSprite()
}
/** /**
* Fires the shooting star (spawns a new one). Only used when spawning new shooting stars, not for downgrading existing ones. * Fires the shooting star (spawns a new one). Only used when spawning new shooting stars, not for downgrading existing ones.
*/ */
fun fire() { fun fire() {
SceneryBuilder.remove(starObject)
clearSprite()
SceneryBuilder.add(starObject) SceneryBuilder.add(starObject)
if(!isSpawned) { if(!isSpawned) {
(0..2).forEach { (0..2).forEach {

View file

@ -17,7 +17,6 @@ import core.game.world.GameWorld
import core.tools.Log import core.tools.Log
import core.tools.secondsToTicks import core.tools.secondsToTicks
import content.data.Quests import content.data.Quests
import core.game.node.scenery.SceneryBuilder
class ShootingStarPlugin : LoginListener, InteractionListener, TickListener, Commands, StartupListener { class ShootingStarPlugin : LoginListener, InteractionListener, TickListener, Commands, StartupListener {
override fun login(player: Player) { override fun login(player: Player) {
@ -47,7 +46,6 @@ class ShootingStarPlugin : LoginListener, InteractionListener, TickListener, Com
// Check if it's time to fire a new one // Check if it's time to fire a new one
if (star.ticks >= tickDelay && !star.spriteSpawned) { if (star.ticks >= tickDelay && !star.spriteSpawned) {
star.clear()
star.rebuildVars() star.rebuildVars()
star.fire() star.fire()
} }
@ -140,7 +138,6 @@ class ShootingStarPlugin : LoginListener, InteractionListener, TickListener, Com
} }
define("submit", Privilege.ADMIN, description = "Rebuilds and fires the shooting star event immediately.") { _, _ -> define("submit", Privilege.ADMIN, description = "Rebuilds and fires the shooting star event immediately.") { _, _ ->
star.clear()
star.rebuildVars() star.rebuildVars()
star.fire() star.fire()
} }

View file

@ -1,10 +1,8 @@
package content.global.ame package content.global.ame
import content.global.ame.events.surpriseexam.MysteriousOldManNPC import content.global.ame.events.surpriseexam.MysteriousOldManNPC
import core.api.getAttribute
import core.api.playGlobalAudio import core.api.playGlobalAudio
import core.api.poofClear import core.api.poofClear
import core.api.removeAttribute
import core.api.sendMessage import core.api.sendMessage
import core.api.setAttribute import core.api.setAttribute
import core.api.utils.WeightBasedTable import core.api.utils.WeightBasedTable
@ -27,6 +25,8 @@ import core.tools.secondsToTicks
import core.tools.ticksToCycles import core.tools.ticksToCycles
import org.rs09.consts.NPCs import org.rs09.consts.NPCs
import org.rs09.consts.Sounds import org.rs09.consts.Sounds
import kotlin.math.ceil
import kotlin.math.min
import kotlin.random.Random import kotlin.random.Random
import kotlin.reflect.full.createInstance import kotlin.reflect.full.createInstance
@ -37,8 +37,8 @@ abstract class RandomEventNPC(id: Int) : NPC(id) {
val SMOKE_GRAPHICS = Graphics(86) val SMOKE_GRAPHICS = Graphics(86)
var initialized = false var initialized = false
var finalized = false var finalized = false
var timerPaused = false
var ticksLeft = secondsToTicks(180) var ticksLeft = secondsToTicks(180)
private val combatBracket = intArrayOf(10, 20, 40, 60, 90)
open fun create(player: Player, loot: WeightBasedTable? = null, type: String = ""): RandomEventNPC { open fun create(player: Player, loot: WeightBasedTable? = null, type: String = ""): RandomEventNPC {
val event = this::class.createInstance() val event = this::class.createInstance()
@ -56,7 +56,6 @@ abstract class RandomEventNPC(id: Int) : NPC(id) {
poofClear(this) poofClear(this)
playGlobalAudio(this.location, Sounds.SMOKEPUFF_1930, ticksToCycles(1)) playGlobalAudio(this.location, Sounds.SMOKEPUFF_1930, ticksToCycles(1))
} }
removeAttribute(player, "random:pause")
finalized = true finalized = true
} }
@ -93,6 +92,7 @@ abstract class RandomEventNPC(id: Int) : NPC(id) {
override fun init() { override fun init() {
initialized = true initialized = true
finalized = false finalized = false
timerPaused = false
spawnLocation ?: terminate() spawnLocation ?: terminate()
location = spawnLocation location = spawnLocation
player.setAttribute("re-npc", this) player.setAttribute("re-npc", this)
@ -144,13 +144,12 @@ abstract class RandomEventNPC(id: Int) : NPC(id) {
} }
fun idForCombatLevel(ids: List<Int>, player: Player): Int { fun idForCombatLevel(ids: List<Int>, player: Player): Int {
val index = combatBracket.indexOfFirst { player.properties.currentCombatLevel <= it }.takeIf { it != -1 }?: ids.lastIndex val index = min(ids.size, ceil(player.properties.currentCombatLevel / 20.0).toInt()) - 1
return ids[index] return ids[index]
} }
fun sayLine(npc: NPC, phrases: Array<String>, hasOpeningPhrase: Boolean, hasOverTimePhrase: Boolean) { fun sayLine(npc: NPC, phrases: Array<String>, hasOpeningPhrase: Boolean, hasOverTimePhrase: Boolean) {
val inInteraction = getAttribute(player, "random:pause", false) //used by Certer if (!timerPaused && (ticksLeft % 20 == 0 || ticksLeft <= 2)) { //unless the Certer interface is up, speak every 20 ticks, or in the 2nd-to-last tick before attack/note-&-teleport
if ((ticksLeft % 20 == 0 || ticksLeft <= 2) && !inInteraction) { //speak every 20 ticks, or in the 2nd-to-last tick before attack/note-&-teleport
var playDwarfWhistle = true var playDwarfWhistle = true
if (ticksLeft == secondsToTicks(180) && hasOpeningPhrase) { if (ticksLeft == secondsToTicks(180) && hasOpeningPhrase) {
sendChat(phrases[0]) sendChat(phrases[0])

View file

@ -6,7 +6,6 @@ import org.rs09.consts.NPCs
import content.global.ame.RandomEventNPC import content.global.ame.RandomEventNPC
import core.api.animate import core.api.animate
import core.api.lock import core.api.lock
import core.api.setAttribute
import core.api.utils.WeightBasedTable import core.api.utils.WeightBasedTable
class CerterNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.GILES_2538) { class CerterNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.GILES_2538) {
@ -34,7 +33,8 @@ class CerterNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NP
"It's really rude to ignore someone, ${player.username}!", "It's really rude to ignore someone, ${player.username}!",
"No-one ignores me!" "No-one ignores me!"
) )
setAttribute(player, "certer:reward", false) player.setAttribute("random:pause", false)
player.setAttribute("certer:reward", false)
animate(this, Emotes.BOW.animation, true) animate(this, Emotes.BOW.animation, true)
} }

View file

@ -73,9 +73,9 @@ object DrillDemonUtils {
fun reward(player: Player) { fun reward(player: Player) {
queueScript(player, 2, QueueStrength.SOFT) { queueScript(player, 2, QueueStrength.SOFT) {
val hasHat = hasAnItem(player, Items.CAMO_HELMET_6656, checkPOH = true).exists() val hasHat = hasAnItem(player, Items.CAMO_HELMET_6656).container != null
val hasShirt = hasAnItem(player, Items.CAMO_TOP_6654, checkPOH = true).exists() val hasShirt = hasAnItem(player, Items.CAMO_TOP_6654).container != null
val hasPants = hasAnItem(player, Items.CAMO_BOTTOMS_6655, checkPOH = true).exists() val hasPants = hasAnItem(player, Items.CAMO_BOTTOMS_6655).container != null
when { when {
!hasHat -> addItemOrDrop(player, Items.CAMO_HELMET_6656) !hasHat -> addItemOrDrop(player, Items.CAMO_HELMET_6656)
!hasShirt -> addItemOrDrop(player, Items.CAMO_TOP_6654) !hasShirt -> addItemOrDrop(player, Items.CAMO_TOP_6654)

View file

@ -8,14 +8,12 @@ import core.game.node.item.Item
import core.tools.RandomFunction import core.tools.RandomFunction
import org.rs09.consts.Items import org.rs09.consts.Items
import content.global.ame.RandomEventNPC import content.global.ame.RandomEventNPC
import core.api.sendMessage
import core.api.utils.WeightBasedTable import core.api.utils.WeightBasedTable
val ids = (2463..2468).toList() val ids = (2463..2468).toList()
class EvilChickenNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(2463) { class EvilChickenNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(2463) {
val phrases = arrayOf("Bwuk","Bwuk bwuk bwuk","Flee from me, @name!","Begone, @name!","Bwaaaauuuk bwuk bwuk","MUAHAHAHAHAAA!") val phrases = arrayOf("Bwuk","Bwuk bwuk bwuk","Flee from me, @name!","Begone, @name!","Bwaaaauuuk bwuk bwuk","MUAHAHAHAHAAA!")
var sentMessage = false
override fun talkTo(npc: NPC) {} override fun talkTo(npc: NPC) {}
override fun init() { override fun init() {
@ -33,16 +31,13 @@ class EvilChickenNPC(override var loot: WeightBasedTable? = null) : RandomEventN
} }
override fun tick() { override fun tick() {
if (!sentMessage) { if(!player.location.withinDistance(this.location,8)){
if (!player.location.withinDistance(this.location, 8)) { this.terminate()
// https://www.youtube.com/watch?v=v9p_I_Tq3JE
sendMessage(player, "The Evil Chicken realises you're out of range and vanishes.")
sentMessage = true
terminate()
} else if (getWorldTicks() % 10 == 0) {
sendChat(phrases.random().replace("@name", player.username.capitalize()))
} }
if(getWorldTicks() % 10 == 0){
sendChat(phrases.random().replace("@name",player.username.capitalize()))
} }
super.tick() super.tick()
if(!player.viewport.currentPlane.npcs.contains(this)) this.clear()
} }
} }

View file

@ -35,9 +35,9 @@ object FreakUtils{
} }
fun reward(player: Player){ fun reward(player: Player){
val hasHat = hasAnItem(player, Items.LEDERHOSEN_HAT_6182, checkPOH = true).exists() val hasHat = hasAnItem(player, Items.LEDERHOSEN_HAT_6182).container != null
val hasTop = hasAnItem(player, Items.LEDERHOSEN_TOP_6180, checkPOH = true).exists() val hasTop = hasAnItem(player, Items.LEDERHOSEN_TOP_6180).container != null
val hasShort = hasAnItem(player, Items.LEDERHOSEN_SHORTS_6181, checkPOH = true).exists() val hasShort = hasAnItem(player, Items.LEDERHOSEN_SHORTS_6181).container != null
sendNPCDialogue(player, freakNpc, "You get a lederhosen item as a reward for your help, many thanks!") sendNPCDialogue(player, freakNpc, "You get a lederhosen item as a reward for your help, many thanks!")
when{ when{
(!hasHat) -> addItemOrDrop(player, Items.LEDERHOSEN_HAT_6182, 1) (!hasHat) -> addItemOrDrop(player, Items.LEDERHOSEN_HAT_6182, 1)

View file

@ -12,6 +12,8 @@ import core.game.interaction.InteractionListener
import core.game.interaction.QueueStrength import core.game.interaction.QueueStrength
import core.game.node.entity.Entity import core.game.node.entity.Entity
import core.game.node.entity.player.Player import core.game.node.entity.player.Player
import core.game.system.task.Pulse
import core.game.world.GameWorld.Pulser
import core.game.world.map.Location import core.game.world.map.Location
import core.game.world.map.zone.ZoneBorders import core.game.world.map.zone.ZoneBorders
import core.game.world.map.zone.ZoneRestriction import core.game.world.map.zone.ZoneRestriction
@ -74,23 +76,9 @@ class MazeInterface : InteractionListener, EventHook<TickEvent>, MapArea {
WeightedItem(Items.DEFENCE_POTION2_135,1,1,1.0), WeightedItem(Items.DEFENCE_POTION2_135,1,1,1.0),
) )
private val ONE_WAY_WALL = mapOf(
Location.create(2904, 4573, 0) to setOf( // Diagonal entries
Location.create(2904, 4573, 0),
Location.create(2904, 4572, 0),
Location.create(2904, 4574, 0),
),
Location.create(2906, 4586, 0) to setOf( // Diagonal entries
Location.create(2906, 4586, 0),
Location.create(2907, 4586, 0),
),
Location.create(2902, 4575, 0) to setOf(Location.create(2903, 4575, 0)),
Location.create(2924, 4583, 0) to setOf(Location.create(2923, 4583, 0)),
)
fun initMaze(player: Player) { fun initMaze(player: Player) {
setAttribute(player, MAZE_ATTRIBUTE_TICKS_LEFT, 500) setAttribute(player, MAZE_ATTRIBUTE_TICKS_LEFT, 300)
setVarp(player, MAZE_TIMER_VARP, (getAttribute<Int>(player, MAZE_ATTRIBUTE_TICKS_LEFT, 0) + 4) / 5,false) setVarp(player, MAZE_TIMER_VARP, (getAttribute<Int>(player, MAZE_ATTRIBUTE_TICKS_LEFT, 0) / 3),false)
openOverlay(player, MAZE_TIMER_INTERFACE) openOverlay(player, MAZE_TIMER_INTERFACE)
sendMessage(player, "You need to reach the maze center, then you'll be returned to where you were.") sendMessage(player, "You need to reach the maze center, then you'll be returned to where you were.")
sendNPCDialogue(player, NPCs.MYSTERIOUS_OLD_MAN_410, "You need to reach the maze center, then you'll be returned to where you were.") sendNPCDialogue(player, NPCs.MYSTERIOUS_OLD_MAN_410, "You need to reach the maze center, then you'll be returned to where you were.")
@ -99,7 +87,7 @@ class MazeInterface : InteractionListener, EventHook<TickEvent>, MapArea {
fun calculateLoot(player: Player) { fun calculateLoot(player: Player) {
val randomNumber = (0..8).random() val randomNumber = (0..8).random()
val totalLevel = player.getSkills().totalLevel.toDouble() val totalLevel = player.getSkills().totalLevel.toDouble()
val rewardPotential = getAttribute(player, MAZE_ATTRIBUTE_TICKS_LEFT, 0).toDouble() / 500.0 val rewardPotential = getAttribute(player, MAZE_ATTRIBUTE_TICKS_LEFT, 0).toDouble() / 300.0
val itemDivisor = ITEM_DIVISOR[randomNumber] val itemDivisor = ITEM_DIVISOR[randomNumber]
val itemQuantity = (totalLevel * rewardPotential * 3.33) / itemDivisor val itemQuantity = (totalLevel * rewardPotential * 3.33) / itemDivisor
// sendMessage(player, "Maze reward calculation: $totalLevel * $rewardPotential * 3.33 / $itemDivisor = $itemQuantity") // sendMessage(player, "Maze reward calculation: $totalLevel * $rewardPotential * 3.33 / $itemDivisor = $itemQuantity")
@ -107,17 +95,73 @@ class MazeInterface : InteractionListener, EventHook<TickEvent>, MapArea {
addItemOrDrop(player, REWARD_ITEM[randomNumber], itemQuantity.toInt()) addItemOrDrop(player, REWARD_ITEM[randomNumber], itemQuantity.toInt())
} }
} }
/**
* Chest Location to rotation mapping.
* This is needed as it is impossible to obtain the underlying chest scenery for the rotation.
* 0: Facing North, 1: Facing East, 2: Facing South, 3: Facing West
*/
val chestLocationRotationMap = mapOf(
Location(2930, 4595, 0).toString() to 2,
Location(2924, 4572, 0).toString() to 2,
Location(2925, 4573, 0).toString() to 0,
Location(2900, 4578, 0).toString() to 2,
Location(2901, 4560, 0).toString() to 1,
Location(2890, 4599, 0).toString() to 2,
Location(2896, 4591, 0).toString() to 2,
Location(2895, 4592, 0).toString() to 1,
Location(2901, 4560, 0).toString() to 3,
Location(2918, 4590, 0).toString() to 1,
Location(2917, 4590, 0).toString() to 3,
)
/**
* Chest Interaction workaround
*
* The issue here is that the walls(3626) of the Maze are overlapping some(not all) chest sceneries.
*
* The types for the wallScenery:
* Type 0 - flat panel |
* Type 2 - right angle panel with rotation 0:r 1:7 2:> 3:L
* Type 3 - corner post . for angle edges of walls
*/
fun overrideScenery(wallScenery: core.game.node.scenery.Scenery, chestSceneryId: Int): core.game.node.scenery.Scenery {
if (wallScenery.id == chestSceneryId) {
replaceScenery(wallScenery, Scenery.CHEST_3636, 30)
wallScenery.isActive = true
return wallScenery // Return the chest scenery as the wallScenery isn't there.
}
addScenery(Scenery.CHEST_3636, wallScenery.location, chestLocationRotationMap[wallScenery.location.toString()] ?: 0, 10)
addScenery(wallScenery)
// replaceScenery(newChestScenery, Scenery.CHEST_3636, 3) // didn't work for an underlying scenery
// I did a world pulse since everyone will get to see the chest open.
Pulser.submit(object : Pulse(30) {
override fun pulse(): Boolean {
addScenery(Scenery.CHEST_3635, wallScenery.location, chestLocationRotationMap[wallScenery.location.toString()] ?: 0, 10)
addScenery(wallScenery)
return true
}
})
// Return the chest scenery to replace PacketProcessor so that MISMATCH will not happen.
return core.game.node.scenery.Scenery(
chestSceneryId,
wallScenery.location,
chestLocationRotationMap[wallScenery.location.toString()] ?: 0
)
}
} }
override fun defineListeners() { override fun defineListeners() {
// This somehow doesn't trigger as the scenery.id != objId (3626 != 3635)
on(Scenery.CHEST_3635, IntType.SCENERY, "open") { player, node -> on(Scenery.CHEST_3635, IntType.SCENERY, "open") { player, node ->
lock(player, 3)
animate(player, 536)
replaceScenery(node.asScenery(), Scenery.CHEST_3636, 3)
if (getAttribute(player, MAZE_ATTRIBUTE_TICKS_LEFT, 0) > 0 && getAttribute(player, MAZE_ATTRIBUTE_CHESTS_OPEN, 0) < 10) { if (getAttribute(player, MAZE_ATTRIBUTE_TICKS_LEFT, 0) > 0 && getAttribute(player, MAZE_ATTRIBUTE_CHESTS_OPEN, 0) < 10) {
animate(player, 536)
// val actualScenery = RegionManager.getObject(node.location.z, node.location.x, node.location.y, 3626)
val tableRoll = CHEST_REWARDS.roll() val tableRoll = CHEST_REWARDS.roll()
addItemOrBank(player, tableRoll[0].id, tableRoll[0].amount) addItemOrBank(player, tableRoll[0].id, tableRoll[0].amount)
when (tableRoll[0].id) { when (tableRoll[0].id){
Items.AIR_RUNE_556 -> sendItemDialogue(player, Items.AIR_RUNE_556, "You've found some air runes!") Items.AIR_RUNE_556 -> sendItemDialogue(player, Items.AIR_RUNE_556, "You've found some air runes!")
Items.WATER_RUNE_555 -> sendItemDialogue(player, Items.WATER_RUNE_555, "You've found some water runes!") Items.WATER_RUNE_555 -> sendItemDialogue(player, Items.WATER_RUNE_555, "You've found some water runes!")
Items.EARTH_RUNE_557 -> sendItemDialogue(player, Items.EARTH_RUNE_557, "You've found some earth runes!") Items.EARTH_RUNE_557 -> sendItemDialogue(player, Items.EARTH_RUNE_557, "You've found some earth runes!")
@ -129,7 +173,7 @@ class MazeInterface : InteractionListener, EventHook<TickEvent>, MapArea {
Items.STRENGTH_POTION2_117 -> sendItemDialogue(player, Items.STRENGTH_POTION2_117, "You've found a strength potion!") Items.STRENGTH_POTION2_117 -> sendItemDialogue(player, Items.STRENGTH_POTION2_117, "You've found a strength potion!")
Items.DEFENCE_POTION2_135 -> sendItemDialogue(player, Items.DEFENCE_POTION2_135, "You've found a defence potion!") Items.DEFENCE_POTION2_135 -> sendItemDialogue(player, Items.DEFENCE_POTION2_135, "You've found a defence potion!")
} }
setAttribute(player, MAZE_ATTRIBUTE_CHESTS_OPEN, getAttribute(player, MAZE_ATTRIBUTE_CHESTS_OPEN, 0) + 1) setAttribute(player, MAZE_ATTRIBUTE_CHESTS_OPEN, getAttribute(player, MAZE_ATTRIBUTE_CHESTS_OPEN, 0))
} else { } else {
sendMessage(player,"You find nothing of interest.") sendMessage(player,"You find nothing of interest.")
} }
@ -146,25 +190,10 @@ class MazeInterface : InteractionListener, EventHook<TickEvent>, MapArea {
return@on true return@on true
} }
on( on(Scenery.WALL_3628, IntType.SCENERY, "open") { player, node ->
intArrayOf( // Door opening workaround
Scenery.WALL_3628, // Ignore 3629(WALL_3629) and 3630(WALL_3630) in handleAutowalkDoor ignoreSecondDoor
Scenery.WALL_3629, DoorActionHandler.handleAutowalkDoor(player, node as core.game.node.scenery.Scenery)
Scenery.WALL_3630,
Scenery.WALL_3631,
Scenery.WALL_3632,
),
IntType.SCENERY,
"open"
) { player, node ->
val scenery = node as core.game.node.scenery.Scenery
if (ONE_WAY_WALL[scenery.location]?.contains(player.location) == true) {
sendDialogue(player, "I don't think that's the right way.")
} else {
DoorActionHandler.handleAutowalkDoor(player, scenery)
}
return@on true return@on true
} }
@ -211,7 +240,7 @@ class MazeInterface : InteractionListener, EventHook<TickEvent>, MapArea {
if (getAttribute(entity, MAZE_ATTRIBUTE_TICKS_LEFT, 0) > 0) { if (getAttribute(entity, MAZE_ATTRIBUTE_TICKS_LEFT, 0) > 0) {
setAttribute(entity, MAZE_ATTRIBUTE_TICKS_LEFT, getAttribute(entity, MAZE_ATTRIBUTE_TICKS_LEFT, 0) - 1) setAttribute(entity, MAZE_ATTRIBUTE_TICKS_LEFT, getAttribute(entity, MAZE_ATTRIBUTE_TICKS_LEFT, 0) - 1)
} }
setVarp(entity, MAZE_TIMER_VARP, (getAttribute(entity, MAZE_ATTRIBUTE_TICKS_LEFT, 0) + 4) / 5, false) setVarp(entity, MAZE_TIMER_VARP, (getAttribute(entity, MAZE_ATTRIBUTE_TICKS_LEFT, 0) / 3), false)
} }
} }

View file

@ -78,6 +78,9 @@ class QuizMasterDialogueFile : DialogueLabeller() {
override fun addConversation() { override fun addConversation() {
assignToIds(NPCs.QUIZ_MASTER_2477) assignToIds(NPCs.QUIZ_MASTER_2477)
afterClose { player ->
loadLabel(player, "question")
}
npc(FacialExpression.FRIENDLY,"WELCOME to the GREATEST QUIZ SHOW in the", "whole of ${ServerConstants.SERVER_NAME}:", "<col=8A0808>O D D</col> <col=8A088A>O N E</col> <col=08088A>O U T</col>", unclosable = true) npc(FacialExpression.FRIENDLY,"WELCOME to the GREATEST QUIZ SHOW in the", "whole of ${ServerConstants.SERVER_NAME}:", "<col=8A0808>O D D</col> <col=8A088A>O N E</col> <col=08088A>O U T</col>", unclosable = true)
player(FacialExpression.THINKING, "I'm sure I didn't ask to take part in a quiz show...", unclosable = true) player(FacialExpression.THINKING, "I'm sure I didn't ask to take part in a quiz show...", unclosable = true)

View file

@ -23,7 +23,7 @@ class QuizMasterNPC(var type: String = "", override var loot: WeightBasedTable?
super.init() super.init()
sendChat("Hey ${player.username}! It's your lucky day!") sendChat("Hey ${player.username}! It's your lucky day!")
face(player) face(player)
kidnapPlayer(this, player, Location(1952, 4764, 1)) { player, _ -> kidnapPlayer(this, player, Location(1952, 4764, 0)) { player, _ ->
setAttribute(player, QuizMasterDialogueFile.QUIZMASTER_ATTRIBUTE_QUESTIONS_CORRECT, 0) setAttribute(player, QuizMasterDialogueFile.QUIZMASTER_ATTRIBUTE_QUESTIONS_CORRECT, 0)
sendMessage(player, "Answer four questions correctly in a row to be teleported back where you came from.") sendMessage(player, "Answer four questions correctly in a row to be teleported back where you came from.")
sendMessage(player, "You will need to relog in if you lose the quiz dialog.") // Inauthentic, but there to notify the player in case. sendMessage(player, "You will need to relog in if you lose the quiz dialog.") // Inauthentic, but there to notify the player in case.

View file

@ -4,7 +4,6 @@ import core.game.node.entity.Entity
import core.game.node.entity.npc.NPC import core.game.node.entity.npc.NPC
import content.global.ame.RandomEventNPC import content.global.ame.RandomEventNPC
import core.api.utils.WeightBasedTable import core.api.utils.WeightBasedTable
import core.game.world.map.MapDistance
val ids = (391..396).toList() val ids = (391..396).toList()
@ -22,12 +21,10 @@ class RiverTrollRENPC(override var loot: WeightBasedTable? = null) : RandomEvent
super.finalizeDeath(killer) super.finalizeDeath(killer)
} }
override fun tick() { override fun tick() {
if (!player.location.withinDistance(this.location, 8)) { if(!player.location.withinDistance(this.location,8)){
this.terminate() this.terminate()
} }
super.tick() super.tick()
if (!player.location.withinDistance(this.location, MapDistance.RENDERING.distance)) { if(!player.viewport.currentPlane.npcs.contains(this)) this.clear()
this.clear()
}
} }
} }

View file

@ -4,7 +4,6 @@ import core.game.node.entity.Entity
import core.game.node.entity.npc.NPC import core.game.node.entity.npc.NPC
import content.global.ame.RandomEventNPC import content.global.ame.RandomEventNPC
import core.api.utils.WeightBasedTable import core.api.utils.WeightBasedTable
import core.game.world.map.MapDistance
val ids = (413..418).toList() val ids = (413..418).toList()
@ -22,12 +21,10 @@ class RockGolemRENPC(override var loot: WeightBasedTable? = null) : RandomEventN
super.finalizeDeath(killer) super.finalizeDeath(killer)
} }
override fun tick() { override fun tick() {
if (!player.location.withinDistance(this.location, 8)) { if(!player.location.withinDistance(this.location,8)){
this.terminate() this.terminate()
} }
super.tick() super.tick()
if (!player.location.withinDistance(this.location, MapDistance.RENDERING.distance)) { if(!player.viewport.currentPlane.npcs.contains(this)) this.clear()
this.clear()
}
} }
} }

View file

@ -4,7 +4,6 @@ import core.game.node.entity.Entity
import core.game.node.entity.npc.NPC import core.game.node.entity.npc.NPC
import content.global.ame.RandomEventNPC import content.global.ame.RandomEventNPC
import core.api.utils.WeightBasedTable import core.api.utils.WeightBasedTable
import core.game.world.map.MapDistance
class ShadeRENPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(425){ class ShadeRENPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(425){
val ids = (425..430).toList() val ids = (425..430).toList()
@ -21,12 +20,10 @@ class ShadeRENPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(4
super.finalizeDeath(killer) super.finalizeDeath(killer)
} }
override fun tick() { override fun tick() {
if (!player.location.withinDistance(this.location, 8)) { if(!player.location.withinDistance(this.location,8)){
this.terminate() this.terminate()
} }
super.tick() super.tick()
if (!player.location.withinDistance(this.location, MapDistance.RENDERING.distance)) { if(!player.viewport.currentPlane.npcs.contains(this)) this.clear()
this.clear()
}
} }
} }

View file

@ -4,7 +4,6 @@ import core.game.node.entity.Entity
import core.game.node.entity.npc.NPC import core.game.node.entity.npc.NPC
import content.global.ame.RandomEventNPC import content.global.ame.RandomEventNPC
import core.api.utils.WeightBasedTable import core.api.utils.WeightBasedTable
import core.game.world.map.MapDistance
val ids = (438..443).toList() val ids = (438..443).toList()
@ -22,12 +21,10 @@ class TreeSpiritRENPC(override var loot: WeightBasedTable? = null) : RandomEvent
super.finalizeDeath(killer) super.finalizeDeath(killer)
} }
override fun tick() { override fun tick() {
if (!player.location.withinDistance(this.location, 8)) { if(!player.location.withinDistance(this.location,8)){
this.terminate() this.terminate()
} }
super.tick() super.tick()
if (!player.location.withinDistance(this.location, MapDistance.RENDERING.distance)) { if(!player.viewport.currentPlane.npcs.contains(this)) this.clear()
this.clear()
}
} }
} }

View file

@ -4,7 +4,6 @@ import core.game.node.entity.Entity
import core.game.node.entity.npc.NPC import core.game.node.entity.npc.NPC
import content.global.ame.RandomEventNPC import content.global.ame.RandomEventNPC
import core.api.utils.WeightBasedTable import core.api.utils.WeightBasedTable
import core.game.world.map.MapDistance
class ZombieRENPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(419){ class ZombieRENPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(419){
val ids = (419..424).toList() val ids = (419..424).toList()
@ -21,12 +20,10 @@ class ZombieRENPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(
super.finalizeDeath(killer) super.finalizeDeath(killer)
} }
override fun tick() { override fun tick() {
if (!player.location.withinDistance(this.location, 8)) { if(!player.location.withinDistance(this.location,8)){
this.terminate() this.terminate()
} }
super.tick() super.tick()
if (!player.location.withinDistance(this.location, MapDistance.RENDERING.distance)) { if(!player.viewport.currentPlane.npcs.contains(this)) this.clear()
this.clear()
}
} }
} }

View file

@ -11,20 +11,24 @@ import core.game.world.GameWorld
import core.game.world.map.Location import core.game.world.map.Location
import core.game.world.map.RegionManager import core.game.world.map.RegionManager
import core.game.world.map.zone.ZoneBorders import core.game.world.map.zone.ZoneBorders
import core.game.world.update.flag.*
import org.json.simple.JSONArray import org.json.simple.JSONArray
import org.json.simple.JSONObject import org.json.simple.JSONObject
import core.ServerConstants import core.ServerConstants
import core.api.log
import core.game.bots.AIRepository import core.game.bots.AIRepository
import core.game.bots.CombatBotAssembler import core.game.bots.CombatBotAssembler
import core.game.bots.Script import core.game.bots.Script
import core.game.interaction.IntType import core.game.interaction.IntType
import core.game.interaction.InteractionListeners import core.game.interaction.InteractionListeners
import core.tools.Log
import java.io.File import java.io.File
import java.io.FileReader import java.io.FileReader
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
import kotlin.random.Random import kotlin.random.Random
/** /**
* A bot script for Adventurers who explore the world! * A bot script for Adventurers who explore the world!
* @param counter used in the bots random idling function. * @param counter used in the bots random idling function.
@ -110,7 +114,7 @@ class Adventurer(val style: CombatStyle): Script() {
} }
private fun otherPlayersNearby(): Boolean { private fun otherPlayersNearby(): Boolean {
val localPlayers = RegionManager.getLocalPlayers(bot.location) val localPlayers = RegionManager.getLocalPlayers(bot)
val otherPlayers = localPlayers.filter { it.name != bot.name } val otherPlayers = localPlayers.filter { it.name != bot.name }
return otherPlayers.isNotEmpty() return otherPlayers.isNotEmpty()
} }
@ -499,7 +503,7 @@ class Adventurer(val style: CombatStyle): Script() {
dateCode == 404 -> lineAlt = dialogue.getLines("easter").rand() dateCode == 404 -> lineAlt = dialogue.getLines("easter").rand()
} }
val localPlayers = RegionManager.getLocalPlayers(bot.location) var localPlayers = RegionManager.getLocalPlayers(bot)
if (localPlayers.isNotEmpty()) { if (localPlayers.isNotEmpty()) {
val localPlayer = localPlayers val localPlayer = localPlayers
.filter { it.name != bot.name } .filter { it.name != bot.name }

View file

@ -58,7 +58,7 @@ class CannonballSmelter : Script() {
} else if(!coalMine.insideBorder(bot)){ } else if(!coalMine.insideBorder(bot)){
scriptAPI.walkTo(coalMine.randomLoc) scriptAPI.walkTo(coalMine.randomLoc)
} else { } else {
val rock = scriptAPI.getNearestObjectByPredicate { node -> node?.name?.equals("rocks", true)!! && MiningNode.forId(node.id)?.reward == Items.COAL_453 } val rock = scriptAPI.getNearestObjectByPredicate({node -> node?.name?.equals("rocks", true)!! && MiningNode.forId(node?.id!!).reward == Items.COAL_453 })
if(rock != null) { if(rock != null) {
scriptAPI.interact(bot, rock, "mine") scriptAPI.interact(bot, rock, "mine")
} else { } else {
@ -75,7 +75,7 @@ class CannonballSmelter : Script() {
var loc = ironMine.randomLoc var loc = ironMine.randomLoc
scriptAPI.walkTo(loc) scriptAPI.walkTo(loc)
} else { } else {
val rock = scriptAPI.getNearestObjectByPredicate { node -> node?.name?.equals("rocks", true)!! && MiningNode.forId(node.id)?.reward == Items.IRON_ORE_440 } val rock = scriptAPI.getNearestObjectByPredicate({node -> node?.name?.equals("rocks", true)!! && MiningNode.forId(node?.id!!).reward == Items.IRON_ORE_440 })
//rock?.let { InteractionListeners.run(rock.id, IntType.SCENERY,"mine",bot,rock) } //rock?.let { InteractionListeners.run(rock.id, IntType.SCENERY,"mine",bot,rock) }
if(rock != null) { if(rock != null) {
scriptAPI.interact(bot, rock, "mine") scriptAPI.interact(bot, rock, "mine")

View file

@ -262,12 +262,10 @@ class DoublingMoney : Script() {
minDist = min(minDist, loc.getDistance(bot.location)) minDist = min(minDist, loc.getDistance(bot.location))
} }
if (minDist > 1) return 2 if (minDist > 1) return 2
val region = RegionManager.forId(bot.location.regionId) RegionManager.forId(bot.location.regionId).planes[bot.location.z].players.forEach {
val players = region.assemblePlayerList(bot.location.z) if (AIRepository.PulseRepository[it?.username?.lowercase()]?.botScript is DoublingMoney
for (player in players) { && it != bot
if (AIRepository.PulseRepository[player.username.lowercase()]?.botScript is DoublingMoney && it.location.getDistance(bot.location) <= 1) {
&& player != bot
&& player.location.getDistance(bot.location) <= 1) {
return 2 return 2
} }
} }

View file

@ -5,7 +5,6 @@ import core.game.bots.SkillingBotAssembler
import core.game.bots.Script import core.game.bots.Script
import core.game.interaction.IntType import core.game.interaction.IntType
import core.game.interaction.InteractionListeners import core.game.interaction.InteractionListeners
import core.game.node.entity.skill.Skills
import java.util.* import java.util.*
class ManThiever : Script() { class ManThiever : Script() {
@ -23,6 +22,6 @@ class ManThiever : Script() {
} }
init { init {
skills[Skills.THIEVING] = 20 equipment.addAll(Arrays.asList(Item(1103), Item(1139), Item(1265)))
} }
} }

View file

@ -2,7 +2,6 @@ package content.global.dialogue;
import content.global.handlers.item.book.GeneralRuleBook; import content.global.handlers.item.book.GeneralRuleBook;
import core.game.dialogue.DialoguePlugin; import core.game.dialogue.DialoguePlugin;
import core.game.diary.DiaryLevel;
import core.game.node.entity.npc.NPC; import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player; import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.diary.DiaryType; import core.game.node.entity.player.link.diary.DiaryType;
@ -11,10 +10,6 @@ import core.game.world.GameWorld;
import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Animation;
import core.plugin.Initializable; import core.plugin.Initializable;
import core.tools.RandomFunction; import core.tools.RandomFunction;
import org.rs09.consts.NPCs;
import static content.region.misthalin.lumbridge.diary.LumbridgeAchivementDiary.Companion.BeginnerTasks.DRAYNOR_TALK_TO_TOWNCRIER_ABOUT_RULES;
import static core.api.ContentAPIKt.finishTask;
/** /**
* Represents the town crier dialogue plugin. * Represents the town crier dialogue plugin.
@ -132,8 +127,9 @@ public final class TownCrierDialogue extends DialoguePlugin {
return true; return true;
} }
}); });
if (npc.getId() == NPCs.TOWN_CRIER_6136) { // Find out about the Rules of Conduct from the Draynor<br><br>Town Crier
finishTask(player, DiaryType.LUMBRIDGE, DiaryLevel.BEGINNER, DRAYNOR_TALK_TO_TOWNCRIER_ABOUT_RULES); if (npc.getId() == 6136) {
player.getAchievementDiaryManager().finishTask(player, DiaryType.LUMBRIDGE, 0, 10);
} }
stage = 71; stage = 71;
break; break;

View file

@ -1,267 +0,0 @@
package content.global.handlers.iface
import core.api.*
import core.game.global.action.EquipHandler.Companion.unequip
import org.rs09.consts.*
import core.game.interaction.InterfaceListener
import core.game.node.entity.player.Player
import core.game.node.item.Item
import core.tools.Log
/**
* Bolt Pouch Interface
* Uses 396.cs2
*/
class BoltPouchInterface: InterfaceListener {
/**
* iface components, attributes, and varbits used to define this all
*
* The varbits 2469 and 2470 are packaged in varp 834 (size 16).
* The varbits 2471 and 2472 are packaged in varp 835 (size 16).
*/
companion object {
val REMOVE_SLOT_1 = 4 // interface button
val WIELD_SLOT_1 = 3 // interface button
val ICON_SLOT_1 = 2 // interface icon component
val TEXT_SLOT_1 = 25 // interface text component
val STORED_ID_SLOT_1 = "/save:boltpouch-slot1" // attribute, this is the stored item ID
val QTY_SLOT_1 = 2469 // varbit
val REMOVE_SLOT_2 = 8
val WIELD_SLOT_2 = 7
val ICON_SLOT_2 = 6
val TEXT_SLOT_2 = 26
val STORED_ID_SLOT_2 = "/save:boltpouch-slot2"
val QTY_SLOT_2 = 2470
val REMOVE_SLOT_3 = 12
val WIELD_SLOT_3 = 11
val ICON_SLOT_3 = 10
val TEXT_SLOT_3 = 27
val STORED_ID_SLOT_3 = "/save:boltpouch-slot3"
val QTY_SLOT_3 = 2471
val REMOVE_SLOT_4 = 16
val WIELD_SLOT_4 = 15
val ICON_SLOT_4 = 14
val TEXT_SLOT_4 = 28
val STORED_ID_SLOT_4 = "/save:boltpouch-slot4"
val QTY_SLOT_4 = 2472
val UNWIELD_EQUIP_SLOT = 19
val ICON_EQUIP_SLOT = 18
val TEXT_EQUIP_SLOT = 29
val QTY_EQUIP_SLOT = 24
}
/**
* Interface interactions
*/
override fun defineInterfaceListeners() {
onOpen(Components.XBOWS_POUCH_433) { player, _ ->
updateBolts(player)
return@onOpen true
}
on(Components.XBOWS_POUCH_433) { player, _, _, buttonID, _, _ ->
when(buttonID) {
REMOVE_SLOT_1 -> removeBolts(player, STORED_ID_SLOT_1, QTY_SLOT_1)
REMOVE_SLOT_2 -> removeBolts(player, STORED_ID_SLOT_2, QTY_SLOT_2)
REMOVE_SLOT_3 -> removeBolts(player, STORED_ID_SLOT_3, QTY_SLOT_3)
REMOVE_SLOT_4 -> removeBolts(player, STORED_ID_SLOT_4, QTY_SLOT_4)
WIELD_SLOT_1 -> wieldBolts(player, STORED_ID_SLOT_1, QTY_SLOT_1)
WIELD_SLOT_2 -> wieldBolts(player, STORED_ID_SLOT_2, QTY_SLOT_2)
WIELD_SLOT_3 -> wieldBolts(player, STORED_ID_SLOT_3, QTY_SLOT_3)
WIELD_SLOT_4 -> wieldBolts(player, STORED_ID_SLOT_4, QTY_SLOT_4)
UNWIELD_EQUIP_SLOT -> unwieldBolts(player)
}
return@on true
}
}
/**
* Helper Functions
*/
// removes the bolts from the pouch by changing the stored ID to 0 and setting the qty varbit to 0
fun removeBolts(player: Player, boltSlotId: String, boltSlotQty: Int) {
val boltId = getAttribute(player, boltSlotId, -1)
val boltQty = getVarbit(player, boltSlotQty)
// error check in case arios fucks up my varbits
if (boltId == -1 && boltQty != 0) {
// log error
log(this::class.java, Log.ERR, "Invalid bolt ID '$boltSlotId' for ${player.name}.")
sendMessage(player, "ERROR: Invalid bolt ID. Please report this.")
// reset slot values
setVarbit(player, boltSlotQty, 0, true)
removeAttribute(player, boltSlotId)
return
}
if (boltQty == 0) {
sendMessage(player, "There's nothing to remove from that slot.")
return
}
val slot = when(boltSlotQty) {
QTY_SLOT_1 -> "first"
QTY_SLOT_2 -> "second"
QTY_SLOT_3 -> "third"
else -> "fourth"
}
if (addItem(player, boltId, boltQty)) {
setVarbit(player, boltSlotQty, 0, true)
removeAttribute(player, boltSlotId)
sendMessage(player, "You remove all the bolts from the $slot slot of your bolt pouch.")
} else {
sendMessage(player, "You don't have enough space in your inventory to do that.")
}
updateBolts(player)
}
// wields the bolts
fun wieldBolts(player: Player, boltSlotId: String, boltSlotQty: Int) {
// any equipped ammo
val ammo = getItemFromEquipment(player, EquipmentSlot.AMMO)
val ammoId = ammo?.id ?: -1
// bolts to equip
val boltId = getAttribute(player, boltSlotId, -1)
val boltQty = getVarbit(player, boltSlotQty)
val bolt = Item(boltId, boltQty)
// error check in case arios fucks up my varbits
if (boltId == -1 && boltQty != 0) {
// log error
log(this::class.java, Log.ERR, "Invalid bolt ID '$boltSlotId' for ${player.name}.")
sendMessage(player, "ERROR: Invalid bolt ID. Please report this.")
// reset slot values
setVarbit(player, boltSlotQty, 0, true)
removeAttribute(player, boltSlotId)
return
}
// pouch slot is empty
if (boltQty == 0) {
sendMessage(player, "There's nothing in that slot to wield.")
return
}
// check requirements
if (!bolt.definition.hasRequirement(player, true, true)) {
return
}
// same bolt type already equipped, add to stack and return
if (ammoId == boltId) {
val newQty = (ammo!!.amount + boltQty).coerceAtMost(Int.MAX_VALUE)
replaceSlot(player, EquipmentSlot.AMMO.ordinal, Item(boltId, newQty), container=Container.EQUIPMENT)
setVarbit(player, boltSlotQty, 0, true)
removeAttribute(player, boltSlotId)
sendMessage(player, "You add the bolts to your equipped stack.")
updateBolts(player)
return
}
// different bolt type, unequip existing first
if (ammoId != -1) {
if (freeSlots(player) < 1) {
sendMessage(player, "You don't have enough space in your inventory to do that.")
return
}
unequip(player, EquipmentSlot.AMMO.ordinal, ammoId)
}
// equip new bolts
if (player.equipment.add(Item(boltId, boltQty), true, EquipmentSlot.AMMO.ordinal)) {
setVarbit(player, boltSlotQty, 0, true)
removeAttribute(player, boltSlotId)
sendMessage(player, "You wield some bolts from your bolt pouch.")
}
updateBolts(player)
}
// unwields the bolts
fun unwieldBolts(player: Player) {
val ammo = getItemFromEquipment(player, EquipmentSlot.AMMO)?.id ?: -1
if (ammo == -1) {
sendMessage(player, "You're not wielding anything.")
return
}
unequip(player, EquipmentSlot.AMMO.ordinal, ammo)
updateBolts(player)
}
// updates the bolt interface. Uses the stored ID (attribute) or equipped ID to get the icon and text needed for each slot. qty is updated automatically with 396.cs2 and the varbits
fun updateBolts(player: Player) {
// the equipment slot
val ammo = getItemFromEquipment(player, EquipmentSlot.AMMO)
val ammoQty = amountInEquipment(player, ammo?.id ?: 0)
sendItemOnInterface(player, Components.XBOWS_POUCH_433, ICON_EQUIP_SLOT, ammo?.id ?: -1, 90)
setInterfaceText(player, ammo?.name ?: "Nothing", Components.XBOWS_POUCH_433, TEXT_EQUIP_SLOT)
if (ammoQty == 0) {
// RED from 396.cs2: Color(255, 0, 51)
setInterfaceText(player, "<col=FF0033>0</col>", Components.XBOWS_POUCH_433, QTY_EQUIP_SLOT)
} else {
// GREEN from 396.cs2: Color(0, 192, 0)
setInterfaceText(player, "<col=00C000>$ammoQty</col>", Components.XBOWS_POUCH_433, QTY_EQUIP_SLOT)
}
// the pouch slots
// slot 1
val slot1 = Item(getAttribute(player, STORED_ID_SLOT_1, 0))
if (slot1.id == 0) {
setInterfaceText(player, "Nothing", Components.XBOWS_POUCH_433, TEXT_SLOT_1)
sendItemOnInterface(player, Components.XBOWS_POUCH_433, ICON_SLOT_1, -1)
} else {
setInterfaceText(player, slot1.name, Components.XBOWS_POUCH_433, TEXT_SLOT_1)
sendItemOnInterface(player, Components.XBOWS_POUCH_433, ICON_SLOT_1, slot1.id, 90)
}
// slot 2
val slot2 = Item(getAttribute(player, STORED_ID_SLOT_2, 0)).definition
if (slot2.id == 0) {
setInterfaceText(player, "Nothing", Components.XBOWS_POUCH_433, TEXT_SLOT_2)
sendItemOnInterface(player, Components.XBOWS_POUCH_433, ICON_SLOT_2, -1)
} else {
setInterfaceText(player, slot2.name, Components.XBOWS_POUCH_433, TEXT_SLOT_2)
sendItemOnInterface(player, Components.XBOWS_POUCH_433, ICON_SLOT_2, slot2.id, 90)
}
// slot 3
val slot3 = Item(getAttribute(player, STORED_ID_SLOT_3, 0)).definition
if (slot3.id == 0) {
setInterfaceText(player, "Nothing", Components.XBOWS_POUCH_433, TEXT_SLOT_3)
sendItemOnInterface(player, Components.XBOWS_POUCH_433, ICON_SLOT_3, -1)
} else {
setInterfaceText(player, slot3.name, Components.XBOWS_POUCH_433, TEXT_SLOT_3)
sendItemOnInterface(player, Components.XBOWS_POUCH_433, ICON_SLOT_3, slot3.id, 90)
}
// slot 4
val slot4 = Item(getAttribute(player, STORED_ID_SLOT_4, 0)).definition
if (slot4.id == 0) {
setInterfaceText(player, "Nothing", Components.XBOWS_POUCH_433, TEXT_SLOT_4)
sendItemOnInterface(player, Components.XBOWS_POUCH_433, ICON_SLOT_4, -1)
} else {
setInterfaceText(player, slot4.name, Components.XBOWS_POUCH_433, TEXT_SLOT_4)
sendItemOnInterface(player, Components.XBOWS_POUCH_433, ICON_SLOT_4, slot4.id, 90)
}
}
}

View file

@ -6,7 +6,6 @@ import core.game.component.ComponentDefinition
import core.game.component.ComponentPlugin import core.game.component.ComponentPlugin
import core.game.container.access.InterfaceContainer import core.game.container.access.InterfaceContainer
import core.game.node.entity.player.Player import core.game.node.entity.player.Player
import core.game.node.entity.player.link.diary.DiaryType
import core.game.node.item.Item import core.game.node.item.Item
import core.plugin.Initializable import core.plugin.Initializable
import core.plugin.Plugin import core.plugin.Plugin
@ -166,10 +165,6 @@ class FurClothingInterface : ComponentPlugin(){
if (removeItem(player, requiredFur, Container.INVENTORY) && if (removeItem(player, requiredFur, Container.INVENTORY) &&
removeItem(player, coins, Container.INVENTORY)) { removeItem(player, coins, Container.INVENTORY)) {
addItem(player, clothing.product.id, amount) addItem(player, clothing.product.id, amount)
if (clothing == FUR_CLOTHING.DASH_CAPE) {
player.achievementDiaryManager.finishTask(player, DiaryType.VARROCK, 2, 2)
}
} }
} }

View file

@ -0,0 +1,37 @@
package content.global.handlers.iface;
import static core.api.ContentAPIKt.*;
import core.game.component.Component;
import core.game.component.ComponentDefinition;
import core.game.component.ComponentPlugin;
import content.global.travel.glider.GliderPulse;
import content.global.travel.glider.Gliders;
import core.game.node.entity.player.Player;
import core.plugin.Initializable;
import core.plugin.Plugin;
/**
* Represents the glider interface component.
* @author Emperor
* @author 'Vexia
* @version 1.0
*/
@Initializable
public final class GliderInterface extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(138, this);
return this;
}
@Override
public boolean handle(final Player player, Component component, int opcode, int button, int slot, int itemId) {
final Gliders glider = Gliders.forId(button);
if (glider == null) {
return true;
}
submitWorldPulse(new GliderPulse(1, player, glider));
return true;
}
}

View file

@ -1,17 +0,0 @@
package content.global.handlers.iface
import core.api.submitWorldPulse
import content.global.travel.glider.GliderPulse
import content.global.travel.glider.Gliders
import core.game.interaction.InterfaceListener
import org.rs09.consts.Components
class GliderInterface : InterfaceListener {
override fun defineInterfaceListeners() {
on(Components.GLIDERMAP_138) { player, _, _, button, _, _ ->
val glider = Gliders.forId(button) ?: return@on true
submitWorldPulse(GliderPulse(1, player, glider))
return@on true
}
}
}

View file

@ -1,34 +1,17 @@
package content.global.handlers.iface package content.global.handlers.iface
import content.data.Quests
import content.region.kandarin.yanille.quest.thehandinthesand.dialogue.BertNPCContactDialogueFile
import core.api.isQuestComplete
import core.api.removeAttribute
import core.game.node.entity.npc.NPC import core.game.node.entity.npc.NPC
import core.game.world.map.Location import core.game.world.map.Location
import core.tools.RandomFunction
import org.rs09.consts.NPCs import org.rs09.consts.NPCs
import core.game.dialogue.DialogueFile import core.game.dialogue.DialogueFile
import core.game.interaction.InterfaceListener import core.game.interaction.InterfaceListener
import core.game.node.entity.player.Player
class NPCContactInterface : InterfaceListener { class NPCContactInterface : InterfaceListener {
val contactNPCs = arrayOf( val contactNPCs = arrayOf(NPCs.HONEST_JIMMY_4362, NPCs.BERT_3108, NPCs.ADVISOR_GHRIM_1375, NPCs.TURAEL_8273, NPCs.LANTHUS_1526, NPCs.SUMONA_7780, NPCs.MAZCHNA_8274, NPCs.DURADEL_8275, NPCs.VANNAKA_1597, NPCs.DARK_MAGE_2262, NPCs.CHAELDAR_1598, NPCs.CYRISUS_432, NPCs.LARRY_5424)
NPCs.HONEST_JIMMY_4362,
NPCs.BERT_3108,
NPCs.ADVISOR_GHRIM_1375,
NPCs.TURAEL_8273,
NPCs.LANTHUS_1526,
NPCs.SUMONA_7780,
NPCs.MAZCHNA_8274,
NPCs.DURADEL_8275,
NPCs.VANNAKA_1597,
NPCs.MURPHY_464,
NPCs.CHAELDAR_1598,
NPCs.CYRISUS_432,
NPCs.LARRY_5424
)
val DialogueFiles = arrayOf<DialogueFile?>( val DialogueFiles = arrayOf<DialogueFile?>(
/*TODO("Honest Jimmy"), /*TODO("Honest Jimmy"),
TODO("Bert"),
TODO("ADVISOR GHRIM"), TODO("ADVISOR GHRIM"),
TODO("Turael"), TODO("Turael"),
TODO("LANTHUS"), TODO("LANTHUS"),
@ -41,51 +24,20 @@ class NPCContactInterface : InterfaceListener {
TODO("Cyrisus"), TODO("Cyrisus"),
TODO("Larry")*/ TODO("Larry")*/
) )
private fun canContact(player: Player, index: Int): Boolean {
return when (contactNPCs[index]) {
// Hidden until their required content is implemented.
NPCs.HONEST_JIMMY_4362, // Trouble Brewing
NPCs.ADVISOR_GHRIM_1375, // Managing Miscellania
NPCs.LANTHUS_1526, // Castle Wars
NPCs.SUMONA_7780, // Smoking Kills
NPCs.MURPHY_464, // Hook up after !2361 is merged.
NPCs.CYRISUS_432 -> false // Dream Mentor
// Add NPC Contact unlock checks here.
NPCs.BERT_3108 -> BertNPCContactDialogueFile.canContact(player)
NPCs.CHAELDAR_1598 -> isQuestComplete(player, Quests.LOST_CITY)
// TODO: Gate Larry after Penguin Hide and Seek intro dialogue is implemented.
NPCs.LARRY_5424 -> true
else -> true
}
}
private fun getContactDialogue(index: Int): DialogueFile? {
return when (contactNPCs[index]) {
// Add custom NPC Contact dialogue files here.
NPCs.BERT_3108 -> BertNPCContactDialogueFile()
else -> DialogueFiles.getOrNull(index)
}
}
val INTER = 429 val INTER = 429
override fun defineInterfaceListeners() { override fun defineInterfaceListeners() {
//Remove a bunch of the buttons/heads so that people don't //Remove a bunch of the buttons/heads so that people don't
//waste runes on spells that aren't implemented //waste runes on spells that aren't implemented
//TODO: Re-enable NPCs as their respective content gets added //TODO: Re-enable NPCs as their respective content gets added
onOpen(INTER){player, _ -> onOpen(INTER){player, component ->
//Honest Jimmy: Trouble Brewing //Honest Jimmy: Trouble Brewing
player.packetDispatch.sendInterfaceConfig(429,10,true) player.packetDispatch.sendInterfaceConfig(429,10,true)
player.packetDispatch.sendInterfaceConfig(429,38,true) player.packetDispatch.sendInterfaceConfig(429,38,true)
//Bert the Sandman: Hand in the Sand quest //Bert the Sandman: Hand in the Sand quest
val showBert = BertNPCContactDialogueFile.canContact(player) player.packetDispatch.sendInterfaceConfig(429,11,true)
player.packetDispatch.sendInterfaceConfig(429,11, !showBert) player.packetDispatch.sendInterfaceConfig(429,39,true)
player.packetDispatch.sendInterfaceConfig(429,39, !showBert)
//Advisor Ghrim: Kingdoms of Miscellania //Advisor Ghrim: Kingdoms of Miscellania
player.packetDispatch.sendInterfaceConfig(429,12,true) player.packetDispatch.sendInterfaceConfig(429,12,true)
@ -99,29 +51,15 @@ class NPCContactInterface : InterfaceListener {
player.packetDispatch.sendInterfaceConfig(429,27,true) player.packetDispatch.sendInterfaceConfig(429,27,true)
player.packetDispatch.sendInterfaceConfig(429,42,true) player.packetDispatch.sendInterfaceConfig(429,42,true)
// Murphy: Fishing Trawler // Replace Murphy's icon with the Abyss's Dark Mage
player.packetDispatch.sendInterfaceConfig(429, 30, true) player.packetDispatch.sendNpcOnInterface(NPCs.DARK_MAGE_2262, 429, 30)
player.packetDispatch.sendInterfaceConfig(429, 47, true) player.packetDispatch.sendString("Dark mage", 429, 47)
// Chaeldar has a duplicate/stale interface child 31
val showChaeldar = canContact(player, 10)
player.packetDispatch.sendInterfaceConfig(429, 29, !showChaeldar)
player.packetDispatch.sendInterfaceConfig(429, 48, !showChaeldar)
val showCyrisus = canContact(player, 11)
player.packetDispatch.sendInterfaceConfig(429, 32, !showCyrisus)
player.packetDispatch.sendInterfaceConfig(429, 33, !showCyrisus)
return@onOpen true return@onOpen true
} }
onClose(INTER) { player, _ ->
removeAttribute(player, "contact-caller")
return@onClose true
}
on(INTER){player, _, _, buttonID, _, _ -> on(INTER){player, _, _, buttonID, _, _ ->
val index = when(buttonID) { var index = when(buttonID){
10,38 -> 0 10,38 -> 0
11,39 -> 1 11,39 -> 1
12,40 -> 2 12,40 -> 2
@ -137,30 +75,15 @@ class NPCContactInterface : InterfaceListener {
34,49 -> 12 34,49 -> 12
else -> -1 else -> -1
} }
if (index == -1) { if(index == -1) index = RandomFunction.random(contactNPCs.size)
// TODO: "Random will contact any of 26 other NPCs around RuneScape, and appears not to be "random" in that it cycles through 26 different NPCs. val dialogueFile = DialogueFiles.getOrNull(index)
// The spell may start going in order randomly or just jump around. Using Random requires completion of Dream Mentor." player.getAttribute<() -> Unit>("contact-caller")?.invoke()
return@on true
}
if (!canContact(player, index)) {
return@on true
}
val npcId = contactNPCs[index]
val dialogueFile = getContactDialogue(index)
val contactCaller = player.getAttribute<() -> Unit>("contact-caller")
removeAttribute(player, "contact-caller")
contactCaller?.invoke()
player.interfaceManager.close() player.interfaceManager.close()
if(dialogueFile != null){
if(dialogueFile != null) { player.dialogueInterpreter.open(dialogueFile, NPC(contactNPCs[index]))
player.dialogueInterpreter.open(dialogueFile, NPC(npcId))
} else { } else {
player.dialogueInterpreter.open(npcId, NPC(npcId, Location(0, 0))) player.dialogueInterpreter.open(contactNPCs[index], NPC(contactNPCs[index], Location(0, 0)))
} }
return@on true return@on true
} }

View file

@ -0,0 +1,90 @@
package content.global.handlers.iface;
import static core.api.ContentAPIKt.*;
import core.game.component.Component;
import core.game.component.ComponentDefinition;
import core.game.component.ComponentPlugin;
import content.global.skill.crafting.TanningProduct;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import core.plugin.Initializable;
import core.plugin.Plugin;
import kotlin.Unit;
/**
* @author Vexia
* @version 1.2
*/
@Initializable
public class TanningInterface extends ComponentPlugin {
/**
* Method used to create a new instance.
* @param arg
* @return
* @throws Throwable
*/
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(324, this);
return this;
}
@Override
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
TanningProduct def = null;
switch (button) {
case 1:
def = TanningProduct.SOFT_LEATHER;
break;
case 2:
def = TanningProduct.HARD_LEATHER;
break;
case 3:
def = TanningProduct.SNAKESKIN;
break;
case 4:
def = TanningProduct.SNAKESKIN2;
break;
case 5:
def = TanningProduct.GREEN_DHIDE;
break;
case 6:
def = TanningProduct.BLUEDHIDE;
break;
case 7:
def = TanningProduct.REDDHIDE;
break;
case 8:
def = TanningProduct.BLACKDHIDE;
break;
}
if (def == null) {
return true;
}
int amount = 0;
final TanningProduct deff = def;
switch (opcode){
case 155:
amount = 1;
break;
case 196:
amount = 5;
break;
case 124:
amount = 10;
case 199:
sendInputDialogue(player, true, "Enter the amount:", (value) -> {
TanningProduct.tan(player, (int) value, deff);
return Unit.INSTANCE;
});
break;
case 234:
amount = player.getInventory().getAmount(new Item(def.getItem(), 1));
break;
}
TanningProduct.tan(player, amount, def);
return true;
}
}

View file

@ -1,25 +0,0 @@
package content.global.handlers.iface
import content.global.skill.crafting.TanningProduct
import core.api.amountInInventory
import core.api.sendInputDialogue
import core.game.interaction.InterfaceListener
class TanningInterface : InterfaceListener {
override fun defineInterfaceListeners() {
on(324) { player, _, opcode, buttonID, _, _ ->
val product = TanningProduct.forId(buttonID)
when (opcode) {
155 -> TanningProduct.tan(player, 1, product)
196 -> TanningProduct.tan(player, 5, product)
124 -> TanningProduct.tan(player, 10, product)
199 -> sendInputDialogue(player, true, "Enter the amount:") { value ->
TanningProduct.tan(player, value as Int, product)
}
234 -> TanningProduct.tan(player, amountInInventory(player, product.item), product)
}
return@on true
}
}
}

View file

@ -127,7 +127,7 @@ private const val F_FLARES = 72
private const val F_PLAIN_TROUSERS = 70 private const val F_PLAIN_TROUSERS = 70
private const val F_SHORTS = 77 private const val F_SHORTS = 77
private val femaleLegIDs = intArrayOf(F_FINE_SKIRT, F_FRILLED_SKIRT, F_LAYERED_SKIRT, F_LONG_NARROW_SKIRT, F_RAGGED_SKIRT, F_TATTERED_SKIRT, F_SHORT_SKIRT, F_SASHED_SKIRT, F_FITTED_SKIRT, F_TORN_TROUSERS, F_LONG_SKIRT, F_TURN_UPS, F_FLARES, F_PLAIN_TROUSERS, F_SHORTS) private val femaleLegIDs = intArrayOf(F_FINE_SKIRT, F_FRILLED_SKIRT, F_LAYERED_SKIRT, F_LONG_NARROW_SKIRT, F_RAGGED_SKIRT, F_TATTERED_SKIRT, F_SHORT_SKIRT, F_SASHED_SKIRT, F_FITTED_SKIRT, F_TORN_TROUSERS, F_LONG_SKIRT, F_TURN_UPS, F_FLARES, F_FLARES, F_PLAIN_TROUSERS, F_SHORTS)
private val COINS = Item(995,1000) private val COINS = Item(995,1000)

View file

@ -0,0 +1,39 @@
package content.global.handlers.iface;
import core.game.component.Component;
import core.game.component.ComponentDefinition;
import core.game.component.ComponentPlugin;
import core.game.node.entity.player.Player;
import core.plugin.Initializable;
import core.plugin.Plugin;
/**
* Handles the world map interface.
* @author Emperor
*
*/
@Initializable
public final class WorldMapInterface extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.forId(755).setPlugin(this);
return this;
}
//Thanks snicker!
@Override
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
switch (button) {
case 3:
player.getInterfaceManager().openWindowsPane(new Component(player.getInterfaceManager().isResizable() ? 746 : 548), 2);
player.getPacketDispatch().sendRunScript(1187, "ii", 0, 0);
player.updateSceneGraph(true);
return true;
default:
//log(this.getClass(), Log.ERR, "World map: buttonid: " + button + ", opcode: " + opcode + ", slot: " + slot);
return true;
}
}
}

View file

@ -1,23 +0,0 @@
package content.global.handlers.iface
import core.game.component.Component
import core.game.interaction.InterfaceListener
import org.rs09.consts.Components
class WorldMapInterface : InterfaceListener {
override fun defineInterfaceListeners() {
on(Components.WORLDMAP_755) { player, _, _, button, _, _ ->
if (button == 3) {
val paneId = if (player.interfaceManager.isResizable) {
Components.TOPLEVEL_FULLSCREEN_746
} else {
Components.TOPLEVEL_548
}
player.interfaceManager.openWindowsPane(Component(paneId), 2)
player.packetDispatch.sendRunScript(1187, "ii", 0, 0)
player.updateSceneGraph(true)
}
return@on true
}
}
}

View file

@ -1,147 +0,0 @@
package content.global.handlers.item
import content.global.handlers.iface.BoltPouchInterface.Companion.QTY_SLOT_1
import content.global.handlers.iface.BoltPouchInterface.Companion.QTY_SLOT_2
import content.global.handlers.iface.BoltPouchInterface.Companion.QTY_SLOT_3
import content.global.handlers.iface.BoltPouchInterface.Companion.QTY_SLOT_4
import content.global.handlers.iface.BoltPouchInterface.Companion.STORED_ID_SLOT_1
import content.global.handlers.iface.BoltPouchInterface.Companion.STORED_ID_SLOT_2
import content.global.handlers.iface.BoltPouchInterface.Companion.STORED_ID_SLOT_3
import content.global.handlers.iface.BoltPouchInterface.Companion.STORED_ID_SLOT_4
import core.api.*
import core.game.interaction.IntType
import core.game.interaction.InteractionListener
import core.game.node.entity.player.Player
import core.game.node.item.Item
import org.rs09.consts.*
/**
* Listener for the bolt pouch.
*/
class BoltPouchListener: InteractionListener {
companion object {
val BOLT_POUCH_ALLOWED_ITEMS = intArrayOf(
// metal bolts and their poisoned variants
Items.BRONZE_BOLTS_877, Items.BRONZE_BOLTSP_878, Items.BRONZE_BOLTSP_PLUS_6061, Items.BRONZE_BOLTSP_PLUS_PLUS_6062,
Items.IRON_BOLTS_9140, Items.IRON_BOLTS_P_9287, Items.IRON_BOLTSP_PLUS_9294, Items.IRON_BOLTSP_PLUS_PLUS_9301,
Items.BLURITE_BOLTS_9139, Items.BLURITE_BOLTSP_9286, Items.BLURITE_BOLTSP_PLUS_9293, Items.BLURITE_BOLTSP_PLUS_PLUS_9300,
Items.SILVER_BOLTS_9145, Items.SILVER_BOLTS_P_9292, Items.SILVER_BOLTSP_PLUS_9299, Items.SILVER_BOLTSP_PLUS_PLUS_9306,
Items.BLACK_BOLTS_13083, Items.BLACK_BOLTSP_13084, Items.BLACK_BOLTSP_PLUS_13085, Items.BLACK_BOLTSP_PLUS_PLUS_13086,
Items.STEEL_BOLTS_9141, Items.STEEL_BOLTS_P_9288, Items.STEEL_BOLTSP_PLUS_9295, Items.STEEL_BOLTSP_PLUS_PLUS_9302,
Items.MITHRIL_BOLTS_9142, Items.MITHRIL_BOLTS_P_9289, Items.MITHRIL_BOLTSP_PLUS_9296, Items.MITHRIL_BOLTSP_PLUS_PLUS_9303,
Items.ADAMANT_BOLTS_9143, Items.ADAMANT_BOLTS_P_9290, Items.ADAMANT_BOLTSP_PLUS_9297, Items.ADAMANT_BOLTSP_PLUS_PLUS_9304,
Items.RUNE_BOLTS_9144, Items.RUNITE_BOLTS_P_9291, Items.RUNITE_BOLTSP_PLUS_9298, Items.RUNITE_BOLTSP_PLUS_PLUS_9305,
// gem and enchanted gem bolts
Items.OPAL_BOLTS_879, Items.OPAL_BOLTS_E_9236,
Items.PEARL_BOLTS_880, Items.PEARL_BOLTS_E_9238,
Items.JADE_BOLTS_9335, Items.JADE_BOLTS_E_9237,
Items.TOPAZ_BOLTS_9336, Items.TOPAZ_BOLTS_E_9239,
Items.SAPPHIRE_BOLTS_9337, Items.SAPPHIRE_BOLTS_E_9240,
Items.EMERALD_BOLTS_9338, Items.EMERALD_BOLTS_E_9241,
Items.RUBY_BOLTS_9339, Items.RUBY_BOLTS_E_9242,
Items.DIAMOND_BOLTS_9340, Items.DIAMOND_BOLTS_E_9243,
Items.DRAGON_BOLTS_9341, Items.DRAGON_BOLTS_E_9244,
Items.ONYX_BOLTS_9342,Items.ONYX_BOLTS_E_9245,
// special bolts
Items.KEBBIT_BOLTS_10158, Items.LONG_KEBBIT_BOLTS_10159,
Items.BARBED_BOLTS_881,
Items.BROAD_TIPPED_BOLTS_13280,
Items.BONE_BOLTS_8882,
)
}
// helper function to drop the bolts
private fun dropBolts(player: Player, boltSlotId: String, boltSlotQty: Int) {
val boltId = getAttribute(player, boltSlotId, -1)
val boltQty = getVarbit(player, boltSlotQty)
if (boltQty == 0) {
return
}
// drops bolts, changes the stored ID to 0, and sets the qty varbit to 0
produceGroundItem(player, boltId, boltQty, player.location)
setVarbit(player, boltSlotQty, 0, true)
removeAttribute(player, boltSlotId)
}
override fun defineListeners() {
// open pouch interface
on(Items.BOLT_POUCH_9433, IntType.ITEM, "open") { player, _ ->
openInterface(player, Components.XBOWS_POUCH_433)
return@on true
}
// destroy pouch - drops bolts
on(Items.BOLT_POUCH_9433, IntType.ITEM, "destroy") { player, node ->
val item = node as Item
player.dialogueInterpreter.sendDestroyItem(item.id, "You can get another pouch from Hirko in Keldagrim.")
addDialogueAction(player) { _, button ->
if (button == 3) {
if (removeItem(player, item)) {
playAudio(player, Sounds.DESTROY_OBJECT_2381)
dropBolts(player, STORED_ID_SLOT_1, QTY_SLOT_1)
dropBolts(player, STORED_ID_SLOT_2, QTY_SLOT_2)
dropBolts(player, STORED_ID_SLOT_3, QTY_SLOT_3)
dropBolts(player, STORED_ID_SLOT_4, QTY_SLOT_4)
}
}
}
return@on true
}
// bolts used on pouch: add to pouch
onUseWith(IntType.ITEM, Items.BOLT_POUCH_9433, *BOLT_POUCH_ALLOWED_ITEMS) { player, _, with ->
val id = with.id
val qtyUsed = amountInInventory(player, id)
// get either the first empty slot by querying the varbits, or a slot that already has the used bolts in it and at least one free space
var targetQtySlot = -1
var targetIdSlot = ""
// slot 1
if (getVarbit(player, QTY_SLOT_1) == 0 || (id == getAttribute(player, STORED_ID_SLOT_1, 0) && getVarbit(player, QTY_SLOT_1) < 255)) {
targetQtySlot = QTY_SLOT_1
targetIdSlot = STORED_ID_SLOT_1
// slot 2
} else if (getVarbit(player, QTY_SLOT_2) == 0 || (id == getAttribute(player, STORED_ID_SLOT_2, 0) && getVarbit(player, QTY_SLOT_2) < 255)) {
targetQtySlot = QTY_SLOT_2
targetIdSlot = STORED_ID_SLOT_2
// slot 3
} else if (getVarbit(player, QTY_SLOT_3) == 0 || (id == getAttribute(player, STORED_ID_SLOT_3, 0) && getVarbit(player, QTY_SLOT_3) < 255)) {
targetQtySlot = QTY_SLOT_3
targetIdSlot = STORED_ID_SLOT_3
// slot 4
} else if (getVarbit(player, QTY_SLOT_4) == 0 || (id == getAttribute(player, STORED_ID_SLOT_4, 0) && getVarbit(player, QTY_SLOT_4) < 255)) {
targetQtySlot = QTY_SLOT_4
targetIdSlot = STORED_ID_SLOT_4
}
// based on target values set earlier, add the bolts
if (targetQtySlot != -1) {
val currentQty = getVarbit(player, targetQtySlot)
val spaceLeft = 255 - currentQty
val toAdd = minOf(qtyUsed, spaceLeft)
if (removeItem(player, Item(id, toAdd))) {
setVarbit(player, targetQtySlot, toAdd + currentQty, true)
setAttribute(player, targetIdSlot, id)
sendMessage(player, "You store some bolts in your pouch.")
}
// all slots are full
} else {
sendMessage(player, "You don't have enough space in your bolt pouch to do that.")
}
return@onUseWith true
}
}
}

View file

@ -1,7 +1,5 @@
package content.global.handlers.item package content.global.handlers.item
import content.global.skill.herblore.FinishedPotion
import content.global.skill.herblore.UnfinishedPotion
import core.api.* import core.api.*
import core.cache.def.impl.ItemDefinition import core.cache.def.impl.ItemDefinition
import core.game.interaction.IntType import core.game.interaction.IntType
@ -82,9 +80,7 @@ class EmptyOptionListener : InteractionListener {
BURNT_GNOMEBOWL(Items.BURNT_GNOMEBOWL_2175, Items.GNOMEBOWL_MOULD_2166, "You empty the contents of the gnomebowl onto the floor."), BURNT_GNOMEBOWL(Items.BURNT_GNOMEBOWL_2175, Items.GNOMEBOWL_MOULD_2166, "You empty the contents of the gnomebowl onto the floor."),
BURNT_EGG(Items.BURNT_EGG_7090, Items.BOWL_1923, "You empty the contents of the bowl onto the floor."), BURNT_EGG(Items.BURNT_EGG_7090, Items.BOWL_1923, "You empty the contents of the bowl onto the floor."),
BURNT_ONION(Items.BURNT_ONION_7092, Items.BOWL_1923, "You empty the contents of the bowl onto the floor."), BURNT_ONION(Items.BURNT_ONION_7092, Items.BOWL_1923, "You empty the contents of the bowl onto the floor."),
BURNT_MUSHROOM(Items.BURNT_MUSHROOM_7094, Items.BOWL_1923, "You empty the contents of the bowl onto the floor."), BURNT_MUSHROOM(Items.BURNT_MUSHROOM_7094, Items.BOWL_1923, "You empty the contents of the bowl onto the floor.");
COCONUT_MILK(Items.COCONUT_MILK_5935, Items.VIAL_229, "You empty the vial.", Sounds.LIQUID_2401),
IMP_REPEL(Items.IMP_REPELLENT_11262, Items.VIAL_229, "You empty the vial.", Sounds.LIQUID_2401);
companion object { companion object {
var emptyItemMap = HashMap<Int, Int?>() var emptyItemMap = HashMap<Int, Int?>()
@ -93,49 +89,17 @@ class EmptyOptionListener : InteractionListener {
var emptyItemList = ArrayList<Int>() var emptyItemList = ArrayList<Int>()
init { init {
// add all the above manually-defined items
for (item in values()) { for (item in values()) {
emptyItemMap.putIfAbsent(item.fullId, item.emptyId) emptyItemMap.putIfAbsent(item.fullId, item.emptyId)
emptyMessageMap.putIfAbsent(item.fullId, item.emptyMessage) emptyMessageMap.putIfAbsent(item.fullId, item.emptyMessage)
emptyAudioMap.putIfAbsent(item.fullId, item.audioId) emptyAudioMap.putIfAbsent(item.fullId, item.audioId)
emptyItemList.add(item.fullId) emptyItemList.add(item.fullId)
} }
// add finished potion products
for (finishedPotion in FinishedPotion.values()) {
val potionId = finishedPotion.potion.id
emptyItemMap.putIfAbsent(potionId, Items.VIAL_229)
emptyMessageMap.putIfAbsent(potionId, "You empty the vial.")
emptyAudioMap.putIfAbsent(potionId, Sounds.LIQUID_2401)
if (!emptyItemList.contains(potionId)) {
emptyItemList.add(potionId)
}
}
// add unfinished potion products
for (unfinishedPotion in UnfinishedPotion.values()) {
val potionId = unfinishedPotion.potion.id
emptyItemMap.putIfAbsent(potionId, Items.VIAL_229)
emptyMessageMap.putIfAbsent(potionId, "You empty the vial.")
emptyAudioMap.putIfAbsent(potionId, Sounds.LIQUID_2401)
if (!emptyItemList.contains(potionId)) {
emptyItemList.add(potionId)
}
}
// todo this legacy line loads a bunch of random shit that may or may not have empty options. It'd be better to define these all in the future in a controlled manner (e.g. this pulls items like Items.SUPER_KEBAB_4608 and Items.VOICE_OF_DOOM_POTION_11788)
// add some strings that might catch anything else
for (item in ItemDefinition.getDefinitions().values) for (item in ItemDefinition.getDefinitions().values)
if (item.name.contains("potion") || item.name.contains("brew") || item.name.contains("poison") || item.name.lowercase(Locale.getDefault()).contains("serum") || item.name.contains("cure") || item.name.contains("mix") || item.name.contains("balm") || item.name.contains("Super ")) { if (item.name.contains("potion") || item.name.contains("brew") || item.name.contains("poison") || item.name.lowercase(Locale.getDefault()).contains("serum") || item.name.contains("cure") || item.name.contains("mix") || item.name.contains("balm") || item.name.contains("Super ")) {
if (!emptyItemList.contains(item.id)) {
emptyItemList.add(item.id) emptyItemList.add(item.id)
} }
} }
}
fun getEmpty(id: Int): Int? { fun getEmpty(id: Int): Int? {
return emptyItemMap[id] return emptyItemMap[id]

View file

@ -2,6 +2,7 @@ package content.global.handlers.item
import content.global.skill.slayer.SlayerUtils import content.global.skill.slayer.SlayerUtils
import core.api.* import core.api.*
import content.global.skill.slayer.Tasks
import org.rs09.consts.Items import org.rs09.consts.Items
import core.game.dialogue.DialogueFile import core.game.dialogue.DialogueFile
import core.game.dialogue.IfTopic import core.game.dialogue.IfTopic
@ -38,7 +39,12 @@ class EnchantedGemDialogue() : DialogueFile() {
if(!hasSlayerTask(player!!)) { if(!hasSlayerTask(player!!)) {
npcl(core.game.dialogue.FacialExpression.HALF_THINKING, "You need something new to hunt. Come and see me when you can and I'll give you a new task.").also { stage = 1 } npcl(core.game.dialogue.FacialExpression.HALF_THINKING, "You need something new to hunt. Come and see me when you can and I'll give you a new task.").also { stage = 1 }
} else { } else {
npcl(core.game.dialogue.FacialExpression.FRIENDLY, "You're currently assigned to kill ${SlayerUtils.pluralise(getSlayerTaskName(player!!))}; only ${getSlayerTaskKillsRemaining(player!!)} more to go.") if(getSlayerTask(player!!) == Tasks.JAD) {
npcl(core.game.dialogue.FacialExpression.FRIENDLY, "You're currently assigned to kill TzTok-Jad!")
} else {
npcl(core.game.dialogue.FacialExpression.FRIENDLY, "You're currently assigned to kill ${SlayerUtils.pluralise(
getSlayerTaskName(player!!))}; only ${getSlayerTaskKillsRemaining(player!!)} more to go.")
}
setVarp(player!!, 2502, getSlayerTaskFlags(player!!) shr 4) setVarp(player!!, 2502, getSlayerTaskFlags(player!!) shr 4)
stage = 1 stage = 1
} }

View file

@ -92,11 +92,7 @@ class ItemQuestRequirementListener : InteractionListener {
private val godBooks = intArrayOf ( private val godBooks = intArrayOf (
Items.HOLY_BOOK_3840, Items.HOLY_BOOK_3840,
Items.UNHOLY_BOOK_3842, Items.UNHOLY_BOOK_3842
Items.BOOK_OF_BALANCE_3844,
Items.DAMAGED_BOOK_3839,
Items.DAMAGED_BOOK_3841,
Items.DAMAGED_BOOK_3843
) )
private val pharaohScepters = (9044..9051).toIntArray() private val pharaohScepters = (9044..9051).toIntArray()

View file

@ -1,77 +0,0 @@
package content.global.handlers.item
import core.api.*
import core.game.interaction.InteractionListener
import core.game.interaction.InterfaceListener
import core.game.node.entity.player.Player
import org.rs09.consts.Items
import org.rs09.consts.NPCs
import org.rs09.consts.Sounds
/**
* Handles morphing with the Ring of Stone and Easter Ring.
*/
class MorphItemListener : InteractionListener, InterfaceListener {
// the morphing items
private val morphItems = intArrayOf(Items.RING_OF_STONE_6583, Items.EASTER_RING_7927)
// the NPCs to morph into
private val easterEggs = intArrayOf(
NPCs.EGG_3689,
NPCs.EGG_3690,
NPCs.EGG_3691,
NPCs.EGG_3692,
NPCs.EGG_3693,
NPCs.EGG_3694
)
private val stone = intArrayOf(NPCs.ROCKS_2626)
// the "unmorph" interface
private val morphIface = 375
// equipping the morph items
override fun defineListeners() {
onEquip(morphItems) { player, item ->
morph(player, item.id)
return@onEquip false
}
}
// the interface that appears when you morph
override fun defineInterfaceListeners() {
// hitting the 'unmorph' button
on(morphIface){ player, _, _, buttonID, _, _ ->
when(buttonID) {
3 -> closeAllInterfaces(player)
}
return@on true
}
// after the interface closes
onClose(morphIface) { player, _ ->
unmorph(player)
return@onClose true
}
}
// morphs the player
private fun morph(player: Player, item: Int) {
val morphId = when (item) {
Items.RING_OF_STONE_6583 -> stone.random()
else -> easterEggs.random()
}
playAudio(player, Sounds.EASTER06_HUMAN_INTO_EGG_1520)
stopWalk(player)
closeAllInterfaces(player)
player.appearance.transformNPC(morphId)
openInterface(player, morphIface)
}
// unmorphs the player
private fun unmorph(player: Player) {
player.appearance.transformNPC(-1)
}
}

View file

@ -0,0 +1,113 @@
package content.global.handlers.item;
import core.cache.def.impl.ItemDefinition;
import core.game.component.CloseEvent;
import core.game.component.Component;
import core.game.component.ComponentDefinition;
import core.game.component.ComponentPlugin;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import core.game.world.GameWorld;
import core.plugin.Initializable;
import core.plugin.Plugin;
import core.plugin.ClassScanner;
import core.tools.RandomFunction;
import org.rs09.consts.Sounds;
import static core.api.ContentAPIKt.playAudio;
/**
* Handles a morph item.
* @author Vexia
*/
@Initializable
public class MorphItemPlugin implements Plugin<Object> {
/**
* The easter egg ids.
*/
protected static final int[] EASTER_EGG_IDS = new int[] { 3689, 3690, 3691, 3692, 3693, 3694 };
/**
* The morph component.
*/
private static final Component COMPONENT = new Component(375).setCloseEvent(new CloseEvent() {
@Override
public boolean close(Player player, Component c) {
unmorph(player);
return true;
}
});
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ItemDefinition.forId(7927).getHandlers().put("equipment", this);
ItemDefinition.forId(6583).getHandlers().put("equipment", this);
ClassScanner.definePlugin(new MorphInterfacePlugin());
return this;
}
@Override
public Object fireEvent(String identifier, Object... args) {
final Player player = (Player) args[0];
final Item item = (Item) args[1];
switch (identifier) {
case "equip":
morph(player, item);
return false;
}
return true;
}
/**
* Morphs the player.
* @param player the player.
* @param item the item.
*/
private void morph(Player player, Item item) {
int morphId = item.getId() == 6583 ? 2626 : EASTER_EGG_IDS[RandomFunction.random(EASTER_EGG_IDS.length)];
playAudio(player, 1520);
player.getInterfaceManager().close();
player.getAppearance().transformNPC(morphId);
player.getInterfaceManager().removeTabs(0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14);
player.getLocks().lockMovement(GameWorld.getTicks() + 900000000);
player.getLocks().lockInteractions(GameWorld.getTicks() + 90000000);
player.getLocks().lockTeleport(GameWorld.getTicks() + 900000000);
player.getInterfaceManager().openSingleTab(COMPONENT);
player.getAppearance().sync();
player.getWalkingQueue().reset();
}
/**
* Unmorphs the player.
* @param player the player.
*/
private static void unmorph(Player player) {
player.getAppearance().transformNPC(-1);
player.unlock();
player.getInterfaceManager().restoreTabs();
}
/**
* Handles the morph interface plugin.
* @author Vexia
*/
public class MorphInterfacePlugin extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.forId(375).setPlugin(this);
return this;
}
@Override
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
player.getInterfaceManager().closeSingleTab();
return true;
}
}
}

View file

@ -1,28 +0,0 @@
package content.global.handlers.item.equipment
import content.region.kandarin.quest.barbariantraining.BarbarianTraining
import core.api.*
import core.cache.def.impl.ItemDefinition
import core.game.interaction.InteractionListener
/**
* Prevents players from equipping hastas without the required barbarian training.
* @author Bishop
*/
class HastaEquipListener : InteractionListener {
override fun defineListeners() {
val hastaIds = ItemDefinition.getDefinitions().values
.filter { it.name.lowercase().contains("hasta") }
.map { it.id }
.toIntArray()
onEquip(hastaIds) { player, _ ->
if (getAttribute(player, BarbarianTraining.attributeHasta, 0) < 2) {
sendDialogue(player, "You must begin the relevant section of Otto Godblessed's barbarian training.")
return@onEquip false
}
return@onEquip true
}
}
}

View file

@ -186,9 +186,9 @@ public final class ChainhitSpecialHandler extends RangeSwingHandler implements P
if (list == null) { if (list == null) {
int distance = 5; int distance = 5;
if (victim instanceof NPC) { if (victim instanceof NPC) {
e.setAttribute("chain-hit_v", list = RegionManager.getLocalNPCs(e.getLocation(), distance)); e.setAttribute("chain-hit_v", list = RegionManager.getLocalNpcs(e, distance));
} else { } else {
e.setAttribute("chain-hit_v", list = RegionManager.getLocalPlayers(e.getLocation(), distance)); e.setAttribute("chain-hit_v", list = RegionManager.getLocalPlayers(e, distance));
} }
list.remove(e); list.remove(e);
list.remove(victim); list.remove(victim);

View file

@ -6,15 +6,16 @@ import core.game.node.entity.combat.equipment.Ammunition;
import core.game.node.entity.combat.equipment.RangeWeapon; import core.game.node.entity.combat.equipment.RangeWeapon;
import core.game.node.entity.combat.equipment.Weapon; import core.game.node.entity.combat.equipment.Weapon;
import core.game.node.entity.combat.equipment.WeaponInterface; import core.game.node.entity.combat.equipment.WeaponInterface;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player; import core.game.node.entity.player.Player;
import core.game.node.entity.skill.Skills; import core.game.node.entity.skill.Skills;
import core.game.world.map.RegionManager;
import core.game.world.update.flag.context.Graphics; import core.game.world.update.flag.context.Graphics;
import core.tools.RandomFunction; import core.tools.RandomFunction;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import static core.game.node.entity.combat.MultihitTargetsKt.findMultihitTargetsForChinchompa;
/** /**
* Handles a combat swing using red chinchompas. * Handles a combat swing using red chinchompas.
* @author Emperor * @author Emperor
@ -55,19 +56,23 @@ public final class ChinchompaSwingHandler extends RangeSwingHandler {
return -1; return -1;
} }
boolean accurate = isAccurateImpact(entity, victim, CombatStyle.RANGE); // ! Initial capacity of 14, but has dynamic size? i.e. we are not restricting to a max of 14 targets hit here now
List<Entity> targetCandidates = findMultihitTargetsForChinchompa(victim, entity); List<Entity> targetCandidates = new ArrayList<>(14);
targetCandidates.addAll(RegionManager.getSurroundingNPCs(victim, 14, entity));
targetCandidates.addAll(RegionManager.getSurroundingPlayers(victim, 14, entity));
BattleState[] targets = new BattleState[targetCandidates.size()]; BattleState[] targets = new BattleState[targetCandidates.size()];
int count = 0; int count = 0;
for (Entity e : targetCandidates) { for (Entity e : targetCandidates) {
if (canSwing(entity, e) != InteractionType.NO_INTERACT && e.isAttackable(entity, CombatStyle.RANGE, false)) {
BattleState s = targets[count++] = new BattleState(entity, e); BattleState s = targets[count++] = new BattleState(entity, e);
s.setStyle(CombatStyle.RANGE); s.setStyle(CombatStyle.RANGE);
int hit = 0; int hit = 0;
if (accurate) { if (isAccurateImpact(entity, e, CombatStyle.RANGE)) {
hit = RandomFunction.random(calculateHit(entity, e, 1.0) + 1); hit = RandomFunction.random(calculateHit(entity, e, 1.0) + 1);
} }
s.setEstimatedHit(hit); s.setEstimatedHit(hit);
} }
}
state.setTargets(targets); state.setTargets(targets);
Companion.useAmmo(entity, state, null); Companion.useAmmo(entity, state, null);
return 2 + (int) Math.ceil(entity.getLocation().getDistance(victim.getLocation()) * 0.3); return 2 + (int) Math.ceil(entity.getLocation().getDistance(victim.getLocation()) * 0.3);

View file

@ -5,9 +5,12 @@ import java.util.List;
import core.game.node.entity.Entity; import core.game.node.entity.Entity;
import core.game.node.entity.combat.BattleState; import core.game.node.entity.combat.BattleState;
import core.game.node.entity.combat.CombatStyle; import core.game.node.entity.combat.CombatStyle;
import core.game.node.entity.combat.InteractionType;
import core.game.node.entity.combat.MeleeSwingHandler; import core.game.node.entity.combat.MeleeSwingHandler;
import core.game.node.entity.impl.Animator.Priority; import core.game.node.entity.impl.Animator.Priority;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player; import core.game.node.entity.player.Player;
import core.game.world.map.RegionManager;
import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Animation;
import core.game.world.update.flag.context.Graphics; import core.game.world.update.flag.context.Graphics;
import core.plugin.Plugin; import core.plugin.Plugin;
@ -16,7 +19,6 @@ import core.tools.RandomFunction;
import org.rs09.consts.Sounds; import org.rs09.consts.Sounds;
import static core.api.ContentAPIKt.playGlobalAudio; import static core.api.ContentAPIKt.playGlobalAudio;
import static core.game.node.entity.combat.MultihitTargetsKt.findMultihitTargetsForD2h;
/** /**
* Handles the Powerstab special attack. * Handles the Powerstab special attack.
@ -73,10 +75,13 @@ public final class PowerstabSpecialHandler extends MeleeSwingHandler implements
if (!multi) { if (!multi) {
return super.swing(entity, victim, state); return super.swing(entity, victim, state);
} }
List<Entity> list = findMultihitTargetsForD2h(victim, entity, CombatStyle.MELEE); @SuppressWarnings("rawtypes")
List list = victim instanceof NPC ? RegionManager.getSurroundingNPCs(entity, 9, entity) : RegionManager.getSurroundingPlayers(entity, 9, entity);
BattleState[] targets = new BattleState[list.size()]; BattleState[] targets = new BattleState[list.size()];
int count = 0; int count = 0;
for (Entity e : list) { for (Object o : list) {
Entity e = (Entity) o;
if (CombatStyle.RANGE.getSwingHandler().canSwing(entity, e) != InteractionType.NO_INTERACT && e.isAttackable(entity, CombatStyle.RANGE, false)) {
BattleState s = targets[count++] = new BattleState(entity, e); BattleState s = targets[count++] = new BattleState(entity, e);
int hit = 0; int hit = 0;
if (isAccurateImpact(entity, e)) { if (isAccurateImpact(entity, e)) {
@ -85,6 +90,7 @@ public final class PowerstabSpecialHandler extends MeleeSwingHandler implements
s.setStyle(CombatStyle.MELEE); s.setStyle(CombatStyle.MELEE);
s.setEstimatedHit(hit); s.setEstimatedHit(hit);
} }
}
state.setTargets(targets); state.setTargets(targets);
return 1; return 1;
} }

View file

@ -52,25 +52,20 @@ public final class QuickSmashSpecialHandler extends MeleeSwingHandler implements
@Override @Override
public Plugin<Object> newInstance(Object arg) throws Throwable { public Plugin<Object> newInstance(Object arg) throws Throwable {
CombatStyle.MELEE.getSwingHandler().register(4153, this); CombatStyle.MELEE.getSwingHandler().register(4153, this);
CombatStyle.MELEE.getSwingHandler().register(14792, this);
return this; return this;
} }
@Override @Override
public int swing(Entity entity, Entity victim, BattleState state) { public int swing(Entity entity, Entity victim, BattleState state) {
Player p = (Player) entity; Player p = (Player) entity;
boolean canMelee = MeleeSwingHandler.Companion.canMelee(p, victim, 1);
if (victim == null) { if (victim == null) {
victim = p.getProperties().getCombatPulse().getLastVictim(); victim = p.getProperties().getCombatPulse().getLastVictim();
if (victim == null || GameWorld.getTicks() - p.getAttribute("combat-stop", -1) > 2 || !canMelee) { if (victim == null || GameWorld.getTicks() - p.getAttribute("combat-stop", -1) > 2 || !MeleeSwingHandler.Companion.canMelee(p, victim, 1)) {
p.getPacketDispatch().sendMessage("Warning: Since the maul's special is an instant attack, it will be wasted when used "); p.getPacketDispatch().sendMessage("Warning: Since the maul's special is an instant attack, it will be wasted when used ");
p.getPacketDispatch().sendMessage("on a first strike."); p.getPacketDispatch().sendMessage("on a first strike.");
return -1; return -1;
} }
} else {
canMelee = canMelee && p.continueAttack(victim, CombatStyle.MELEE, true); //this is what checks wildy rules, e.g. "The level difference between you and your opponent is too great."
}
if (!canMelee) {
return -1;
} }
if (DeathTask.isDead(victim)) { if (DeathTask.isDead(victim)) {
return -1; return -1;

View file

@ -5,9 +5,12 @@ import java.util.List;
import core.game.node.entity.Entity; import core.game.node.entity.Entity;
import core.game.node.entity.combat.BattleState; import core.game.node.entity.combat.BattleState;
import core.game.node.entity.combat.CombatStyle; import core.game.node.entity.combat.CombatStyle;
import core.game.node.entity.combat.InteractionType;
import core.game.node.entity.combat.MeleeSwingHandler; import core.game.node.entity.combat.MeleeSwingHandler;
import core.game.node.entity.impl.Animator.Priority; import core.game.node.entity.impl.Animator.Priority;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player; import core.game.node.entity.player.Player;
import core.game.world.map.RegionManager;
import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Animation;
import core.game.world.update.flag.context.Graphics; import core.game.world.update.flag.context.Graphics;
import core.plugin.Plugin; import core.plugin.Plugin;
@ -16,7 +19,6 @@ import core.tools.RandomFunction;
import org.rs09.consts.Sounds; import org.rs09.consts.Sounds;
import static core.api.ContentAPIKt.playGlobalAudio; import static core.api.ContentAPIKt.playGlobalAudio;
import static core.game.node.entity.combat.MultihitTargetsKt.findMultihitTargets;
/** /**
* Handles Vesta's Spear special attack - Spear Wall. * Handles Vesta's Spear special attack - Spear Wall.
@ -74,15 +76,20 @@ public final class SpearWallSpecialHandler extends MeleeSwingHandler implements
if (!multi) { if (!multi) {
return super.swing(entity, victim, state); return super.swing(entity, victim, state);
} }
List<Entity> list = findMultihitTargets(victim, entity, CombatStyle.MELEE); @SuppressWarnings("rawtypes")
List list = victim instanceof NPC ? RegionManager.getSurroundingNPCs(entity, 9, entity) : RegionManager.getSurroundingPlayers(entity, 9, entity);
BattleState[] targets = new BattleState[list.size()]; BattleState[] targets = new BattleState[list.size()];
int count = 0; int count = 0;
for (Entity e : list) { for (Object o : list) {
Entity e = (Entity) o;
if (CombatStyle.RANGE.getSwingHandler().canSwing(entity, e) != InteractionType.NO_INTERACT && e.isAttackable(entity, CombatStyle.RANGE, false)) {
BattleState s = targets[count++] = new BattleState(entity, e); BattleState s = targets[count++] = new BattleState(entity, e);
int hit = RandomFunction.random(calculateHit(entity, e, 1.0) + 1); int hit = 0;
hit = RandomFunction.random(calculateHit(entity, e, 1.0) + 1);
s.setStyle(CombatStyle.MELEE); s.setStyle(CombatStyle.MELEE);
s.setEstimatedHit(hit); s.setEstimatedHit(hit);
} }
}
state.setTargets(targets); state.setTargets(targets);
return 1; return 1;
} }

View file

@ -4,12 +4,17 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import core.plugin.Initializable; import core.plugin.Initializable;
import content.global.skill.summoning.familiar.Familiar;
import core.game.node.entity.Entity; import core.game.node.entity.Entity;
import core.game.node.entity.combat.BattleState; import core.game.node.entity.combat.BattleState;
import core.game.node.entity.combat.CombatStyle; import core.game.node.entity.combat.CombatStyle;
import core.game.node.entity.combat.MeleeSwingHandler; import core.game.node.entity.combat.MeleeSwingHandler;
import core.game.node.entity.impl.Animator.Priority; import core.game.node.entity.impl.Animator.Priority;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player; import core.game.node.entity.player.Player;
import core.game.world.map.Direction;
import core.game.world.map.Location;
import core.game.world.map.RegionManager;
import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Animation;
import core.game.world.update.flag.context.Graphics; import core.game.world.update.flag.context.Graphics;
import core.plugin.Plugin; import core.plugin.Plugin;
@ -17,7 +22,6 @@ import core.tools.RandomFunction;
import org.rs09.consts.Sounds; import org.rs09.consts.Sounds;
import static core.api.ContentAPIKt.playGlobalAudio; import static core.api.ContentAPIKt.playGlobalAudio;
import static core.game.node.entity.combat.MultihitTargetsKt.findMultihitTargetsForDragonHalberd;
/** /**
* Handles the Dragon halberd special attack. * Handles the Dragon halberd special attack.
@ -88,11 +92,25 @@ public final class SweepSpecialHandler extends MeleeSwingHandler implements Plug
if (!entity.getProperties().isMultiZone() || !victim.getProperties().isMultiZone()) { if (!entity.getProperties().isMultiZone() || !victim.getProperties().isMultiZone()) {
return new BattleState[]{state}; return new BattleState[]{state};
} }
Location vl = victim.getLocation();
int x = vl.getX();
int y = vl.getY();
Direction dir = Direction.getDirection(x - entity.getLocation().getX(), y - entity.getLocation().getY());
List<BattleState> l = new ArrayList<>(20); List<BattleState> l = new ArrayList<>(20);
l.add(new BattleState(entity, victim)); l.add(new BattleState(entity, victim));
List<Entity> list = findMultihitTargetsForDragonHalberd(victim, entity); for (Entity n : victim instanceof NPC ? RegionManager.getSurroundingNPCs(victim, 9, entity, victim) : RegionManager.getSurroundingPlayers(victim, 9, entity, victim)) {
for (Entity n : list) { if (n instanceof Familiar) {
continue;
}
if (!n.isAttackable(entity, CombatStyle.MELEE, false)) {
continue;
}
if (n.getLocation().equals(vl.transform(dir.getStepY(), dir.getStepX(), 0)) || n.getLocation().equals(vl.transform(-dir.getStepY(), -dir.getStepX(), 0))) {
l.add(new BattleState(entity, n)); l.add(new BattleState(entity, n));
if (l.size() >= 3) {
break;
}
}
} }
return l.toArray(new BattleState[l.size()]); return l.toArray(new BattleState[l.size()]);
} }

View file

@ -3,7 +3,6 @@ package content.global.handlers.item.withitem
import content.data.Dyes import content.data.Dyes
import core.game.interaction.NodeUsageEvent import core.game.interaction.NodeUsageEvent
import core.game.interaction.UseWithHandler import core.game.interaction.UseWithHandler
import core.game.node.entity.player.link.diary.DiaryType
import core.game.node.item.Item import core.game.node.item.Item
import core.plugin.Initializable import core.plugin.Initializable
import core.plugin.Plugin import core.plugin.Plugin
@ -47,10 +46,6 @@ class CapeDyer : UseWithHandler(*CAPES.copyOfRange(0,CAPES.size - 1).toIntArray(
player.inventory.add(product.product) player.inventory.add(product.product)
player.inventory.add(Item(Items.VIAL_229)) player.inventory.add(Item(Items.VIAL_229))
player.sendMessage("You dye the cape.") player.sendMessage("You dye the cape.")
if (product == Cape.PINK) {
player.achievementDiaryManager.finishTask(player, DiaryType.FALADOR, 2, 5)
}
} }
return true return true
} }

View file

@ -0,0 +1,100 @@
package content.global.handlers.item.withitem;
import core.cache.def.impl.ItemDefinition;
import core.plugin.Initializable;
import core.game.dialogue.DialogueAction;
import core.game.interaction.NodeUsageEvent;
import core.game.interaction.OptionHandler;
import core.game.interaction.UseWithHandler;
import core.game.node.Node;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import core.plugin.Plugin;
import core.plugin.ClassScanner;
/**
* The plugin used to make the granite maul into the ornamental version.
* @author Splinter
* @version 1.0
*/
@Initializable
public final class GraniteMaulPlugin extends UseWithHandler {
/**
* Constructs a new {@code GraniteMaulPlugin} {@code Object}.
*/
public GraniteMaulPlugin() {
super(4153);
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ClassScanner.definePlugin(new GraniteMaulRevertHandler());
addHandler(14793, ITEM_TYPE, this);
return this;
}
@Override
public boolean handle(final NodeUsageEvent event) {
final Player player = event.getPlayer();
player.getDialogueInterpreter().sendOptions("Attach the clamp?", "Yes", "No");
player.getDialogueInterpreter().addAction(new DialogueAction() {
@Override
public void handle(Player player, int buttonId) {
switch (buttonId) {
case 2:
if (player.getInventory().remove(event.getBaseItem()) && player.getInventory().remove(event.getUsedItem())) {
player.getInventory().add(new Item(14792, 1));
player.sendMessage("You attach the clamp to the granite maul, making it slightly more fashionable.");
}
break;
}
}
});
return true;
}
/**
* Handles the removal of the ornamental kit.
* @author Splinter
*/
public final class GraniteMaulRevertHandler extends OptionHandler {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ItemDefinition.forId(14792).getHandlers().put("option:revert", this);
return null;
}
@Override
public boolean handle(Player player, Node node, String option) {
final Item item = (Item) node;
player.getDialogueInterpreter().sendOptions("Remove the clamp?", "Yes", "No");
player.getDialogueInterpreter().addAction(new DialogueAction() {
@Override
public void handle(Player player, int buttonId) {
switch (buttonId) {
case 2:
if(player.getInventory().remove(item)){
player.getInventory().add(new Item(4153, 1));
player.sendMessage("You remove the clamp from your maul, and in the process, it is destroyed.");
}
break;
}
}
});
return true;
}
@Override
public boolean isWalk() {
return false;
}
}
}

View file

@ -20,7 +20,7 @@ public final class ImpJarCreatePlugin extends UseWithHandler {
/** /**
* The flower ids. * The flower ids.
*/ */
private static final int[] FLOWERS = new int[] { 2460, 2461, 2462, 2463, 2464, 2465, 2466, 2467, 2468, 2469, 2470, 2471, 2472, 2473, 2474, 2475, 2476, 2477, 6010, 6012 }; private static final int[] FLOWERS = new int[] { 2460, 2461, 2462, 2463, 2464, 2465, 2466, 2467, 2468, 2469, 2470, 2471, 2472, 2473, 2474, 2475, 2476, 2477 };
/** /**
* Constructs a new {@code ImpJarCreatePlugin} {@code Object}. * Constructs a new {@code ImpJarCreatePlugin} {@code Object}.

View file

@ -97,14 +97,7 @@ class PoisonedWeaponListeners : InteractionListener {
ADAMANT_SPEAR(1245, 1259, 5712, 5726), ADAMANT_SPEAR(1245, 1259, 5712, 5726),
RUNE_SPEAR(1247, 1261, 5714, 5728), RUNE_SPEAR(1247, 1261, 5714, 5728),
DRAGON_SPEAR(1249, 1263, 5716, 5730), DRAGON_SPEAR(1249, 1263, 5716, 5730),
BLACK_SPEAR(4580, 4582, 5734, 5736), BLACK_SPEAR(4580, 4582, 5734, 5736);
BRONZE_HASTA(Items.BRONZE_HASTA_11367, Items.BRONZE_HASTAP_11379, Items.BRONZE_HASTAP_PLUS_11382, Items.BRONZE_HASTAP_PLUS_PLUS_11384),
IRON_HASTA(Items.IRON_HASTA_11369, Items.IRON_HASTAP_11386, Items.IRON_HASTAP_PLUS_11389, Items.IRON_HASTAP_PLUS_PLUS_11391),
STEEL_HASTA(Items.STEEL_HASTA_11371, Items.STEEL_HASTAP_11393, Items.STEEL_HASTAP_PLUS_11396, Items.STEEL_HASTAP_PLUS_PLUS_11398),
MITHRIL_HASTA(Items.MITHRIL_HASTA_11373, Items.MITHRIL_HASTAP_11400, Items.MITHRIL_HASTAP_PLUS_11403, Items.MITHRIL_HASTAP_PLUS_PLUS_11405),
ADAMANT_HASTA(Items.ADAMANT_HASTA_11375, Items.ADAMANT_HASTAP_11407, Items.ADAMANT_HASTAP_PLUS_11410, Items.ADAMANT_HASTAP_PLUS_PLUS_11412),
RUNE_HASTA(Items.RUNE_HASTA_11377, Items.RUNE_HASTAP_11414, Items.RUNE_HASTAP_PLUS_11417, Items.RUNE_HASTAP_PLUS_PLUS_11419);
companion object { companion object {
val itemMap = values().map { it.base to intArrayOf(it.p,it.pp,it.ppp) }.toMap() val itemMap = values().map { it.base to intArrayOf(it.p,it.pp,it.ppp) }.toMap()

View file

@ -136,7 +136,7 @@ public final class SoftclayPlugin extends UseWithHandler {
player.getPacketDispatch().sendMessage("You mix the clay and water. You now have some soft, workable clay."); player.getPacketDispatch().sendMessage("You mix the clay and water. You now have some soft, workable clay.");
player.getInventory().add(SOFT_CLAY); player.getInventory().add(SOFT_CLAY);
player.getInventory().add(returnItem); player.getInventory().add(returnItem);
if (!player.getAchievementDiaryManager().hasCompletedTask(DiaryType.LUMBRIDGE, 0, 6) && player.getLocation().getRegionId() == 12341) { if (!player.getAchievementDiaryManager().hasCompletedTask(DiaryType.LUMBRIDGE, 0, 6) && player.getViewport().getRegion().getId() == 12341) {
player.getAchievementDiaryManager().finishTask(player, DiaryType.LUMBRIDGE, 0, 6); player.getAchievementDiaryManager().finishTask(player, DiaryType.LUMBRIDGE, 0, 6);
} }
return true; return true;

View file

@ -1,6 +1,5 @@
package content.global.handlers.item.withobject package content.global.handlers.item.withobject
import content.region.kandarin.seers.diary.SeersVillageAchievementDiary
import core.api.* import core.api.*
import core.game.node.item.Item import core.game.node.item.Item
import org.rs09.consts.Items import org.rs09.consts.Items
@ -27,8 +26,6 @@ class CoalTruckListener : InteractionListener {
return@on true return@on true
} }
val coalTruckFull = coalInTruck == 120
var toRemove = freeSlots(player) var toRemove = freeSlots(player)
if (toRemove > coalInTruck) { if (toRemove > coalInTruck) {
@ -38,10 +35,6 @@ class CoalTruckListener : InteractionListener {
if (addItem(player, Items.COAL_453, toRemove)) { if (addItem(player, Items.COAL_453, toRemove)) {
coalInTruck -= toRemove coalInTruck -= toRemove
setAttribute(player, "/save:$ATTRIBUTE_COAL_TRUCK_INVENTORY", coalInTruck) setAttribute(player, "/save:$ATTRIBUTE_COAL_TRUCK_INVENTORY", coalInTruck)
if (toRemove > 0) {
SeersVillageAchievementDiary().onCoalRemovedFromSeersTruck(player, node, coalTruckFull)
}
} }
return@on true return@on true

View file

@ -15,19 +15,30 @@ import org.rs09.consts.Sounds
* @author Ceikry * @author Ceikry
*/ */
class WaterSourceListener : InteractionListener { class WaterSourceListener : InteractionListener {
private val waterSources = intArrayOf(21355, 16302, 6827, 11661, 24160, 34577, 15936, 15937, 15938, 23920, 35469, 24265, 153, 879, 880, 2864, 6232, 10436, 10437, 10827, 11007, 11759, 21764, 22973, 24161, 24214, 24265, 28662, 30223, 30820, 34579, 36781, 873, 874, 4063, 6151, 8699, 9143, 9684, 10175, 12279, 12974, 13563, 13564, 14868, 14917, 14918, 15678, 16704, 16705, 20358, 22715, 24112, 24314, 25729, 25929, 26966, 29105, 33458, 34082, 34411, 34496, 34547, 34566, 35762, 36971, 37154, 37155, 878, 884, 3264, 3305, 3359, 4004, 4005, 6097, 6249, 6549, 8747, 8927, 11793, 12201, 12897, 24166, 26945, 31359, 32023, 32024, 34576, 35671, 40063, 13561, 13563, 13559, 12089) // NOTE '9695' should be removed from the array below once the sink object can be used directly, this is a temporary
// solution.
// this is ugly!
private val waterSources = intArrayOf(21355, 16302, 6827, 11661, 24160, 34577, 15936, 15937, 15938, 23920, 35469, 24265, 153, 879, 880, 2864, 6232, 10436, 10437, 10827, 11007, 11759, 21764, 22973, 24161, 24214, 24265, 28662, 30223, 30820, 34579, 36781, 873, 874, 4063, 6151, 8699, 9143, 9684, 9695, 10175, 12279, 12974, 13563, 13564, 14868, 14917, 14918, 15678, 16704, 16705, 20358, 22715, 24112, 24314, 25729, 25929, 26966, 29105, 33458, 34082, 34411, 34496, 34547, 34566, 35762, 36971, 37154, 37155, 878, 884, 3264, 3305, 3359, 4004, 4005, 6097, 6249, 6549, 8747, 8927, 11793, 12201, 12897, 24166, 26945, 31359, 32023, 32024, 34576, 35671, 40063, 13561, 13563, 13559, 12089)
private val nonWellableMsg = "If I drop my @ down there, I don't think I'm likely to get it back." private val nonWellableMsg = "If I drop my @ down there, I don't think I'm likely to get it back."
private val animation = Animation(832) private val animation = Animation(832)
override fun defineListeners() { override fun defineListeners()
{
onUseWith(IntType.SCENERY, WaterVessel.getInputs(), *waterSources){ player, used, with -> onUseWith(IntType.SCENERY, WaterVessel.getInputs(), *waterSources){ player, used, with ->
val vessel = WaterVessel.forId(used.id) ?: return@onUseWith false val vessel = WaterVessel.forId(used.id) ?: return@onUseWith false
if(with.name.contains("well", ignoreCase = true) && !vessel.wellable) if(with.name.contains("well", ignoreCase = true) && !vessel.wellable)
{ {
sendMessage(player, formatMsgText(used.name, nonWellableMsg)) sendMessage(player, formatMsgText(used.name, nonWellableMsg))
return@onUseWith true return@onUseWith true
} }
if(with.id == 9695 && player.location.regionId != 11571)
{
return@onUseWith false
}
//ugly achievement code, achievement system sux //ugly achievement code, achievement system sux
if(vessel == WaterVessel.BUCKET && with.id == 11661) if(vessel == WaterVessel.BUCKET && with.id == 11661)
{ {
@ -56,6 +67,15 @@ class WaterSourceListener : InteractionListener {
return@onUseWith true return@onUseWith true
} }
// This is needed to make the crafting guild sink work, but technically it's wrong as it is the noticeboard and
// not the sink being used. This is a temporary solution until the sink object can be used directly.
setDest(IntType.SCENERY, intArrayOf(9695), "use") { player, node ->
if (player.location.regionId == 11571){
return@setDest Location.create(2934, 3280, 0)
}
return@setDest node.location
}
} }
private fun formatMsgText(name: String, template: String): String private fun formatMsgText(name: String, template: String): String

View file

@ -14,11 +14,9 @@ import core.game.node.entity.npc.AbstractNPC
import core.game.node.entity.npc.NPC import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player import core.game.node.entity.player.Player
import core.game.node.entity.player.link.IronmanMode import core.game.node.entity.player.link.IronmanMode
import core.game.node.item.Item
import core.game.world.map.Direction import core.game.world.map.Direction
import core.game.world.map.Location import core.game.world.map.Location
import core.plugin.Initializable import core.plugin.Initializable
import org.rs09.consts.Items
import org.rs09.consts.NPCs import org.rs09.consts.NPCs
/** /**
@ -41,7 +39,7 @@ class BankerNPC : AbstractNPC, InteractionListener {
NPCs.GHOST_BANKER_1702, NPCs.GNOME_BANKER_166, NPCs.NARDAH_BANKER_3046, NPCs.MAGNUS_GRAM_5488, NPCs.TZHAAR_KET_ZUH_2619, NPCs.GHOST_BANKER_1702, NPCs.GNOME_BANKER_166, NPCs.NARDAH_BANKER_3046, NPCs.MAGNUS_GRAM_5488, NPCs.TZHAAR_KET_ZUH_2619,
NPCs.SIRSAL_BANKER_4519, NPCs.FADLI_958, NPCs.BANK_TUTOR_4907, NPCs.JADE_4296, NPCs.SIRSAL_BANKER_4519, NPCs.FADLI_958, NPCs.BANK_TUTOR_4907, NPCs.JADE_4296,
NPCs.OGRESS_BANKER_7049, NPCs.OGRESS_BANKER_7050, NPCs.OGRESS_BANKER_7049, NPCs.OGRESS_BANKER_7050,
NPCs.BANKER_6538, NPCs.ODOVACAR_5383 NPCs.BANKER_6538
) )
companion object { companion object {
@ -63,25 +61,6 @@ class BankerNPC : AbstractNPC, InteractionListener {
return false return false
} }
private const val ODOVACAR_FEE = 100
/**
* Handles special access requirements for bankers that charge a fee.
* @return true if banking may proceed, false if it should be blocked.
*/
fun canAccessBank(player: Player, npc: NPC): Boolean {
if (npc.id != NPCs.ODOVACAR_5383) {
return true
}
if (removeItem(player, Item(Items.COINS_995, ODOVACAR_FEE))) {
sendMessage(player, "You pay 100 coins to use the travelling bank.")
return true
}
return false
}
fun attemptBank(player: Player, node: Node): Boolean { fun attemptBank(player: Player, node: Node): Boolean {
val npc = node as NPC val npc = node as NPC
@ -90,11 +69,6 @@ class BankerNPC : AbstractNPC, InteractionListener {
return true return true
} }
if (!canAccessBank(player, node)) {
sendMessage(player, "You need 100 coins to use the travelling bank.")
return true
}
npc.faceLocation(null) npc.faceLocation(null)
openBankAccount(player) openBankAccount(player)
@ -184,7 +158,7 @@ class BankerNPC : AbstractNPC, InteractionListener {
} }
class BankerDialogueLabellerFile : DialogueLabeller() { class BankerDialogueLabellerFile : DialogueLabeller() {
val BANKERS_WITH_EXTRA_OPTION = intArrayOf(NPCs.BANK_TUTOR_4907, NPCs.JADE_4296, NPCs.BANKER_6538, NPCs.ODOVACAR_5383) val BANKERS_WITH_EXTRA_OPTION = intArrayOf(NPCs.BANK_TUTOR_4907, NPCs.JADE_4296, NPCs.BANKER_6538)
override fun addConversation() { override fun addConversation() {
exec { player, npc -> exec { player, npc ->
@ -224,7 +198,6 @@ class BankerNPC : AbstractNPC, InteractionListener {
options( options(
DialogueOption("how to use", "How do I use the bank?") { _, npc -> return@DialogueOption npc.id == NPCs.BANK_TUTOR_4907 }, DialogueOption("how to use", "How do I use the bank?") { _, npc -> return@DialogueOption npc.id == NPCs.BANK_TUTOR_4907 },
DialogueOption("who is the bounty hunter banker", "Who are you?") { _, npc -> return@DialogueOption npc.id == NPCs.BANKER_6538 }, DialogueOption("who is the bounty hunter banker", "Who are you?") { _, npc -> return@DialogueOption npc.id == NPCs.BANKER_6538 },
DialogueOption("who is odovacar", "Who are you?") { _, npc -> return@DialogueOption npc.id == NPCs.ODOVACAR_5383 },
DialogueOption("access", "I'd like to access my bank account please.", expression = ChatAnim.ASKING), DialogueOption("access", "I'd like to access my bank account please.", expression = ChatAnim.ASKING),
DialogueOption("buy second bank", "I'd like to open a secondary bank account.") { player, _ -> return@DialogueOption ServerConstants.SECOND_BANK && !hasActivatedSecondaryBankAccount(player) }, DialogueOption("buy second bank", "I'd like to open a secondary bank account.") { player, _ -> return@DialogueOption ServerConstants.SECOND_BANK && !hasActivatedSecondaryBankAccount(player) },
DialogueOption("switch second bank", "I'd like to switch to my primary bank account.") { player, _ -> return@DialogueOption hasActivatedSecondaryBankAccount(player) && isUsingSecondaryBankAccount(player) }, DialogueOption("switch second bank", "I'd like to switch to my primary bank account.") { player, _ -> return@DialogueOption hasActivatedSecondaryBankAccount(player) && isUsingSecondaryBankAccount(player) },
@ -269,43 +242,9 @@ class BankerNPC : AbstractNPC, InteractionListener {
npc(ChatAnim.NEUTRAL, "How inconsiderate of me, dear @g[sir,madam]. My name is Maximillian Sackville and I conduct operations here on behalf of The Bank of Gielinor.") npc(ChatAnim.NEUTRAL, "How inconsiderate of me, dear @g[sir,madam]. My name is Maximillian Sackville and I conduct operations here on behalf of The Bank of Gielinor.")
goto("main options") goto("main options")
label("who is odovacar")
npc("How frightfully rude of me, my dear @g[chap,lady]. My name is Odovacar and I work for that excellent enterprise, the Bank of Gielinor.")
player("If you work for the bank, what are you doing here?")
npc("As part of our ongoing service to provide you, the customer, with an absolutely world-class banking experience, we are investigating the option of opening a chain of travelling banks.")
npc("These will provide you, our esteemed customer, with the convenience of having banking facilities where they will be of optimum use to you. Such as here!")
player("Huh?")
npc("I am the first of a new generation of travelling bankers that will wander the perilous areas of the world to provide you, the valued customer, with a bank when you need it most!")
player("So I can access my bank account simply by talking to you?")
npc("Absolutely correct, dear @g[sir,lady].")
npc("I must warn you, however, that due to the significantly increased overheads of an enterprise such as this, there is a small bank charge of 100gp every time you want to access your account.")
options(
DialogueOption("access", "Sounds fair; here's the money. Can I access my account now?"),
DialogueOption("payafterbank", "Let me open my account and then I'll pay you."),
DialogueOption("nopay2bank", "That's preposterous! I'm not paying to withdraw my own money!")
)
label("payafterbank")
npc("It's not that I don't trust you, old @g[chap,girl], but as the old adage goes, 'money comes before friends'.")
goto("nowhere")
label("nopay2bank")
npc("I'm sorry to hear that, @g[sir,madam]. If you should reconsider, because I believe this service offers excellent value for money, do not hesitate to contact me.")
goto("nowhere")
label("nomoney")
npc("I'm afraid you don't have the necessary funds with you at this time so I can't allow you to access your account. Please come again, when you have 100 gold to cover the fee.")
goto("nowhere")
label("access") label("access")
exec { player, npc -> exec { player, _ -> openBankAccount(player) }
if (!canAccessBank(player, npc)) {
goto("nomoney")
} else {
openBankAccount(player)
goto("nowhere") goto("nowhere")
}
}
label("buy second bank") label("buy second bank")
npc("Certainly. We offer secondary accounts to all our customers.") npc("Certainly. We offer secondary accounts to all our customers.")

View file

@ -2,7 +2,6 @@ package content.global.handlers.npc
import content.data.consumables.Consumables import content.data.consumables.Consumables
import content.global.skill.cooking.fermenting.CalquatDecant import content.global.skill.cooking.fermenting.CalquatDecant
import content.region.kandarin.quest.barbariantraining.BarbarianTraining
import core.api.* import core.api.*
import core.game.consumable.Potion import core.game.consumable.Potion
import core.game.dialogue.DialogueFile import core.game.dialogue.DialogueFile
@ -119,7 +118,7 @@ class DecantListener : InteractionListener {
// Barbarian decanting: use a 4-dose potion and an empty vial together to make two 2-dose potions // 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 -> onUseWith(IntType.ITEM, potions, Items.VIAL_229) { player, used, with ->
// Check if player has started barbarian herblore training // Check if player has started barbarian herblore training
if (getAttribute(player, BarbarianTraining.attributeHerblore, 0) == 0) { if (getAttribute(player, "/save:barbtraining:herblore", 0) == 0) {
return@onUseWith false return@onUseWith false
} }

View file

@ -129,9 +129,9 @@ class SheepBehavior : NPCBehavior(*sheepIds), InteractionListener {
val sheepDirection = Direction.getDirection(sheepLocation, playerLocation) // Get direction sheep is facing, from the player's location val sheepDirection = Direction.getDirection(sheepLocation, playerLocation) // Get direction sheep is facing, from the player's location
val sheepOppositeDirection = sheepDirection.getOpposite() // Switch to opposite direction val sheepOppositeDirection = sheepDirection.getOpposite() // Switch to opposite direction
val xWalkLocation = sheepLocation.x + (sheepOppositeDirection.getStepX() * 3) // Gets x location, if set, 3 steps away from player val xWalkLocation = sheepLocation.getX() + (sheepOppositeDirection.getStepX() * 3) // Gets x location, if set, 3 steps away from player
val yWalkLocation = sheepLocation.y + (sheepOppositeDirection.getStepY() * 3) // Gets y location, if set, 3 steps away from player val yWalkLocation = sheepLocation.getY() + (sheepOppositeDirection.getStepY() * 3) // Gets y location, if set, 3 steps away from player
val sheepWalkToLocation = Location(xWalkLocation, yWalkLocation, sheepLocation.z); // New location for pathfinding val sheepWalkToLocation = Location(xWalkLocation, yWalkLocation, sheepLocation.getZ()); // New location for pathfinding
sendMessage(player, messagePlayer) sendMessage(player, messagePlayer)

View file

@ -20,12 +20,10 @@ import core.tools.RandomFunction;
import org.rs09.consts.Sounds; import org.rs09.consts.Sounds;
import static core.api.ContentAPIKt.playAudio; import static core.api.ContentAPIKt.playAudio;
import static core.api.ContentAPIKt.sendMessage;
/** /**
* Handles the pick option of interactive scenery (non-farming cabbages, * Handles the pick option of interactive scenery (non-farming cabbages,
* potatoes, bananas, etc) * potatoes, bananas, etc)
*
* @author Emperor * @author Emperor
* @version 1.0 * @version 1.0
*/ */
@ -39,10 +37,10 @@ public final class FieldPickingPlugin extends OptionHandler {
@Override @Override
public Plugin<Object> newInstance(Object arg) throws Throwable { public Plugin<Object> newInstance(Object arg) throws Throwable {
for (PickingPlant p : PickingPlant.values()) { for(PickingPlant p : PickingPlant.values()){
SceneryDefinition.forId(p.objectId).getHandlers().put("option:pick", this); SceneryDefinition.forId(p.objectId).getHandlers().put("option:pick",this);
} }
SceneryDefinition.forId(3511).getHandlers().put("option:take-cutting", this); SceneryDefinition.forId(3511).getHandlers().put("option:take-cutting",this);
return this; return this;
} }
@ -107,12 +105,10 @@ public final class FieldPickingPlugin extends OptionHandler {
if (!isBloomPlant) { if (!isBloomPlant) {
SceneryBuilder.replace(plant == PickingPlant.BANANA_TREE_4 ? full : object, object.transform(banana ? plant.respawn : 0), banana ? 300 : plant.respawn); SceneryBuilder.replace(plant == PickingPlant.BANANA_TREE_4 ? full : object, object.transform(banana ? plant.respawn : 0), banana ? 300 : plant.respawn);
} }
if (plant.name().startsWith("NETTLES")) { if (!plant.name().startsWith("NETTLES")) {
sendMessage(player, "You pick a handful of nettles."); player.getPacketDispatch().sendMessage("You pick a " + reward.getName().toLowerCase() + ".");
} else if (plant.name().startsWith("GLOWING")) {
sendMessage(player, "You pull the fungus from the water, it is very cold to the touch.");
} else { } else {
sendMessage(player, "You pick a " + reward.getName().toLowerCase() + "."); player.getPacketDispatch().sendMessage("You pick a handful of nettles.");
} }
return true; return true;
} }
@ -122,7 +118,6 @@ public final class FieldPickingPlugin extends OptionHandler {
/** /**
* Method used to handle the flax picking. * Method used to handle the flax picking.
*
* @param player the player. * @param player the player.
* @param object the object. * @param object the object.
* @param plant the plank. * @param plant the plank.
@ -143,7 +138,6 @@ public final class FieldPickingPlugin extends OptionHandler {
/** /**
* Represents a plant to be picked. * Represents a plant to be picked.
*
* @author Emperor * @author Emperor
*/ */
private static enum PickingPlant { private static enum PickingPlant {
@ -192,6 +186,7 @@ public final class FieldPickingPlugin extends OptionHandler {
GOLDEN_PEAR_BUSH(3513, 2974, -1), GOLDEN_PEAR_BUSH(3513, 2974, -1),
GLOWING_FUNGUS_0(4932, 4075, 30), GLOWING_FUNGUS_0(4932, 4075, 30),
GLOWING_FUNGUS_1(4933, 4075, 30), GLOWING_FUNGUS_1(4933, 4075, 30),
RARE_FLOWERS(5006, 2460, 30),
BLACK_MUSHROOMS(6311, 4620, 30), BLACK_MUSHROOMS(6311, 4620, 30),
KELP(12478, 7516, 30), KELP(12478, 7516, 30),
RED_BANANA_TREE(12609, 7572, 30), RED_BANANA_TREE(12609, 7572, 30),
@ -208,7 +203,7 @@ public final class FieldPickingPlugin extends OptionHandler {
TANSYMUM(29115, 12576, 30), TANSYMUM(29115, 12576, 30),
PRIMWEED(29116, 12588, 30), PRIMWEED(29116, 12588, 30),
STINKBLOOM(29117, 12590, 30), STINKBLOOM(29117, 12590, 30),
TROLLWEISS_FLOWERS(5006, 4086, 30), TROLLWEISS_FLOWERS(37328, 4086, 30),
HOLLOW_LOG(37830, 10968, 30); HOLLOW_LOG(37830, 10968, 30);
/** /**
@ -228,7 +223,6 @@ public final class FieldPickingPlugin extends OptionHandler {
/** /**
* Constructs a new {@code FieldPickingPlugin {@code Object}. * Constructs a new {@code FieldPickingPlugin {@code Object}.
*
* @param objectId the object id. * @param objectId the object id.
* @param reward the reward. * @param reward the reward.
* @param respawn the resapwn. * @param respawn the resapwn.
@ -241,7 +235,6 @@ public final class FieldPickingPlugin extends OptionHandler {
/** /**
* Gets the picking plant by the id. * Gets the picking plant by the id.
*
* @param objectId the id. * @param objectId the id.
* @return the picking plant. * @return the picking plant.
*/ */

View file

@ -413,7 +413,7 @@ class TableListener : InteractionListener {
} }
val droppedItem = used.dropItem val droppedItem = used.dropItem
if (droppedItem.id == Items.COINS_995) playAudio(player, DROP_COINS_SOUND) else playAudio(player, DROP_ITEM_SOUND) if (droppedItem.id == Items.COINS_995) playAudio(player, DROP_COINS_SOUND) else playAudio(player, DROP_ITEM_SOUND)
GroundItemManager.create(droppedItem, Location(nearestX, nearestY, player.location.z), player) GroundItemManager.create(droppedItem, Location(nearestX, nearestY), player)
setAttribute(player, "droppedItem:${droppedItem.id}", getWorldTicks() + 2) setAttribute(player, "droppedItem:${droppedItem.id}", getWorldTicks() + 2)
PlayerParser.save(player) PlayerParser.save(player)

View file

@ -139,13 +139,6 @@ public final class AgilityHandler {
* @return The force movement instance, if force movement is used. * @return The force movement instance, if force movement is used.
*/ */
public static ForceMovement forceWalk(final Player player, final int courseIndex, Location start, Location end, Animation animation, int speed, final double experience, final String message) { public static ForceMovement forceWalk(final Player player, final int courseIndex, Location start, Location end, Animation animation, int speed, final double experience, final String message) {
return forceWalk(player, courseIndex, start, end, animation, speed, experience, message, null);
}
/**
* Walks across an obstacle while using an explicit force-movement facing direction.
*/
public static ForceMovement forceWalk(final Player player, final int courseIndex, Location start, Location end, Animation animation, int speed, final double experience, final String message, Direction direction) {
player.logoutListeners.put("forcewalk", p -> { player.logoutListeners.put("forcewalk", p -> {
p.setLocation(player.getLocation().transform(0,0,0)); p.setLocation(player.getLocation().transform(0,0,0));
return Unit.INSTANCE; return Unit.INSTANCE;
@ -165,9 +158,6 @@ public final class AgilityHandler {
player.logoutListeners.remove("forcewalk"); player.logoutListeners.remove("forcewalk");
} }
}; };
if (direction != null) {
movement.setDirection(direction);
}
movement.start(); movement.start();
GameWorld.getPulser().submit(movement); GameWorld.getPulser().submit(movement);
return movement; return movement;

View file

@ -2,7 +2,6 @@ package content.global.skill.agility
import core.api.* import core.api.*
import core.cache.def.impl.SceneryDefinition import core.cache.def.impl.SceneryDefinition
import core.game.interaction.QueueStrength
import core.game.node.Node import core.game.node.Node
import core.game.node.scenery.Scenery import core.game.node.scenery.Scenery
import core.game.node.entity.player.Player import core.game.node.entity.player.Player
@ -169,27 +168,25 @@ class WildernessCourse
private fun handleSteppingStones(player: Player, `object`: Scenery) { private fun handleSteppingStones(player: Player, `object`: Scenery) {
lock(player, 50) lock(player, 50)
val fail = AgilityHandler.hasFailed(player, 1, 0.3) val fail = AgilityHandler.hasFailed(player, 1, 0.3)
queueScript(player, 0, QueueStrength.SOFT) { stage -> val origLoc = player.location
val courseIndex = if (stage == 5) 2 else -1 registerLogoutListener(player, "steppingstone"){p ->
val start = player.location player.location = origLoc
val end = player.location.transform(-1, 0, 0)
val anim = Animation(741)
val xp = if (stage == 5) 20.0 else 0.0
val message = if (stage == 0) "You carefully start crossing the stepping stones..." else null
AgilityHandler.forceWalk(player, courseIndex, start, end, anim, 10, xp, message)
if (stage == 2 && fail) {
val dest = Location(3001, 3963, 0)
val failanim = Animation(771)
val hit = (player.skills.lifepoints * 0.26).toInt()
AgilityHandler.fail(player, -1, dest, failanim, hit, "... You lose your footing and fall into the lava.")
return@queueScript stopExecuting(player)
} }
if (stage == 5) { submitWorldPulse(object : Pulse(2, player){
var counter = 0
override fun pulse(): Boolean {
if (counter == 3 && fail) {
AgilityHandler.fail(player, -1, Location.create(3001, 3963, 0), Animation.create(771), (player.skills.lifepoints * 0.26).toInt(), "...You lose your footing and fall into the lava.")
return true
}
AgilityHandler.forceWalk(player, if (counter == 5) 2 else -1, player.location, player.location.transform(-1, 0, 0), Animation.create(741), 10, if (counter == 5) 20.0 else 0.0, if (counter != 0) null else "You carefully start crossing the stepping stones...")
if(++counter == 6){
unlock(player) unlock(player)
return@queueScript stopExecuting(player) clearLogoutListener(player, "steppingstone")
} }
return@queueScript delayScript(player, 2) return counter == 6
} }
})
} }
/** /**

View file

@ -5,9 +5,6 @@ import core.game.node.entity.Entity;
import core.game.node.entity.player.Player; import core.game.node.entity.player.Player;
import core.game.system.task.MovementHook; import core.game.system.task.MovementHook;
import core.game.system.task.Pulse; import core.game.system.task.Pulse;
import core.net.packet.PacketRepository;
import core.net.packet.context.PlayerContext;
import core.net.packet.out.ClearMinimapFlag;
import kotlin.Unit; import kotlin.Unit;
import core.game.world.GameWorld; import core.game.world.GameWorld;
import core.game.world.map.Direction; import core.game.world.map.Direction;
@ -27,10 +24,6 @@ public final class BladeTrap implements MovementHook {
final Direction dir = e.getDirection(); final Direction dir = e.getDirection();
final Player player = (Player) e; final Player player = (Player) e;
final Location start = l.transform(-dir.getStepX(), -dir.getStepY(), 0); final Location start = l.transform(-dir.getStepX(), -dir.getStepY(), 0);
player.getPulseManager().clear();
player.getWalkingQueue().reset();
PacketRepository.send(ClearMinimapFlag.class, new PlayerContext(player));
e.lock(5); e.lock(5);
if(e.isPlayer()) if(e.isPlayer())
{ {

View file

@ -237,32 +237,30 @@ public final class BrimhavenArena extends MapZone implements Plugin<Object> {
return false; return false;
} }
if (GameWorld.getTicks() % 100 == 0) { if (GameWorld.getTicks() % 100 == 0) {
for (int z = 0; z < 4; z++) { for (RegionPlane plane : r.getPlanes()) {
for (Player player : r.assemblePlayerList(z)) { for (Player player : plane.getPlayers()) {
if (player != null) {
setDispenser(player); setDispenser(player);
} }
} }
}
handlePlankSwitching(); handlePlankSwitching();
} }
int ticks = 3; int ticks = 3;
if (GameWorld.getTicks() % ticks == 0) { if (GameWorld.getTicks() % ticks == 0) {
sawBladeActive = !sawBladeActive; sawBladeActive = !sawBladeActive;
if (sawBladeActive) { if (sawBladeActive) {
Scenery object = RegionManager.getObject(2788, 9579, 3); Scenery object = RegionManager.getObject(3, 2788, 9579);
SceneryBuilder.replace(object, object.transform(3567, object.getRotation(), 10), ticks); SceneryBuilder.replace(object, object.transform(3567, object.getRotation(), 10), ticks);
object = RegionManager.getObject(2789, 9579, 3); object = RegionManager.getObject(3, 2789, 9579);
SceneryBuilder.replace(object, object.transform(0), ticks); SceneryBuilder.replace(object, object.transform(0), ticks);
object = RegionManager.getObject(2783, 9551, 3); object = RegionManager.getObject(3, 2783, 9551);
SceneryBuilder.replace(object, object.transform(3567, object.getRotation(), 10), ticks); SceneryBuilder.replace(object, object.transform(3567, object.getRotation(), 10), ticks);
object = RegionManager.getObject(2783, 9552, 3); object = RegionManager.getObject(3, 2783, 9552);
SceneryBuilder.replace(object, object.transform(0), ticks); SceneryBuilder.replace(object, object.transform(0), ticks);
object = RegionManager.getObject(2761, 9584, 3); object = RegionManager.getObject(3, 2761, 9584);
SceneryBuilder.replace(object, object.transform(3567, object.getRotation(), 10), ticks); SceneryBuilder.replace(object, object.transform(3567, object.getRotation(), 10), ticks);
object = RegionManager.getObject(2761, 9585, 3); object = RegionManager.getObject(3, 2761, 9585);
SceneryBuilder.replace(object, object.transform(0), ticks); SceneryBuilder.replace(object, object.transform(0), ticks);
} }
} }

View file

@ -119,8 +119,6 @@ public final class BrimhavenCourse extends OptionHandler {
final Direction dir = direction; final Direction dir = direction;
final Direction faceDirection = Direction.get(object.getDirection().toInteger() - 1 & 3); final Direction faceDirection = Direction.get(object.getDirection().toInteger() - 1 & 3);
final Location start = player.getLocation(); final Location start = player.getLocation();
player.setDirection(faceDirection);
player.faceLocation(start.transform(faceDirection));
player.getAppearance().setAnimations(Animation.create(1118 + m)); player.getAppearance().setAnimations(Animation.create(1118 + m));
player.getAppearance().sync(); player.getAppearance().sync();
AgilityHandler.climb(player, -1, new Animation(1117 + m), start.transform(dir), 0.0, null); AgilityHandler.climb(player, -1, new Animation(1117 + m), start.transform(dir), 0.0, null);
@ -145,12 +143,12 @@ public final class BrimhavenCourse extends OptionHandler {
} else if (count == 6) { } else if (count == 6) {
player.getAppearance().setAnimations(); player.getAppearance().setAnimations();
player.getAppearance().sync(); player.getAppearance().sync();
AgilityHandler.forceWalk(player, -1, last, last.transform(dir), Animation.create(1120 + m), 5, getExp(player, 22.0), null, faceDirection); AgilityHandler.forceWalk(player, -1, last, last.transform(dir), Animation.create(1120 + m), 5, getExp(player, 22.0), null).setDirection(faceDirection);
player.logoutListeners.remove("brimcourse"); player.logoutListeners.remove("brimcourse");
return true; return true;
} }
player.logoutListeners.remove("brimcourse"); player.logoutListeners.remove("brimcourse");
AgilityHandler.forceWalk(player, -1, last, last = last.transform(dir), Animation.create(1118 + m), 5, 0.0, null, faceDirection); AgilityHandler.forceWalk(player, -1, last, last = last.transform(dir), Animation.create(1118 + m), 5, 0.0, null).setDirection(faceDirection);
return false; return false;
} }
}); });
@ -274,7 +272,7 @@ public final class BrimhavenCourse extends OptionHandler {
public boolean pulse() { public boolean pulse() {
if (!finish) { if (!finish) {
setDelay(2); setDelay(2);
AgilityHandler.fail(player, 1, player.getLocation().transform(0, 0, -3), Animation.create(768), getHitAmount(player), "You stepped on a broken piece of plank!"); AgilityHandler.fail(player, 1, player.getLocation().transform(0, 0, -3), Animation.create(189), getHitAmount(player), "You stepped on a broken piece of plank!");
finish = true; finish = true;
return false; return false;
} }
@ -284,7 +282,7 @@ public final class BrimhavenCourse extends OptionHandler {
}); });
return; return;
} }
AgilityHandler.walk(player, -1, start, end, Animation.create(1426), getExp(player, 6.0), null); AgilityHandler.walk(player, -1, start, end, ForceMovement.WALK_ANIMATION, getExp(player, 6.0), null);
} }
/** /**
@ -391,7 +389,6 @@ public final class BrimhavenCourse extends OptionHandler {
} }
break; break;
case 3551: case 3551:
case 3583:
return n.getLocation(); return n.getLocation();
} }
return null; return null;

View file

@ -7,8 +7,6 @@ import core.game.node.entity.impl.Projectile;
import core.game.node.entity.player.Player; import core.game.node.entity.player.Player;
import core.game.system.task.MovementHook; import core.game.system.task.MovementHook;
import core.game.system.task.Pulse; import core.game.system.task.Pulse;
import core.net.packet.context.PlayerContext;
import core.net.packet.out.ClearMinimapFlag;
import kotlin.Unit; import kotlin.Unit;
import core.game.world.GameWorld; import core.game.world.GameWorld;
import core.game.world.map.Direction; import core.game.world.map.Direction;
@ -31,9 +29,6 @@ public final class DartTrap implements MovementHook {
final Direction dir = e.getDirection(); final Direction dir = e.getDirection();
final Player player = (Player) e; final Player player = (Player) e;
final Location start = l.transform(-dir.getStepX(), -dir.getStepY(), 0); final Location start = l.transform(-dir.getStepX(), -dir.getStepY(), 0);
player.getPulseManager().clear();
player.getWalkingQueue().reset();
PacketRepository.send(ClearMinimapFlag.class, new PlayerContext(player));
e.lock(6); e.lock(6);
if(e.isPlayer()) if(e.isPlayer())
{ {

View file

@ -6,9 +6,6 @@ import core.game.node.entity.Entity;
import core.game.node.entity.player.Player; import core.game.node.entity.player.Player;
import core.game.system.task.MovementHook; import core.game.system.task.MovementHook;
import core.game.system.task.Pulse; import core.game.system.task.Pulse;
import core.net.packet.PacketRepository;
import core.net.packet.context.PlayerContext;
import core.net.packet.out.ClearMinimapFlag;
import kotlin.Unit; import kotlin.Unit;
import core.game.world.GameWorld; import core.game.world.GameWorld;
import core.game.world.map.Direction; import core.game.world.map.Direction;
@ -27,9 +24,6 @@ public final class FloorSpikes implements MovementHook {
final Direction dir = e.getDirection(); final Direction dir = e.getDirection();
final Player player = (Player) e; final Player player = (Player) e;
final Location start = l.transform(-dir.getStepX(), -dir.getStepY(), 0); final Location start = l.transform(-dir.getStepX(), -dir.getStepY(), 0);
player.getPulseManager().clear();
player.getWalkingQueue().reset();
PacketRepository.send(ClearMinimapFlag.class, new PlayerContext(player));
e.lock(5); e.lock(5);
if(e.isPlayer()) if(e.isPlayer())
{ {

View file

@ -6,9 +6,6 @@ import core.game.node.entity.Entity;
import core.game.node.entity.player.Player; import core.game.node.entity.player.Player;
import core.game.system.task.MovementHook; import core.game.system.task.MovementHook;
import core.game.system.task.Pulse; import core.game.system.task.Pulse;
import core.net.packet.PacketRepository;
import core.net.packet.context.PlayerContext;
import core.net.packet.out.ClearMinimapFlag;
import kotlin.Unit; import kotlin.Unit;
import core.game.world.GameWorld; import core.game.world.GameWorld;
import core.game.world.map.Direction; import core.game.world.map.Direction;
@ -27,10 +24,6 @@ public final class PressurePad implements MovementHook {
final Direction dir = e.getDirection(); final Direction dir = e.getDirection();
final Player player = (Player) e; final Player player = (Player) e;
final Location start = dest.transform(-dir.getStepX(), -dir.getStepY(), 0); final Location start = dest.transform(-dir.getStepX(), -dir.getStepY(), 0);
player.getPulseManager().clear();
player.getWalkingQueue().reset();
PacketRepository.send(ClearMinimapFlag.class, new PlayerContext(player));
e.lock(5); e.lock(5);
if(e.isPlayer()) if(e.isPlayer())
{ {

View file

@ -6,9 +6,6 @@ import core.game.node.entity.Entity;
import core.game.node.entity.player.Player; import core.game.node.entity.player.Player;
import core.game.system.task.MovementHook; import core.game.system.task.MovementHook;
import core.game.system.task.Pulse; import core.game.system.task.Pulse;
import core.net.packet.PacketRepository;
import core.net.packet.context.PlayerContext;
import core.net.packet.out.ClearMinimapFlag;
import kotlin.Unit; import kotlin.Unit;
import core.game.world.GameWorld; import core.game.world.GameWorld;
import core.game.world.map.Direction; import core.game.world.map.Direction;
@ -27,9 +24,6 @@ public final class SpinningBlades implements MovementHook {
final Direction dir = e.getDirection(); final Direction dir = e.getDirection();
final Player player = (Player) e; final Player player = (Player) e;
final Location start = l.transform(-dir.getStepX(), -dir.getStepY(), 0); final Location start = l.transform(-dir.getStepX(), -dir.getStepY(), 0);
player.getPulseManager().clear();
player.getWalkingQueue().reset();
PacketRepository.send(ClearMinimapFlag.class, new PlayerContext(player));
e.lock(5); e.lock(5);
if(e.isPlayer()) if(e.isPlayer())
{ {

View file

@ -65,16 +65,14 @@ public enum BuildHotspot {
* Low-level Work shop hotspots. * Low-level Work shop hotspots.
*/ */
REPAIR(15448, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.REPAIR_BENCH, Decoration.WHETSTONE, Decoration.ARMOUR_STAND), REPAIR(15448, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.REPAIR_BENCH, Decoration.WHETSTONE, Decoration.ARMOUR_STAND),
WORKBENCH(15439, BuildHotspotType.LINKED, BuildingUtils.BUILD_MID_ANIM, Decoration.WORKBENCH_WOODEN, Decoration.WORKBENCH_OAK,Decoration.WORKBENCH_STEEL_FRAME, Decoration.WORKBENCH_WITH_VICE, Decoration.WORKBENCH_WITH_LATHE), WORKBENCH(15439, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.WORKBENCH_WOODEN, Decoration.WORKBENCH_OAK,Decoration.WORKBENCH_STEEL_FRAME, Decoration.WORKBENCH_WITH_VICE,Decoration.WORKBENCH_WITH_LATHE),
CRAFTING(15441, BuildHotspotType.LINKED, BuildingUtils.BUILD_MID_ANIM, Decoration.CRAFTING_TABLE_1, Decoration.CRAFTING_TABLE_2,Decoration.CRAFTING_TABLE_3, Decoration.CRAFTING_TABLE_4), CRAFTING(15441, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.CRAFTING_TABLE_1, Decoration.CRAFTING_TABLE_2,Decoration.CRAFTING_TABLE_3, Decoration.CRAFTING_TABLE_4),
TOOL1(15443, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_HIGH_ANIM, Decoration.TOOL_STORE_1, Decoration.TOOL_STORE_2, Decoration.TOOL_STORE_3, Decoration.TOOL_STORE_4, Decoration.TOOL_STORE_5), TOOL1(15443, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_HIGH_ANIM, Decoration.TOOL_STORE_1, Decoration.TOOL_STORE_2, Decoration.TOOL_STORE_3, Decoration.TOOL_STORE_4, Decoration.TOOL_STORE_5),
TOOL2(15444, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_HIGH_ANIM, Decoration.TOOL_STORE_1, Decoration.TOOL_STORE_2,Decoration.TOOL_STORE_3, Decoration.TOOL_STORE_4,Decoration.TOOL_STORE_5), TOOL2(15444, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_HIGH_ANIM, Decoration.TOOL_STORE_1, Decoration.TOOL_STORE_2,Decoration.TOOL_STORE_3, Decoration.TOOL_STORE_4,Decoration.TOOL_STORE_5),
TOOL3(15445, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_HIGH_ANIM, Decoration.TOOL_STORE_1, Decoration.TOOL_STORE_2,Decoration.TOOL_STORE_3, Decoration.TOOL_STORE_4,Decoration.TOOL_STORE_5), TOOL3(15445, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_HIGH_ANIM, Decoration.TOOL_STORE_1, Decoration.TOOL_STORE_2,Decoration.TOOL_STORE_3, Decoration.TOOL_STORE_4,Decoration.TOOL_STORE_5),
TOOL4(15446, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_HIGH_ANIM, Decoration.TOOL_STORE_1, Decoration.TOOL_STORE_2,Decoration.TOOL_STORE_3, Decoration.TOOL_STORE_4,Decoration.TOOL_STORE_5), TOOL4(15446, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_HIGH_ANIM, Decoration.TOOL_STORE_1, Decoration.TOOL_STORE_2,Decoration.TOOL_STORE_3, Decoration.TOOL_STORE_4,Decoration.TOOL_STORE_5),
TOOL5(15447, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_HIGH_ANIM, Decoration.TOOL_STORE_1, Decoration.TOOL_STORE_2,Decoration.TOOL_STORE_3, Decoration.TOOL_STORE_4,Decoration.TOOL_STORE_5), TOOL5(15447, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_HIGH_ANIM, Decoration.TOOL_STORE_1, Decoration.TOOL_STORE_2,Decoration.TOOL_STORE_3, Decoration.TOOL_STORE_4,Decoration.TOOL_STORE_5),
HERALDRY(15450, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.PLUMING_STAND, Decoration.SHIELD_EASEL,Decoration.BANNER_EASEL), HERALDRY(15450, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.PLUMING_STAND, Decoration.SHIELD_EASEL,Decoration.BANNER_EASEL),
WORKBENCH_STOOL(15440, BuildHotspotType.LINKED, BuildingUtils.BUILD_MID_ANIM, Decoration.WORKSHOP_STOOL, Decoration.WORKSHOP_STOOL,Decoration.WORKSHOP_STOOL_OAK, Decoration.WORKSHOP_STOOL_OAK,Decoration.WORKSHOP_STOOL_OAK),
CRAFTING_STOOL(15442, BuildHotspotType.LINKED, BuildingUtils.BUILD_MID_ANIM, Decoration.WORKSHOP_STOOL, Decoration.WORKSHOP_STOOL,Decoration.WORKSHOP_STOOL, Decoration.WORKSHOP_STOOL),
/** /**
* Bedroom hotspots. * Bedroom hotspots.
@ -388,8 +386,6 @@ public enum BuildHotspot {
linkedHotspots.add(new BuildHotspot[] { DUNGEON_DOOR_LEFT2, DUNGEON_DOOR_RIGHT2 }); linkedHotspots.add(new BuildHotspot[] { DUNGEON_DOOR_LEFT2, DUNGEON_DOOR_RIGHT2 });
linkedHotspots.add(new BuildHotspot[] { SMALL_PLANT_1, SMALL_PLANT1 }); linkedHotspots.add(new BuildHotspot[] { SMALL_PLANT_1, SMALL_PLANT1 });
linkedHotspots.add(new BuildHotspot[] { SHELVES, SHELVES_2 }); linkedHotspots.add(new BuildHotspot[] { SHELVES, SHELVES_2 });
linkedHotspots.add(new BuildHotspot[] { WORKBENCH, WORKBENCH_STOOL });
linkedHotspots.add(new BuildHotspot[] { CRAFTING, CRAFTING_STOOL });
} }
/** /**

View file

@ -9,15 +9,13 @@ import core.game.interaction.OptionHandler;
import core.game.node.Node; import core.game.node.Node;
import core.game.node.entity.player.Player; import core.game.node.entity.player.Player;
import core.game.node.scenery.Scenery; import core.game.node.scenery.Scenery;
import core.game.world.map.Location;
import core.game.world.map.RegionManager;
import core.plugin.Initializable; import core.plugin.Initializable;
import core.plugin.Plugin; import core.plugin.Plugin;
import core.tools.Log; import core.tools.Log;
import core.tools.SystemLogger;
import core.plugin.ClassScanner; import core.plugin.ClassScanner;
import static core.api.ContentAPIKt.log; import static core.api.ContentAPIKt.log;
import static core.api.ContentAPIKt.setAttribute;
/** /**
* The build option handling plugin. * The build option handling plugin.
@ -50,7 +48,7 @@ public final class BuildOptionPlugin extends OptionHandler {
player.getDialogueInterpreter().open("con:removedec", object); player.getDialogueInterpreter().open("con:removedec", object);
return true; return true;
} }
setAttribute(player, ConstructionInterface.ATTRIBUTE_HOTSPOT_OBJ, node); player.setAttribute("con:hsobject", node);
if (BuildingUtils.isDoorHotspot(object)) { if (BuildingUtils.isDoorHotspot(object)) {
int[] pos = BuildingUtils.roomExists(player, object); int[] pos = BuildingUtils.roomExists(player, object);
if (pos != null) { if (pos != null) {
@ -73,30 +71,8 @@ public final class BuildOptionPlugin extends OptionHandler {
return true; return true;
} }
BuildHotspot buildHotspot = hotspot.getHotspot(); player.setAttribute("con:hotspot", hotspot);
BuildHotspot[] linked = BuildHotspot.getLinkedHotspots(buildHotspot); BuildingUtils.openBuildInterface(player, hotspot.getHotspot());
if (linked != null && linked[0] != buildHotspot) {
Location locObj = object.getLocation();
Room room = player.getHouseManager().getRoom(locObj);
if (room == null) return true;
for (Hotspot h : room.getHotspots()) {
if (h.getHotspot() == linked[0]) {
int dx = h.getCurrentX() - locObj.getChunkOffsetX();
int dy = h.getCurrentY() - locObj.getChunkOffsetY();
Scenery primaryObj = RegionManager.getObject(locObj.transform(dx, dy, 0));
if (primaryObj != null) {
setAttribute(player, ConstructionInterface.ATTRIBUTE_HOTSPOT_OBJ, primaryObj);
setAttribute(player, ConstructionInterface.ATTRIBUTE_HOTSPOT, h);
BuildingUtils.openBuildInterface(player, linked[0]);
}
return true;
}
}
return true;
}
setAttribute(player, ConstructionInterface.ATTRIBUTE_HOTSPOT, hotspot);
BuildingUtils.openBuildInterface(player, buildHotspot);
return true; return true;
} }

View file

@ -1,5 +1,6 @@
package content.global.skill.construction; package content.global.skill.construction;
import core.game.node.entity.player.Player; import core.game.node.entity.player.Player;
import core.game.node.item.Item; import core.game.node.item.Item;
import core.game.node.scenery.Scenery; import core.game.node.scenery.Scenery;
@ -17,9 +18,6 @@ import java.awt.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static core.api.ContentAPIKt.getAttribute;
import static core.game.world.map.RegionChunk.getRotatedPosition;
/** /**
* Handles the building a room dialogue. * Handles the building a room dialogue.
* @author Emperor * @author Emperor
@ -27,6 +25,7 @@ import static core.game.world.map.RegionChunk.getRotatedPosition;
*/ */
@Initializable @Initializable
public final class BuildRoomDialogue extends DialoguePlugin { public final class BuildRoomDialogue extends DialoguePlugin {
/** /**
* The door hotspot. * The door hotspot.
*/ */
@ -50,7 +49,7 @@ public final class BuildRoomDialogue extends DialoguePlugin {
/** /**
* The boundaries of the room to build. * The boundaries of the room to build.
*/ */
private final List<Scenery> boundaries = new ArrayList<>(20); private List<Scenery> boundaries = new ArrayList<>(20);
/** /**
* The room we're building. * The room we're building.
@ -106,7 +105,7 @@ public final class BuildRoomDialogue extends DialoguePlugin {
stage = 2; stage = 2;
return true; return true;
} }
this.door = getAttribute(player, ConstructionInterface.ATTRIBUTE_HOTSPOT_OBJ, null); this.door = (Scenery) player.getAttribute("con:hsobject");
int[] pos = BuildingUtils.getRoomPosition(player, door); int[] pos = BuildingUtils.getRoomPosition(player, door);
roomX = pos[0]; roomX = pos[0];
roomY = pos[1]; roomY = pos[1];
@ -240,18 +239,15 @@ public final class BuildRoomDialogue extends DialoguePlugin {
for (Scenery object : boundaries) { for (Scenery object : boundaries) {
SceneryBuilder.remove(object); SceneryBuilder.remove(object);
} }
boundaries.clear();
int rotation = directions[index].toInteger(); int rotation = directions[index].toInteger();
Location base = player.getLocation().getRegion().getBaseLocation().transform(roomX << 3, roomY << 3, player.getLocation().getZ()); boundaries.clear();
for (int x = 0; x < RegionChunk.SIZE; x++) { Location base = player.getViewport().getRegion().getBaseLocation().transform(roomX << 3, roomY << 3, player.getLocation().getZ());
for (int y = 0; y < RegionChunk.SIZE; y++) { for (int x = 0; x < 8; x++) {
for (int i = 0; i < RegionChunk.ARRAY_SIZE; i++) { for (int y = 0; y < 8; y++) {
Scenery object = room.getChunk().getObjects(x, y)[i]; Scenery[] objects = room.getChunk().getObjects(x, y);
for (Scenery object : objects) {
if (object != null && object.getDefinition().hasAction("build")) { if (object != null && object.getDefinition().hasAction("build")) {
if (object.getLayer() == Scenery.Layer.WALL && !BuildingUtils.isDoorHotspot(object)) { int[] pos = RegionChunk.getRotatedPosition(x, y, object.getDefinition().getSizeX(), object.getDefinition().getSizeY(), object.getRotation(), rotation);
continue;
}
int[] pos = getRotatedPosition(x, y, object.getDefinition().getSizeX(), object.getDefinition().getSizeY(), object.getRotation(), rotation);
Scenery obj = object.transform(object.getId(), (object.getRotation() + rotation) % 4, base.transform(pos[0], pos[1], 0)); Scenery obj = object.transform(object.getId(), (object.getRotation() + rotation) % 4, base.transform(pos[0], pos[1], 0));
boundaries.add(SceneryBuilder.add(obj)); boundaries.add(SceneryBuilder.add(obj));
} }

View file

@ -8,7 +8,10 @@ import core.game.node.item.Item;
import core.game.node.scenery.Scenery; import core.game.node.scenery.Scenery;
import core.game.node.scenery.SceneryBuilder; import core.game.node.scenery.SceneryBuilder;
import core.game.system.task.Pulse; import core.game.system.task.Pulse;
import core.game.world.map.*; import core.game.world.map.BuildRegionChunk;
import core.game.world.map.Direction;
import core.game.world.map.Location;
import core.game.world.map.Region;
import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Animation;
import core.net.packet.PacketRepository; import core.net.packet.PacketRepository;
import core.net.packet.context.ContainerContext; import core.net.packet.context.ContainerContext;
@ -136,13 +139,9 @@ public final class BuildingUtils {
* @param object The object. * @param object The object.
*/ */
public static void buildDecoration(final Player player, final Hotspot hotspot, final Decoration deco, final Scenery object) { public static void buildDecoration(final Player player, final Hotspot hotspot, final Decoration deco, final Scenery object) {
buildDecoration(player, hotspot, deco, object, false, false);
}
public static void buildDecoration(final Player player, final Hotspot hotspot, final Decoration deco, final Scenery object, final boolean bypassCost, final boolean bypassXp) {
final int nailAmount = deco.getNailAmount(); final int nailAmount = deco.getNailAmount();
final NailType type = nailAmount > 0 ? NailType.get(player, nailAmount) : null; final NailType type = nailAmount > 0 ? NailType.get(player, nailAmount) : null;
if (nailAmount > 0 && type == null && !bypassCost) { if (nailAmount > 0 && type == null) {
player.getPacketDispatch().sendMessage("You don't have the right materials."); player.getPacketDispatch().sendMessage("You don't have the right materials.");
return; return;
} }
@ -166,7 +165,7 @@ public final class BuildingUtils {
NailType nail = type; NailType nail = type;
@Override @Override
public boolean pulse() { public boolean pulse() {
if (nails > 0 && !bypassCost) { if (nails > 0) {
if (!type.isBend()) { if (!type.isBend()) {
player.getPacketDispatch().sendMessage("You use a nail."); player.getPacketDispatch().sendMessage("You use a nail.");
nails--; nails--;
@ -190,15 +189,13 @@ public final class BuildingUtils {
} }
} }
} }
if (bypassCost || player.isAdmin() || player.getInventory().remove(deco.getItems())) { if (player.getInventory().remove(deco.getItems()) || player.isAdmin()) {
setDecoration(player, r, room, hotspot, object, deco); setDecoration(player, r, room, hotspot, object, deco);
if (!bypassXp) {
player.getSkills().addExperience(Skills.CONSTRUCTION, deco.getExperience(), true); player.getSkills().addExperience(Skills.CONSTRUCTION, deco.getExperience(), true);
if (getObjectIdsThatGiveFarmingExperience().contains(deco.getObjectId())) { if (getObjectIdsThatGiveFarmingExperience().contains(deco.getObjectId())) {
player.getSkills().addExperience(Skills.FARMING, deco.getExperience(), true); player.getSkills().addExperience(Skills.FARMING, deco.getExperience(), true);
} }
}
player.unlock(); player.unlock();
} }
return true; return true;
@ -253,7 +250,7 @@ public final class BuildingUtils {
if (reg == null) { if (reg == null) {
continue; continue;
} }
RegionChunk chunk = reg.getChunks()[l.getChunkX()][l.getChunkY()][plane % 3]; BuildRegionChunk chunk = (BuildRegionChunk) reg.getPlanes()[plane % 3].getChunks()[l.getChunkX()][l.getChunkY()];
Scenery[] objects = chunk.getObjects(h.getCurrentX(), h.getCurrentY()); Scenery[] objects = chunk.getObjects(h.getCurrentX(), h.getCurrentY());
for (Scenery o : objects) { for (Scenery o : objects) {
if (o != null && o.getType() == object.getType()) { if (o != null && o.getType() == object.getType()) {
@ -287,27 +284,24 @@ public final class BuildingUtils {
hotspot.setDecorationIndex(decIndex); hotspot.setDecorationIndex(decIndex);
break; break;
case RECURSIVE: case RECURSIVE:
RegionChunk chunk = region.getChunks()[l.getChunkX()][l.getChunkY()][l.getZ()]; BuildRegionChunk chunk = (BuildRegionChunk) region.getPlanes()[l.getZ()].getChunks()[l.getChunkX()][l.getChunkY()];
for (int x = 0; x < 8; x++) { for (int x = 0; x < 8; x++) {
for (int y = 0; y < 8; y++) { for (int y = 0; y < 8; y++) {
Hotspot h = room.getHotspot(hotspot.getHotspot(), x, y); Hotspot h = room.getHotspot(hotspot.getHotspot(), x, y);
if (h != null) { if (h != null) {
h.setDecorationIndex(decIndex); h.setDecorationIndex(decIndex);
int objectId = hotspot.getHotspot().getObjectId(style); int objectId = hotspot.getHotspot().getObjectId(style);
int index = chunk.getIndex(x, y, objectId, -1); Scenery o = chunk.get(x, y, chunk.getIndex(x, y, objectId));
if (index != -1) { if (o != null && objectId == o.getId()) {
Scenery o = chunk.getObjects()[x][y][index];
if (objectId == o.getId()) {
SceneryBuilder.replace(o, o.transform(hotspot.getHotspot().getDecorations()[decIndex].getObjectId(style))); SceneryBuilder.replace(o, o.transform(hotspot.getHotspot().getDecorations()[decIndex].getObjectId(style)));
} }
} }
} }
} }
}
break; break;
case LINKED: case LINKED:
BuildHotspot[] linkedHotspots = BuildHotspot.getLinkedHotspots(hotspot.getHotspot()); BuildHotspot[] linkedHotspots = BuildHotspot.getLinkedHotspots(hotspot.getHotspot());
chunk = region.getChunks()[l.getChunkX()][l.getChunkY()][l.getZ()]; chunk = (BuildRegionChunk) region.getPlanes()[l.getZ()].getChunks()[l.getChunkX()][l.getChunkY()];
for (int x = 0; x < 8; x++) { for (int x = 0; x < 8; x++) {
for (int y = 0; y < 8; y++) { for (int y = 0; y < 8; y++) {
for (BuildHotspot bh : linkedHotspots) { for (BuildHotspot bh : linkedHotspots) {
@ -315,17 +309,14 @@ public final class BuildingUtils {
if (h != null) { if (h != null) {
h.setDecorationIndex(decIndex); h.setDecorationIndex(decIndex);
int objectId = bh.getObjectId(style); int objectId = bh.getObjectId(style);
int index = chunk.getIndex(x, y, objectId, -1); Scenery o = chunk.get(x, y, chunk.getIndex(x, y, objectId));
if (index != -1) { if (o != null && objectId == o.getId()) {
Scenery o = chunk.getObjects()[x][y][index];
if (objectId == o.getId()) {
SceneryBuilder.replace(o, o.transform(bh.getDecorations()[decIndex].getObjectId(style))); SceneryBuilder.replace(o, o.transform(bh.getDecorations()[decIndex].getObjectId(style)));
} }
} }
} }
} }
} }
}
break; break;
} }
} }
@ -394,7 +385,7 @@ public final class BuildingUtils {
if (reg == null) { if (reg == null) {
continue; continue;
} }
RegionChunk chunk = reg.getChunks()[l.getChunkX()][l.getChunkY()][plane % 3]; BuildRegionChunk chunk = (BuildRegionChunk) reg.getPlanes()[plane % 3].getChunks()[l.getChunkX()][l.getChunkY()];
Scenery[] objects = chunk.getObjects(h.getCurrentX(), h.getCurrentY()); Scenery[] objects = chunk.getObjects(h.getCurrentX(), h.getCurrentY());
for (Scenery o : objects) { for (Scenery o : objects) {
if (o != null && o.getType() == object.getType()) { if (o != null && o.getType() == object.getType()) {
@ -426,18 +417,14 @@ public final class BuildingUtils {
hotspot.setDecorationIndex(-1); hotspot.setDecorationIndex(-1);
break; break;
case RECURSIVE: case RECURSIVE:
RegionChunk chunk = region.getChunks()[l.getChunkX()][l.getChunkY()][l.getZ()]; BuildRegionChunk chunk = (BuildRegionChunk) region.getPlanes()[l.getZ()].getChunks()[l.getChunkX()][l.getChunkY()];
for (int x = 0; x < 8; x++) { for (int x = 0; x < 8; x++) {
for (int y = 0; y < 8; y++) { for (int y = 0; y < 8; y++) {
Hotspot h = room.getHotspot(hotspot.getHotspot(), x, y); Hotspot h = room.getHotspot(hotspot.getHotspot(), x, y);
if (h != null) { if (h != null) {
int objectId = hotspot.getHotspot().getDecorations()[h.getDecorationIndex()].getObjectId(style); int objectId = hotspot.getHotspot().getDecorations()[h.getDecorationIndex()].getObjectId(style);
int index = chunk.getIndex(x, y, objectId, -1); Scenery o = chunk.get(x, y, chunk.getIndex(x, y, objectId));
h.setDecorationIndex(-1); h.setDecorationIndex(-1);
if (index == -1) {
continue;
}
Scenery o = chunk.getObjects()[x][y][index];
if (o != null && objectId == o.getId()) { if (o != null && objectId == o.getId()) {
SceneryBuilder.replace(o, o.transform(hotspot.getHotspot().getObjectId(style))); SceneryBuilder.replace(o, o.transform(hotspot.getHotspot().getObjectId(style)));
} }
@ -447,19 +434,15 @@ public final class BuildingUtils {
break; break;
case LINKED: case LINKED:
BuildHotspot[] linkedHotspots = BuildHotspot.getLinkedHotspots(hotspot.getHotspot()); BuildHotspot[] linkedHotspots = BuildHotspot.getLinkedHotspots(hotspot.getHotspot());
chunk = region.getChunks()[l.getChunkX()][l.getChunkY()][l.getZ()]; chunk = (BuildRegionChunk) region.getPlanes()[l.getZ()].getChunks()[l.getChunkX()][l.getChunkY()];
for (int x = 0; x < 8; x++) { for (int x = 0; x < 8; x++) {
for (int y = 0; y < 8; y++) { for (int y = 0; y < 8; y++) {
for (BuildHotspot bh : linkedHotspots) { for (BuildHotspot bh : linkedHotspots) {
Hotspot h = room.getHotspot(bh, x, y); Hotspot h = room.getHotspot(bh, x, y);
if (h != null && h.getDecorationIndex() >= 0) { if (h != null) {
int objectId = bh.getDecorations()[h.getDecorationIndex()].getObjectId(style); int objectId = bh.getDecorations()[h.getDecorationIndex()].getObjectId(style);
Scenery o = chunk.get(x, y, chunk.getIndex(x, y, objectId));
h.setDecorationIndex(-1); h.setDecorationIndex(-1);
int index = chunk.getIndex(x, y, objectId, -1);
if (index == -1) {
continue;
}
Scenery o = chunk.getObjects()[x][y][index];
if (o != null && objectId == o.getId()) { if (o != null && objectId == o.getId()) {
SceneryBuilder.replace(o, o.transform(bh.getObjectId(style))); SceneryBuilder.replace(o, o.transform(bh.getObjectId(style)));
} }

View file

@ -0,0 +1,120 @@
package content.global.skill.construction;
import core.cache.def.impl.ItemDefinition;
import core.game.component.Component;
import core.game.component.ComponentDefinition;
import core.game.component.ComponentPlugin;
import core.game.node.entity.player.Player;
import core.game.node.entity.skill.Skills;
import core.game.node.scenery.Scenery;
import core.plugin.Initializable;
import core.plugin.Plugin;
import core.tools.Log;
import core.tools.SystemLogger;
import static core.api.ContentAPIKt.log;
/**
* Handles the creating of a decoration object.
* @author Emperor
*
*/
@Initializable
public final class ConstructionInterface extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) {
ComponentDefinition.put(396, this);
ComponentDefinition.put(398, this);
ComponentDefinition.put(402, this);
return this;
}
@Override
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
switch (component.getId()) {
case 396:
switch (button) {
case 132:
player.getInterfaceManager().close();
Hotspot hotspot = player.getAttribute("con:hotspot");
Scenery object = player.getAttribute("con:hsobject");
if (hotspot == null || object == null) {
log(this.getClass(), Log.ERR, "Failed building decoration " + hotspot + " : " + object);
break;
}
slot = ((slot % 2 != 0) ? 4 : 0) + (slot >> 1);
if (slot >= hotspot.getHotspot().getDecorations().length) {
log(this.getClass(), Log.ERR, "Failed building decoration " + slot + "/" + hotspot.getHotspot().getDecorations().length);
break;
}
boolean debug = player.isStaff();
Decoration deco = hotspot.getHotspot().getDecorations()[slot];
if (!debug) {
if (player.getSkills().getLevel(Skills.CONSTRUCTION) < deco.getLevel()) {
player.sendMessage("You need to have a Construction level of " + deco.getLevel() + " to build that.");
return true;
}
if (!player.getInventory().containsItems(deco.getItems())) {
player.sendMessage("You don't have the right materials.");
return true;
}
for (int tool : deco.getTools()) {
if (tool == BuildingUtils.WATERING_CAN) {
boolean hasWateringCan = false;
for (int i = 0; i < 8; i++) {
if (player.getInventory().contains(tool - i, 1)) {
hasWateringCan = true;
break;
}
}
if (!hasWateringCan) {
player.sendMessage("You need a watering can to plant this.");
return true;
}
continue;
}
if (!player.getInventory().contains(tool, 1)) {
player.sendMessage("You need a " + ItemDefinition.forId(tool).getName() + " to build this.");
return true;
}
}
}
BuildingUtils.buildDecoration(player, hotspot, deco, object);
return true;
}
break;
case 398:
switch (button) {
case 14:
player.getHouseManager().toggleBuildingMode(player, true);
return true;
case 1:
player.getHouseManager().toggleBuildingMode(player, false);
return true;
case 15:
player.getHouseManager().expelGuests(player);
return true;
case 13:
if (!player.getHouseManager().isInHouse(player)) {
player.sendMessage("You can't do this outside of your house.");
return true;
}
HouseManager.leave(player);
return true;
}
break;
case 402:
int index = button - 160;
log(this.getClass(), Log.FINE, "BuildRoom Interface Index: " + index);
if (index > -1 && index < RoomProperties.values().length) {
player.getDialogueInterpreter().open("con:room", RoomProperties.values()[index]);
return true;
}
break;
}
return false;
}
}

View file

@ -1,159 +0,0 @@
package content.global.skill.construction
import content.global.skill.construction.decoration.workshop.WorkbenchListeners
import core.api.*
import core.cache.def.impl.ItemDefinition
import core.game.interaction.InterfaceListener
import core.game.node.entity.skill.Skills
import core.game.node.scenery.Scenery
import core.tools.Log
import org.rs09.consts.Components
import org.rs09.consts.Scenery as SceneryObj
/**
* Handles three interfaces related to the Construction skill, namely those which allow a player to build decorations,
* toggle building mode/expel guests, and select a room to add to the POH.
* @author Bishop
*/
class ConstructionInterface : InterfaceListener {
companion object {
const val ATTRIBUTE_HOTSPOT = "con:hotspot"
const val ATTRIBUTE_HOTSPOT_OBJ = "con:hsobject"
private const val DECO_BUTTON_BUILD = 132
private const val HOUSE_BUTTON_BUILDMODE_ON = 14
private const val HOUSE_BUTTON_BUILDMODE_OFF = 1
private const val HOUSE_BUTTON_EXPEL_GUESTS = 15
private const val HOUSE_BUTTON_LEAVE_HOUSE = 13
// Register furniture here when it is only obtainable by upgrading, to send the correct rejection message.
private val upgradeOnly = arrayOf(
Decoration.WORKBENCH_WITH_VICE,
Decoration.WORKBENCH_WITH_LATHE,
)
}
override fun defineInterfaceListeners() {
/**
* Handles the interface for selecting a decoration to build.
*/
on(Components.POH_DECORATION_396) { player, _, _, buttonID, slot, _ ->
when (buttonID) {
DECO_BUTTON_BUILD -> {
val hotspot = getAttribute<Hotspot?>(player, ATTRIBUTE_HOTSPOT, null)
val hotspotObj = getAttribute<Scenery?>(player, ATTRIBUTE_HOTSPOT_OBJ, null)
val flatpackMode = getAttribute(player, WorkbenchListeners.ATTRIBUTE_FLATPACK_MODE, false)
if (!flatpackMode) {
closeInterface(player)
}
if ((hotspot == null || hotspotObj == null) && !flatpackMode) {
log(this.javaClass, Log.ERR, "Failed building decoration $hotspot : $hotspotObj")
return@on false
}
// Translates slot data to index data, as slots are not in order of level requirement in the interface, but decoration data is organized that way
val decoIndex = (if (slot % 2 != 0) 4 else 0) + (slot shr 1)
val buildHotspot = if (flatpackMode) {
getAttribute<BuildHotspot?>(player, WorkbenchListeners.ATTRIBUTE_WORKBENCH_SELECTION, null)?: return@on false
} else {
hotspot!!.hotspot
}
if (decoIndex >= buildHotspot.decorations.size) {
return@on false
}
val deco = buildHotspot.decorations[decoIndex]
if (!player.isAdmin) {
if (getDynLevel(player, Skills.CONSTRUCTION) < deco.level) {
closeInterface(player)
sendMessage(player, "You need to have a Construction level of ${deco.level} to build that.")
return@on true
}
if (deco in upgradeOnly) {
closeInterface(player)
sendMessage(player, "That can only be built by upgrading the previous piece of furniture.")
return@on true
}
if (!player.inventory.containsItems(*deco.items)) { // No clean ContentAPI substitute for this
closeInterface(player)
sendMessage(player, "You don't have the right materials.")
return@on true
}
for (tool in deco.tools) {
if (tool == BuildingUtils.WATERING_CAN) {
var hasWaterInCan = false
for (i in 0..8) {
if (inInventory(player, tool - i)) {
hasWaterInCan = true
break
}
}
if (!hasWaterInCan) {
sendMessage(player, "You need a watering can to plant this.")
return@on true
}
continue
}
if (!inInventory(player, tool)) {
closeInterface(player)
sendMessage(player, "You need a ${ItemDefinition.forId(tool).name} to build this.")
return@on true
}
}
if (flatpackMode && WorkbenchListeners.getBenchLevel(getAttribute(player, WorkbenchListeners.ATTRIBUTE_WORKBENCH_ID, SceneryObj.WORKBENCH_13704)) < deco.level) {
closeInterface(player)
sendMessage(player, "You cannot make this with this workbench.") // TODO: Find authentic text
return@on true
}
}
if (flatpackMode) {
WorkbenchListeners.produceFlatpack(player, deco)
} else {
BuildingUtils.buildDecoration(player, hotspot, deco, hotspotObj)
}
return@on true
}
else -> return@on false
}
}
/**
* Handles the interface for managing building mode and POH guests.
*/
on(Components.POH_HOUSE_OPTIONS_398) { player, _, _, buttonID, _, _ ->
when (buttonID) {
HOUSE_BUTTON_BUILDMODE_ON -> {
player.houseManager.toggleBuildingMode(player, true)
return@on true
}
HOUSE_BUTTON_BUILDMODE_OFF -> {
player.houseManager.toggleBuildingMode(player, false)
return@on true
}
HOUSE_BUTTON_EXPEL_GUESTS -> {
player.houseManager.expelGuests(player)
return@on true
}
HOUSE_BUTTON_LEAVE_HOUSE -> {
if (!player.houseManager.isInHouse(player)) {
sendMessage(player, "You can't do this outside of your house.")
return@on true
}
HouseManager.leave(player)
return@on true
}
else -> return@on false
}
}
/**
* Handles the interface for selecting a new room to add to a POH.
*/
on(Components.POH_ROOMS_402) { player, _, _, buttonID, _, _ ->
val index = buttonID - 160
if (index > -1 && index < RoomProperties.values().size) {
player.dialogueInterpreter.open("con:room", RoomProperties.values()[index]) // ContentAPI impl won't work for this
}
return@on true
}
}
}

View file

@ -74,13 +74,13 @@ public enum Decoration {
/** /**
* Parlour chair spot * Parlour chair spot
*/ */
CRUDE_CHAIR (13581, 8309, 1, 58, new Item[] { new Item(Items.PLANK_960, 2) }, Items.CRUDE_WOODEN_CHAIR_8496), CRUDE_CHAIR (13581, 8309, 1, 58, new Item[] { new Item(Items.PLANK_960, 2) }),
WOODEN_CHAIR (13582, 8310, 8, 87, new Item[] { new Item(Items.PLANK_960, 3) }, Items.WOODEN_CHAIR_8498), WOODEN_CHAIR (13582, 8310, 8, 87, new Item[] { new Item(Items.PLANK_960, 3) }),
ROCKING_CHAIR (13583, 8311, 14, 87, new Item[] { new Item(Items.PLANK_960, 3) }, Items.ROCKING_CHAIR_8500), ROCKING_CHAIR (13583, 8311, 14, 87, new Item[] { new Item(Items.PLANK_960, 3) }),
OAK_CHAIR (13584, 8312, 19, 120, new Item[] { new Item(Items.OAK_PLANK_8778, 2) }, Items.OAK_CHAIR_8502), OAK_CHAIR (13584, 8312, 19, 120, new Item[] { new Item(Items.OAK_PLANK_8778, 2) }),
OAK_ARMCHAIR (13585, 8313, 26, 180, new Item[] { new Item(Items.OAK_PLANK_8778, 3) }, Items.OAK_ARMCHAIR_8504), OAK_ARMCHAIR (13585, 8313, 26, 180, new Item[] { new Item(Items.OAK_PLANK_8778, 3) }),
TEAK_ARMCHAIR (13586, 8314, 35, 180, new Item[] { new Item(Items.TEAK_PLANK_8780, 2) }, Items.TEAK_ARMCHAIR_8506), TEAK_ARMCHAIR (13586, 8314, 35, 180, new Item[] { new Item(Items.TEAK_PLANK_8780, 2) }),
MAHOGANY_ARMCHAIR(13587, 8315, 50, 280, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2) }, Items.MAHOGANY_ARMCHAIR_8508), MAHOGANY_ARMCHAIR(13587, 8315, 50, 280, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2) }),
/** /**
* Rugs rugs rugs * Rugs rugs rugs
@ -112,26 +112,29 @@ public enum Decoration {
/** /**
* Bookcases * Bookcases
*/ */
WOODEN_BOOKCASE (13597, 8319, 4, 115, new Item[] { new Item(Items.PLANK_960, 4) }, Items.WOODEN_BOOKCASE_8510), WOODEN_BOOKCASE (13597, 8319, 4, 115, new Item[] { new Item(Items.PLANK_960, 4) }),
OAK_BOOKCASE (13598, 8320, 29, 180, new Item[] { new Item(Items.OAK_PLANK_8778, 3) }, Items.OAK_BOOKCASE_8512), OAK_BOOKCASE (13598, 8320, 29, 180, new Item[] { new Item(Items.OAK_PLANK_8778, 3) }),
MAHOGANY_BOOKCASE(13599, 8321, 40, 420, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 3) }, Items.MAHOGANY_BKCASE_8514), MAHOGANY_BOOKCASE(13599, 8321, 40, 420, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 3) }),
/** /**
* Kitchen Beer Barrels * Kitchen Beer Barrels
* TODO: These also require cooking levels!
* Basic: 1, Cider: 14, Asgarnian: 24, Greenman's: 29, D.Bitter: 39, Chef's: 54
*
*/ */
BASIC_BEER_BARREL (13568, 8239, 7, 87, new Item[] { new Item(Items.PLANK_960, 3) }, Items.BEER_BARREL_8516), BASIC_BEER_BARREL (13568, 8239, 7, 87, new Item[] { new Item(Items.PLANK_960, 3) }),
CIDER_BARREL (13569, 8240, 12, 91, new Item[] { new Item(Items.PLANK_960, 3), new Item(Items.CIDER_5763, 8) }, Items.CIDER_BARREL_8518), CIDER_BARREL (13569, 8240, 12, 91, new Item[] { new Item(Items.PLANK_960, 3), new Item(Items.CIDER_5763, 8) }),
ASGARNIAN_ALE_BARREL(13570, 8241, 18, 184, new Item[] { new Item(Items.OAK_PLANK_8778, 3), new Item(Items.ASGARNIAN_ALE_1905, 8) }, Items.ASGARNIAN_ALE_8520), ASGARNIAN_ALE_BARREL(13570, 8241, 18, 184, new Item[] { new Item(Items.OAK_PLANK_8778, 3), new Item(Items.ASGARNIAN_ALE_1905, 8) }),
GREENMANS_ALE_BARREL(13571, 8242, 26, 184, new Item[] { new Item(Items.OAK_PLANK_8778, 3), new Item(Items.GREENMANS_ALE_1909, 8) }, Items.GREENMANS_ALE_8522), GREENMANS_ALE_BARREL(13571, 8242, 26, 184, new Item[] { new Item(Items.OAK_PLANK_8778, 3), new Item(Items.GREENMANS_ALE_1909, 8) }),
DRAGON_BITTER_BARREL(13572, 8243, 36, 224, new Item[] { new Item(Items.OAK_PLANK_8778, 3), new Item(Items.DRAGON_BITTER_1911, 8), new Item(Items.STEEL_BAR_2353, 2) }, Items.DRAGON_BITTER_8524), DRAGON_BITTER_BARREL(13572, 8243, 36, 224, new Item[] { new Item(Items.OAK_PLANK_8778, 3), new Item(Items.DRAGON_BITTER_1911, 8), new Item(Items.STEEL_BAR_2353, 2) }),
CHEFS_DELIGHT_BARREL(13573, 8244, 48, 224, new Item[] { new Item(Items.OAK_PLANK_8778, 3), new Item(Items.CHEFS_DELIGHT_5755, 8), new Item(Items.STEEL_BAR_2353, 2) }, Items.CHEFS_DELIGHT_8526), CHEFS_DELIGHT_BARREL(13573, 8244, 48, 224, new Item[] { new Item(Items.OAK_PLANK_8778, 3), new Item(Items.CHEFS_DELIGHT_5755, 8), new Item(Items.STEEL_BAR_2353, 2) }),
/** /**
* Kitchen Tables! * Kitchen Tables!
*/ */
KITCHEN_WOODEN_TABLE(13577, 8246, 12, 87, new Item[] { new Item(Items.PLANK_960, 3) }, Items.WOOD_KITCHEN_TABLE_8528), KITCHEN_WOODEN_TABLE(13577, 8246, 12, 87, new Item[] { new Item(Items.PLANK_960, 3) }),
KITCHEN_OAK_TABLE (13578, 8247, 32, 180, new Item[] { new Item(Items.OAK_PLANK_8778, 3) }, Items.OAK_KITCHEN_TABLE_8530), KITCHEN_OAK_TABLE (13578, 8247, 32, 180, new Item[] { new Item(Items.OAK_PLANK_8778, 3) }),
KITCHEN_TEAK_TABLE (13579, 8248, 52, 270, new Item[] { new Item(Items.TEAK_PLANK_8780, 3) }, Items.TEAK_KITCHEN_TABLE_8532), KITCHEN_TEAK_TABLE (13579, 8248, 52, 270, new Item[] { new Item(Items.TEAK_PLANK_8780, 3) }),
/** /**
* Kitchen Stoves * Kitchen Stoves
@ -179,24 +182,24 @@ public enum Decoration {
/** /**
* Dining room tables * Dining room tables
*/ */
DINING_TABLE_WOOD (13293, 8246, 10, 115, new Item[] { new Item(Items.PLANK_960, 4) }, Items.WOOD_DINING_TABLE_8548), DINING_TABLE_WOOD (13293, 8246, 10, 115, new Item[] { new Item(Items.PLANK_960, 4) }),
DINING_TABLE_OAK (13294, 8247, 22, 240, new Item[] { new Item(Items.OAK_PLANK_8778, 4) }, Items.OAK_DINING_TABLE_8550), DINING_TABLE_OAK (13294, 8247, 22, 240, new Item[] { new Item(Items.OAK_PLANK_8778, 4) }),
DINING_TABLE_CARVED_OAK (13295, 8247, 31, 360, new Item[] { new Item(Items.OAK_PLANK_8778, 6) }, Items.CARVED_OAK_TABLE_8552), DINING_TABLE_CARVED_OAK (13295, 8247, 31, 360, new Item[] { new Item(Items.OAK_PLANK_8778, 6) }),
DINING_TABLE_TEAK (13296, 8248, 38, 360, new Item[] { new Item(Items.TEAK_PLANK_8780, 4) }, Items.TEAK_TABLE_8554), DINING_TABLE_TEAK (13296, 8248, 38, 360, new Item[] { new Item(Items.TEAK_PLANK_8780, 4) }),
DINING_TABLE_CARVED_TEAK(13297, 8248, 45, 600, new Item[] { new Item(Items.TEAK_PLANK_8780, 6), new Item(Items.BOLT_OF_CLOTH_8790, 4) }, Items.CARVED_TEAK_TABLE_8556), DINING_TABLE_CARVED_TEAK(13297, 8248, 45, 600, new Item[] { new Item(Items.TEAK_PLANK_8780, 6), new Item(Items.BOLT_OF_CLOTH_8790, 4) }),
DINING_TABLE_MAHOGANY (13298, 8120, 52, 840, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 6) }, Items.MAHOGANY_TABLE_8558), DINING_TABLE_MAHOGANY (13298, 8120, 52, 840, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 6) }),
DINING_TABLE_OPULENT (13299, 8121, 72, 3100, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 6), new Item(Items.BOLT_OF_CLOTH_8790, 4), new Item(Items.GOLD_LEAF_8784, 4), new Item(Items.MARBLE_BLOCK_8786, 2) }, Items.OPULENT_TABLE_8560), DINING_TABLE_OPULENT (13299, 8121, 72, 3100, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 6), new Item(Items.BOLT_OF_CLOTH_8790, 4), new Item(Items.GOLD_LEAF_8784, 4), new Item(Items.MARBLE_BLOCK_8786, 2) }),
/** /**
* Dining room benches * Dining room benches
*/ */
BENCH_WOODEN (13300, 8108, 10, 115, new Item[] { new Item(Items.PLANK_960, 4) }, Items.WOODEN_BENCH_8562), BENCH_WOODEN (13300, 8108, 10, 115, new Item[] { new Item(Items.PLANK_960, 4) }),
BENCH_OAK (13301, 8109, 22, 240, new Item[] { new Item(Items.OAK_PLANK_8778, 4) }, Items.OAK_BENCH_8564), BENCH_OAK (13301, 8109, 22, 240, new Item[] { new Item(Items.OAK_PLANK_8778, 4) }),
BENCH_CARVED_OAK (13302, 8110, 31, 240, new Item[] { new Item(Items.OAK_PLANK_8778, 4) }, Items.CARVED_OAK_BENCH_8566), BENCH_CARVED_OAK (13302, 8110, 31, 240, new Item[] { new Item(Items.OAK_PLANK_8778, 4) }),
BENCH_TEAK (13303, 8111, 38, 360, new Item[] { new Item(Items.TEAK_PLANK_8780, 4) }, Items.TEAK_DINING_BENCH_8568), BENCH_TEAK (13303, 8111, 38, 360, new Item[] { new Item(Items.TEAK_PLANK_8780, 4) }),
BENCH_CARVED_TEAK(13304, 8112, 44, 360, new Item[] { new Item(Items.TEAK_PLANK_8780, 4) }, Items.CARVED_TEAK_BENCH_8570), BENCH_CARVED_TEAK(13304, 8112, 44, 360, new Item[] { new Item(Items.TEAK_PLANK_8780, 4) }),
BENCH_MAHOGANY (13305, 8113, 52, 560, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 6) }, Items.MAHOGANY_BENCH_8572), BENCH_MAHOGANY (13305, 8113, 52, 560, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 6) }),
BENCH_GILDED (13306, 8114, 61, 1760, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 4), new Item(Items.GOLD_LEAF_8784, 4) }, Items.GILDED_BENCH_8574), BENCH_GILDED (13306, 8114, 61, 1760, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 4), new Item(Items.GOLD_LEAF_8784, 4) }),
/** /**
* Dining room bell-pulls * Dining room bell-pulls
@ -206,7 +209,7 @@ public enum Decoration {
FANCY_BELL_PULL(13309, 8101, 33, 58, new Item[] { new Item(Items.TEAK_PLANK_8780), new Item(Items.BOLT_OF_CLOTH_8790, 2), new Item(Items.GOLD_LEAF_8784) }), FANCY_BELL_PULL(13309, 8101, 33, 58, new Item[] { new Item(Items.TEAK_PLANK_8780), new Item(Items.BOLT_OF_CLOTH_8790, 2), new Item(Items.GOLD_LEAF_8784) }),
/** /**
* Workshop workbenches * Workshop workbench
*/ */
WORKBENCH_WOODEN (13704, 8375, 17, 143, new Item[] { new Item(Items.PLANK_960, 5) }), WORKBENCH_WOODEN (13704, 8375, 17, 143, new Item[] { new Item(Items.PLANK_960, 5) }),
WORKBENCH_OAK (13705, 8376, 32, 300, new Item[] { new Item(Items.OAK_PLANK_8778, 5) }), WORKBENCH_OAK (13705, 8376, 32, 300, new Item[] { new Item(Items.OAK_PLANK_8778, 5) }),
@ -214,12 +217,6 @@ public enum Decoration {
WORKBENCH_WITH_VICE (13707, 8378, 62, 750, new Item[] { new Item(Items.STEEL_FRAMED_BENCH_8377), new Item(Items.OAK_PLANK_8778, 2), new Item(Items.STEEL_BAR_2353) }), WORKBENCH_WITH_VICE (13707, 8378, 62, 750, new Item[] { new Item(Items.STEEL_FRAMED_BENCH_8377), new Item(Items.OAK_PLANK_8778, 2), new Item(Items.STEEL_BAR_2353) }),
WORKBENCH_WITH_LATHE (13708, 8379, 77, 1000, new Item[] { new Item(Items.OAK_WORKBENCH_8376), new Item(Items.OAK_PLANK_8778, 2), new Item(Items.STEEL_BAR_2353) }), WORKBENCH_WITH_LATHE (13708, 8379, 77, 1000, new Item[] { new Item(Items.OAK_WORKBENCH_8376), new Item(Items.OAK_PLANK_8778, 2), new Item(Items.STEEL_BAR_2353) }),
/**
* Workshop stools (linked to workbench/crafting table hotspots)
*/
WORKSHOP_STOOL (13719, -1, 1, 0),
WORKSHOP_STOOL_OAK(13720, -1, 1, 0),
/** /**
* Workshop repair benches/stands * Workshop repair benches/stands
*/ */
@ -428,30 +425,30 @@ public enum Decoration {
/** /**
* Bedroom decorations. * Bedroom decorations.
*/ */
WOODEN_BED (13148, 8031, 20, 117, new Item[] { new Item(Items.PLANK_960, 3), new Item(Items.BOLT_OF_CLOTH_8790, 2) }, Items.WOODEN_BED_8576), WOODEN_BED (13148, 8031, 20, 117, new Item[] { new Item(Items.PLANK_960, 3), new Item(Items.BOLT_OF_CLOTH_8790, 2) }),
OAK_BED (13149, 8032, 30, 210, new Item[] { new Item(Items.OAK_PLANK_8778, 3), new Item(Items.BOLT_OF_CLOTH_8790, 2) }, Items.OAK_BED_8578), OAK_BED (13149, 8032, 30, 210, new Item[] { new Item(Items.OAK_PLANK_8778, 3), new Item(Items.BOLT_OF_CLOTH_8790, 2) }),
LARGE_OAK_BED (13150, 8033, 34, 330, new Item[] { new Item(Items.OAK_PLANK_8778, 5), new Item(Items.BOLT_OF_CLOTH_8790, 2) }, Items.LARGE_OAK_BED_8580), LARGE_OAK_BED (13150, 8033, 34, 330, new Item[] { new Item(Items.OAK_PLANK_8778, 5), new Item(Items.BOLT_OF_CLOTH_8790, 2) }),
TEAK_BED (13151, 8034, 40, 300, new Item[] { new Item(Items.TEAK_PLANK_8780, 3), new Item(Items.BOLT_OF_CLOTH_8790, 2) }, Items.TEAK_BED_8582), TEAK_BED (13151, 8034, 40, 300, new Item[] { new Item(Items.TEAK_PLANK_8780, 3), new Item(Items.BOLT_OF_CLOTH_8790, 2) }),
LARGE_TEAK_BED (13152, 8035, 45, 480, new Item[] { new Item(Items.TEAK_PLANK_8780, 5), new Item(Items.BOLT_OF_CLOTH_8790, 2) }, Items.LARGE_TEAK_BED_8584), LARGE_TEAK_BED (13152, 8035, 45, 480, new Item[] { new Item(Items.TEAK_PLANK_8780, 5), new Item(Items.BOLT_OF_CLOTH_8790, 2) }),
FOUR_POSTER (13153, 8036, 53, 450, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 3), new Item(Items.BOLT_OF_CLOTH_8790, 2) }, Items.FOUR_POSTER_8586), FOUR_POSTER (13153, 8036, 53, 450, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 3), new Item(Items.BOLT_OF_CLOTH_8790, 2) }),
GILDED_FOUR_POSTER(13154, 8037, 60, 1330, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 5), new Item(Items.BOLT_OF_CLOTH_8790, 2), new Item(Items.GOLD_LEAF_8784, 2) }, Items.GILDED_4_POSTER_8588), GILDED_FOUR_POSTER(13154, 8037, 60, 1330, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 5), new Item(Items.BOLT_OF_CLOTH_8790, 2), new Item(Items.GOLD_LEAF_8784, 2) }),
OAK_CLOCK (13169, 8052, 25, 142, new Item[] { new Item(Items.OAK_PLANK_8778, 2), new Item(Items.CLOCKWORK_8792) }, Items.OAK_CLOCK_8590), OAK_CLOCK (13169, 8052, 25, 142, new Item[] { new Item(Items.OAK_PLANK_8778, 2), new Item(Items.CLOCKWORK_8792) }),
TEAK_CLOCK (13170, 8053, 55, 202, new Item[] { new Item(Items.TEAK_PLANK_8780, 2), new Item(Items.CLOCKWORK_8792) }, Items.TEAK_CLOCK_8592), TEAK_CLOCK (13170, 8053, 55, 202, new Item[] { new Item(Items.TEAK_PLANK_8780, 2), new Item(Items.CLOCKWORK_8792) }),
GILDED_CLOCK (13171, 8054, 85, 602, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2), new Item(Items.CLOCKWORK_8792), new Item(Items.GOLD_LEAF_8784) }, Items.GILDED_CLOCK_8594), GILDED_CLOCK (13171, 8054, 85, 602, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2), new Item(Items.CLOCKWORK_8792), new Item(Items.GOLD_LEAF_8784) }),
SHAVING_STAND (13162, 8045, 21, 30, new Item[] { new Item(Items.PLANK_960), new Item(Items.MOLTEN_GLASS_1775) }, Items.SHAVING_STAND_8596), SHAVING_STAND (13162, 8045, 21, 30, new Item[] { new Item(Items.PLANK_960), new Item(Items.MOLTEN_GLASS_1775) }),
OAK_SHAVING_STAND (13163, 8046, 29, 61, new Item[] { new Item(Items.OAK_PLANK_8778), new Item(Items.MOLTEN_GLASS_1775) }, Items.OAK_SHAVING_STAND_8598), OAK_SHAVING_STAND (13163, 8046, 29, 61, new Item[] { new Item(Items.OAK_PLANK_8778), new Item(Items.MOLTEN_GLASS_1775) }),
OAK_DRESSER (13164, 8047, 37, 121, new Item[] { new Item(Items.OAK_PLANK_8778, 2), new Item(Items.MOLTEN_GLASS_1775) }, Items.OAK_DRESSER_8600), OAK_DRESSER (13164, 8047, 37, 121, new Item[] { new Item(Items.OAK_PLANK_8778, 2), new Item(Items.MOLTEN_GLASS_1775) }),
TEAK_DRESSER (13165, 8048, 46, 181, new Item[] { new Item(Items.TEAK_PLANK_8780, 2), new Item(Items.MOLTEN_GLASS_1775) }, Items.TEAK_DRESSER_8602), TEAK_DRESSER (13165, 8048, 46, 181, new Item[] { new Item(Items.TEAK_PLANK_8780, 2), new Item(Items.MOLTEN_GLASS_1775) }),
FANCY_TEAK_DRESSER(13166, 8049, 56, 182, new Item[] { new Item(Items.TEAK_PLANK_8780, 2), new Item(Items.MOLTEN_GLASS_1775, 2) }, Items.FANCY_TEAK_DRESSER_8604), FANCY_TEAK_DRESSER(13166, 8049, 56, 182, new Item[] { new Item(Items.TEAK_PLANK_8780, 2), new Item(Items.MOLTEN_GLASS_1775, 2) }),
MAHOGANY_DRESSER (13167, 8050, 64, 281, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2), new Item(Items.MOLTEN_GLASS_1775) }, Items.MAHOGANY_DRESSER_8606), MAHOGANY_DRESSER (13167, 8050, 64, 281, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2), new Item(Items.MOLTEN_GLASS_1775) }),
GILDED_DRESSER (13168, 8051, 74, 582, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2), new Item(Items.MOLTEN_GLASS_1775, 2), new Item(Items.GOLD_LEAF_8784) }, Items.GILDED_DRESSER_8608), GILDED_DRESSER (13168, 8051, 74, 582, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2), new Item(Items.MOLTEN_GLASS_1775, 2), new Item(Items.GOLD_LEAF_8784) }),
SHOE_BOX (13155, 8038, 20, 58, new Item[] { new Item(Items.PLANK_960, 2) }, Items.SHOE_BOX_8610), SHOE_BOX (13155, 8038, 20, 58, new Item[] { new Item(Items.PLANK_960, 2) }),
OAK_DRAWERS (13156, 8039, 27, 120, new Item[] { new Item(Items.OAK_PLANK_8778, 2) }, Items.OAK_DRAWERS_8612), OAK_DRAWERS (13156, 8039, 27, 120, new Item[] { new Item(Items.OAK_PLANK_8778, 2) }),
OAK_WARDROBE (13157, 8040, 39, 180, new Item[] { new Item(Items.OAK_PLANK_8778, 3) }, Items.OAK_WARDROBE_8614), OAK_WARDROBE (13157, 8040, 39, 180, new Item[] { new Item(Items.OAK_PLANK_8778, 3) }),
TEAK_DRAWERS (13158, 8041, 51, 180, new Item[] { new Item(Items.TEAK_PLANK_8780, 2) }, Items.TEAK_DRAWERS_8616), TEAK_DRAWERS (13158, 8041, 51, 180, new Item[] { new Item(Items.TEAK_PLANK_8780, 2) }),
TEAK_WARDROBE (13159, 8042, 63, 270, new Item[] { new Item(Items.TEAK_PLANK_8780, 3) }, Items.TEAK_WARDROBE_8618), TEAK_WARDROBE (13159, 8042, 63, 270, new Item[] { new Item(Items.TEAK_PLANK_8780, 3) }),
MAHOGANY_WARDROBE (13160, 8043, 75, 420, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2) }, Items.MAHOGANY_DROBE_8620), MAHOGANY_WARDROBE (13160, 8043, 75, 420, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2) }),
GILDED_WARDROBE (13161, 8044, 87, 720, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2), new Item(Items.GOLD_LEAF_8784) }, Items.GILDED_WARDROBE_8622), GILDED_WARDROBE (13161, 8044, 87, 720, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2), new Item(Items.GOLD_LEAF_8784) }),
/** /**
* Quest hall decorations. * Quest hall decorations.
@ -505,31 +502,31 @@ public enum Decoration {
/** /**
* Costume room decorations. * Costume room decorations.
*/ */
OAK_TREASURE_CHEST (18804, 9839, 48, 120, new Item[] { new Item(Items.OAK_PLANK_8778, 2) }, Items.OAK_TREASURE_CHEST_9862), OAK_TREASURE_CHEST (18804, 9839, 48, 120, new Item[] { new Item(Items.OAK_PLANK_8778, 2) }),
TEAK_TREASURE_CHEST (18806, 9840, 66, 180, new Item[] { new Item(Items.TEAK_PLANK_8780, 2) }, Items.TEAK_TREAS_CHEST_9863), TEAK_TREASURE_CHEST (18806, 9840, 66, 180, new Item[] { new Item(Items.TEAK_PLANK_8780, 2) }),
MAHOGANY_TREASURE_CHEST(18808, 9841, 84, 280, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2) }, Items.MGANY_TREAS_CHEST_9864), MAHOGANY_TREASURE_CHEST(18808, 9841, 84, 280, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2) }),
OAK_ARMOUR_CASE (18778, 9826, 46, 180, new Item[] { new Item(Items.OAK_PLANK_8778, 3) }, Items.OAK_ARMOUR_CASE_9859), OAK_ARMOUR_CASE (18778, 9826, 46, 180, new Item[] { new Item(Items.OAK_PLANK_8778, 3) }),
TEAK_ARMOUR_CASE (18780, 9827, 64, 270, new Item[] { new Item(Items.TEAK_PLANK_8780, 3) }, Items.TEAK_ARMOUR_CASE_9860), TEAK_ARMOUR_CASE (18780, 9827, 64, 270, new Item[] { new Item(Items.TEAK_PLANK_8780, 3) }),
MGANY_ARMOUR_CASE (18782, 9828, 82, 420, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 3) }, Items.MGANY_ARMR_CASE_9861), MGANY_ARMOUR_CASE (18782, 9828, 82, 420, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 3) }),
OAK_MAGIC_WARDROBE (18784, 9829, 42, 240, new Item[] { new Item(Items.OAK_PLANK_8778, 4) }, Items.OAK_MAGIC_WARDROBE_9852), OAK_MAGIC_WARDROBE (18784, 9829, 42, 240, new Item[] { new Item(Items.OAK_PLANK_8778, 4) }),
C_OAK_MAGIC_WARDROBE (18786, 9830, 51, 360, new Item[] { new Item(Items.OAK_PLANK_8778, 6) }, Items.CARVED_OAK_MAGIC_WARDROBE_9853), C_OAK_MAGIC_WARDROBE (18786, 9830, 51, 360, new Item[] { new Item(Items.OAK_PLANK_8778, 6) }),
TEAK_MAGIC_WARDROBE (18788, 9831, 60, 360, new Item[] { new Item(Items.TEAK_PLANK_8780, 4) }, Items.TEAK_MAGIC_WARDROBE_9854), TEAK_MAGIC_WARDROBE (18788, 9831, 60, 360, new Item[] { new Item(Items.TEAK_PLANK_8780, 4) }),
C_TEAK_MAGIC_WARDROBE (18790, 9832, 69, 540, new Item[] { new Item(Items.TEAK_PLANK_8780, 6) }, Items.CARVED_TEAK_MAGIC_WARDROBE_9855), C_TEAK_MAGIC_WARDROBE (18790, 9832, 69, 540, new Item[] { new Item(Items.TEAK_PLANK_8780, 6) }),
MGANY_MAGIC_WARDROBE (18792, 9833, 78, 560, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 4) }, Items.MAHOGANY_MAGIC_WARDROBE_9856), MGANY_MAGIC_WARDROBE (18792, 9833, 78, 560, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 4) }),
GILDED_MAGIC_WARDROBE (18794, 9834, 87, 860, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 4), new Item(Items.GOLD_LEAF_8784) }, Items.GILDED_MAGIC_WARDROBE_9857), GILDED_MAGIC_WARDROBE (18794, 9834, 87, 860, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 4), new Item(Items.GOLD_LEAF_8784) }),
MARBLE_MAGIC_WARDROBE (18796, 9835, 96, 500, new Item[] { new Item(Items.MARBLE_BLOCK_8786) }, Items.MARBLE_MAGIC_WARDROBE_9858), MARBLE_MAGIC_WARDROBE (18796, 9835, 96, 500, new Item[] { new Item(Items.MARBLE_BLOCK_8786) }),
OAK_CAPE_RACK (18766, 9817, 54, 240, new Item[] { new Item(Items.OAK_PLANK_8778, 4) }, Items.OAK_CAPE_RACK_9843), OAK_CAPE_RACK (18766, 9817, 54, 240, new Item[] { new Item(Items.OAK_PLANK_8778, 4) }),
TEAK_CAPE_RACK (18767, 9818, 63, 360, new Item[] { new Item(Items.TEAK_PLANK_8780, 4) }, Items.TEAK_CAPE_RACK_9844), TEAK_CAPE_RACK (18767, 9818, 63, 360, new Item[] { new Item(Items.TEAK_PLANK_8780, 4) }),
MGANY_CAPE_RACK (18768, 9819, 72, 560, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 4) }, Items.MGANY_CAPE_RACK_9845), MGANY_CAPE_RACK (18768, 9819, 72, 560, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 4) }),
GILDED_CAPE_RACK (18769, 9820, 81, 860, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 4), new Item(Items.GOLD_LEAF_8784) }, Items.GILDED_CAPE_RACK_9846), GILDED_CAPE_RACK (18769, 9820, 81, 860, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 4), new Item(Items.GOLD_LEAF_8784) }),
MARBLE_CAPE_RACK (18770, 9821, 90, 500, new Item[] { new Item(Items.MARBLE_BLOCK_8786) }, Items.MARBLE_CAPE_RACK_9847), MARBLE_CAPE_RACK (18770, 9821, 90, 500, new Item[] { new Item(Items.MARBLE_BLOCK_8786) }),
MAGIC_CAPE_RACK (18771, 9822, 99, 1000, new Item[] { new Item(Items.MAGIC_STONE_8788) }, Items.MAGICAL_CAPE_RACK_9848), MAGIC_CAPE_RACK (18771, 9822, 99, 1000, new Item[] { new Item(Items.MAGIC_STONE_8788) }),
OAK_TOY_BOX (18798, 9836, 50, 120, new Item[] { new Item(Items.OAK_PLANK_8778, 2) }, Items.OAK_TOY_BOX_9849), OAK_TOY_BOX (18798, 9836, 50, 120, new Item[] { new Item(Items.OAK_PLANK_8778, 2) }),
TEAK_TOY_BOX (18800, 9837, 68, 180, new Item[] { new Item(Items.TEAK_PLANK_8780, 2) }, Items.TEAK_TOY_BOX_9850), TEAK_TOY_BOX (18800, 9837, 68, 180, new Item[] { new Item(Items.TEAK_PLANK_8780, 2) }),
MAHOGANY_TOY_BOX (18802, 9838, 86, 280, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2) }, Items.MAHOGANY_TOY_BOX_9851), MAHOGANY_TOY_BOX (18802, 9838, 86, 280, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2) }),
OAK_COSTUME_BOX (18772, 9823, 44, 120, new Item[] { new Item(Items.OAK_PLANK_8778, 2) }, Items.OAK_COSTUME_BOX_9865), OAK_COSTUME_BOX (18772, 9823, 44, 120, new Item[] { new Item(Items.OAK_PLANK_8778, 2) }),
TEAK_COSTUME_BOX (18774, 9824, 62, 180, new Item[] { new Item(Items.TEAK_PLANK_8780, 2) }, Items.TEAK_COSTUME_BOX_9866), TEAK_COSTUME_BOX (18774, 9824, 62, 180, new Item[] { new Item(Items.TEAK_PLANK_8780, 2) }),
MAHOGANY_COSTUME_BOX (18776, 9825, 80, 280, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2) }, Items.MAHOGANY_COS_BOX_9867), MAHOGANY_COSTUME_BOX (18776, 9825, 80, 280, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2) }),
/** /**
* Chapel decorations. * Chapel decorations.
@ -687,7 +684,6 @@ public enum Decoration {
FREMENNIK_WINDOW (13112, -1, 1, 0), FREMENNIK_WINDOW (13112, -1, 1, 0),
TROPICAL_WOOD_WINDOW (10816, -1, 1, 0), TROPICAL_WOOD_WINDOW (10816, -1, 1, 0),
FANCY_STONE_WINDOW (13117, -1, 1, 0), FANCY_STONE_WINDOW (13117, -1, 1, 0),
; ;
/** /**
@ -720,11 +716,6 @@ public enum Decoration {
*/ */
private final Item[] refundItems; private final Item[] refundItems;
/**
* The item id of the flatpack.
*/
private final int flatpackItemId;
/** /**
* The tools required. * The tools required.
*/ */
@ -783,11 +774,6 @@ public enum Decoration {
this.reqsText = generateDefaultReqsText(items, getNailAmount()); this.reqsText = generateDefaultReqsText(items, getNailAmount());
} }
Decoration(int objectId, int interfaceItem, int level, int experience, Item[] items, int flatpackItemId) {
this(objectId, interfaceItem, level, experience, new int[] { Items.HAMMER_2347, Items.SAW_8794 }, items, new Item[] {}, new String[] {}, flatpackItemId);
this.reqsText = generateDefaultReqsText(items, getNailAmount());
}
/** /**
* Constructs a new object, default refund items, default requirements text. * Constructs a new object, default refund items, default requirements text.
* @param objectId The object id. * @param objectId The object id.
@ -841,10 +827,6 @@ public enum Decoration {
* @param reqsText The requirements text to be shown in the interface. * @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, String[] reqsText) { Decoration(int objectId, int interfaceItem, int level, int experience, int[] tools, Item[] items, Item[] refundItems, String[] reqsText) {
this(objectId, interfaceItem, level, experience, tools, items, refundItems, reqsText, -1);
}
Decoration(int objectId, int interfaceItem, int level, int experience, int[] tools, Item[] items, Item[] refundItems, String[] reqsText, int flatpackItemId) {
this.objectId = objectId; this.objectId = objectId;
this.objectIds = null; this.objectIds = null;
this.interfaceItem = interfaceItem; this.interfaceItem = interfaceItem;
@ -853,7 +835,6 @@ public enum Decoration {
this.tools = tools; this.tools = tools;
this.items = items; this.items = items;
this.refundItems = refundItems; this.refundItems = refundItems;
this.flatpackItemId = flatpackItemId;
if (reqsText.length > 0) { if (reqsText.length > 0) {
System.arraycopy(reqsText, 0, this.reqsText, 0, reqsText.length); System.arraycopy(reqsText, 0, this.reqsText, 0, reqsText.length);
} }
@ -900,7 +881,6 @@ public enum Decoration {
this.tools = tools; this.tools = tools;
this.items = items; this.items = items;
this.refundItems = refundItems; this.refundItems = refundItems;
this.flatpackItemId = -1;
} }
/** /**
@ -951,15 +931,6 @@ public enum Decoration {
return null; return null;
} }
public static Decoration forFlatpackItemId(int flatpackId) {
for (Decoration d : Decoration.values()) {
if (d.getFlatpackItemID() == flatpackId) {
return d;
}
}
return null;
}
/** /**
* Gets the amount of nails required for this hotspot. * Gets the amount of nails required for this hotspot.
* @return The amount of nails. * @return The amount of nails.
@ -1049,14 +1020,6 @@ public enum Decoration {
return objectIds; return objectIds;
} }
/**
* Gets the flatpack item ID if it exists.
* @return the int ID.
*/
public int getFlatpackItemID() {
return flatpackItemId;
}
/** /**
* If this node should be invisible to user build options * If this node should be invisible to user build options
* @return true if so. * @return true if so.

Some files were not shown because too many files have changed in this diff Show more