Merge branch 2009scape:master into master

This commit is contained in:
Tooze 2025-10-14 01:03:31 +00:00
commit 094bc4ac6b
102 changed files with 3667 additions and 1692 deletions

30
.dockerignore Normal file
View file

@ -0,0 +1,30 @@
# Local volumes
/config
/data
/db
# Updated through volumes
Server/data
Server/worldprops
# Env files containing secrets
/.env
/*.env
# Log files
logs
*.log
# Git files
.git
.gitattributes
.gitignore
# Basic stuff
*.md
LICENSE
.gitlab-ci.yml
# Docker files
docker-compose.yml
Dockerfile

12
.gitignore vendored
View file

@ -18,7 +18,8 @@ Server/data/global_kill_stats.json
Server/ge_test.db
Server/latestdump.txt
Management-Server/managementprops/
Server/worldprops/
Server/worldprops/*
!Server/worldprops/default.conf
**/.idea/workspace.xml
**/.idea/tasks.xml
@ -32,3 +33,12 @@ gradle
build/kotlin/sessions/
**/*.iml
Server/hasRan.txt
# Local volumes
/config
/data
/db
# Env files containing secrets
/.env
/*.env

View file

@ -4,14 +4,8 @@ FROM maven:3-openjdk-11-slim
# Set working directory to /app
WORKDIR /app
# Update apt; install git and git-lfs
RUN apt-get update && apt-get -qq -y install git git-lfs
# Clone the 2009scape repository
RUN git clone --depth=1 https://gitlab.com/2009scape/2009scape.git
# Fake it til you make it - let's go home
WORKDIR /app/2009scape
# Copy all sources etc
COPY . .
# Make sure ./run has permissions
RUN chmod +x run

View file

@ -125,6 +125,78 @@ Start the game server with the included run script. Use `./run -h` for more info
Start the game server with `run-server.bat`
#### Docker
Make sure [Docker Engine](https://docs.docker.com/engine/install/) & [Docker Compose](https://docs.docker.com/compose/install/) plugin are installed first:
Go to the project root where the git repository is cloned into:
```bash
cd /path/to/project-dir
```
To configure the database, copy the mysql env file template to a env file in the project root:
```bash
cp mysql.env.example mysql.env
```
Customize the env file however necessary.
Create a new directory called 'config' into the project root.
```bash
mkdir config
```
Copy the server config file template in the config directory:
```bash
cp Server/worldprops/default.conf config/default.conf
```
Edit the server configuration file as per needed.
Go to the project root directory and execute:
```bash
docker compose up --build
```
Which will build the docker image using the local Dockerfile and starts the server and database containers.
The previous up command should be run every time the server sources are modified to propagate the changes to the container.
For the first time, the server compilation process takes a long time. Grab some coffee in the meanwhile.
You can check (and follow) the containers logs by running the following in the project root directory (-f for follow and Ctrl+C to stop):
```bash
docker compose logs -f
```
Any compilation or runtime errors will be logged here.
If you have already compiled the server and made no changes to the sources, you can simply run without the build option (however it will be cached anyways):
```bash
docker compose up
```
To later restart the server to apply simple configuration changes, in the project root directory run:
```bash
docker compose restart server
```
To shut down / take down the server, in the project root directory run:
```bash
docker compose up --build
```
The database files, build cache and config files will be persisted on the host filesystem for easy backup management.
### License
We use the AGPL 3.0 license, which can be found [here](https://www.gnu.org/licenses/agpl-3.0.en.html). Please be sure to read and understand the license. Failure to follow the guidelines outlined in the license will result in legal action. If you know or hear of anyone breaking this license, please send a report, with proof, to Red Bracket#8151, ceikry#2724, or woahscam#8535 on discord or email woahscam@hotmail.com. **We WILL NOT change the license to fit your needs.**

View file

@ -125,7 +125,7 @@
"start_graphic": "232,96",
"darkbow_graphic": "",
"projectile": "226,40,36,32,32,15,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "813",
@ -133,7 +133,7 @@
"start_graphic": "233,96",
"darkbow_graphic": "",
"projectile": "227,40,36,32,32,15,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "814",
@ -141,7 +141,7 @@
"start_graphic": "234,96",
"darkbow_graphic": "",
"projectile": "228,40,36,32,32,15,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "815",
@ -149,7 +149,7 @@
"start_graphic": "235,96",
"darkbow_graphic": "",
"projectile": "229,40,36,32,32,15,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "816",
@ -157,7 +157,7 @@
"start_graphic": "236,96",
"darkbow_graphic": "",
"projectile": "230,40,36,32,32,15,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "817",
@ -165,7 +165,7 @@
"start_graphic": "237,96",
"darkbow_graphic": "",
"projectile": "231,40,36,32,32,15,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "825",
@ -221,7 +221,7 @@
"start_graphic": "206,96",
"darkbow_graphic": "",
"projectile": "200,40,36,32,32,15,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "832",
@ -229,7 +229,7 @@
"start_graphic": "207,96",
"darkbow_graphic": "",
"projectile": "201,40,36,32,32,15,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "833",
@ -237,7 +237,7 @@
"start_graphic": "208,96",
"darkbow_graphic": "",
"projectile": "202,40,36,32,32,15,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "834",
@ -245,7 +245,7 @@
"start_graphic": "209,96",
"darkbow_graphic": "",
"projectile": "203,40,36,32,32,15,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "835",
@ -253,7 +253,7 @@
"start_graphic": "210,96",
"darkbow_graphic": "",
"projectile": "204,40,36,32,32,15,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "836",
@ -261,7 +261,7 @@
"start_graphic": "211,96",
"darkbow_graphic": "",
"projectile": "205,40,36,32,32,15,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "863",
@ -325,7 +325,7 @@
"start_graphic": "219,96",
"darkbow_graphic": "",
"projectile": "212,40,36,32,32,15,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "871",
@ -333,7 +333,7 @@
"start_graphic": "220,96",
"darkbow_graphic": "",
"projectile": "213,40,36,32,32,15,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "872",
@ -341,7 +341,7 @@
"start_graphic": "221,96",
"darkbow_graphic": "",
"projectile": "214,40,36,32,32,15,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "873",
@ -349,7 +349,7 @@
"start_graphic": "223,96",
"darkbow_graphic": "",
"projectile": "216,40,36,32,32,15,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "874",
@ -357,7 +357,7 @@
"start_graphic": "222,96",
"darkbow_graphic": "",
"projectile": "215,40,36,32,32,15,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "875",
@ -365,7 +365,7 @@
"start_graphic": "224,96",
"darkbow_graphic": "",
"projectile": "217,40,36,32,32,15,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "876",
@ -373,7 +373,7 @@
"start_graphic": "225,96",
"darkbow_graphic": "",
"projectile": "218,40,36,32,32,15,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "877",
@ -389,7 +389,7 @@
"start_graphic": "-1,0",
"darkbow_graphic": "",
"projectile": "27,38,36,41,32,5,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "879",
@ -421,7 +421,7 @@
"start_graphic": "19,96",
"darkbow_graphic": "1104,96",
"projectile": "10,40,36,41,46,5,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "884",
@ -437,7 +437,7 @@
"start_graphic": "18,96",
"darkbow_graphic": "1105,96",
"projectile": "9,40,36,41,46,5,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "886",
@ -453,7 +453,7 @@
"start_graphic": "20,96",
"darkbow_graphic": "1106,96",
"projectile": "11,40,36,41,46,5,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "888",
@ -469,7 +469,7 @@
"start_graphic": "21,96",
"darkbow_graphic": "1107,96",
"projectile": "12,40,36,41,46,5,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "890",
@ -485,7 +485,7 @@
"start_graphic": "22,96",
"darkbow_graphic": "1108,96",
"projectile": "13,40,36,41,46,5,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "892",
@ -501,7 +501,7 @@
"start_graphic": "24,96",
"darkbow_graphic": "1109,96",
"projectile": "15,40,36,41,46,5,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "2532",
@ -565,7 +565,7 @@
"start_graphic": "273,96",
"darkbow_graphic": "",
"projectile": "227,40,36,32,32,15,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "4160",
@ -725,7 +725,7 @@
"start_graphic": "19,96",
"darkbow_graphic": "1104,96",
"projectile": "10,40,36,41,46,5,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "5617",
@ -733,7 +733,7 @@
"start_graphic": "18,96",
"darkbow_graphic": "1105,96",
"projectile": "9,40,36,41,46,5,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "5618",
@ -741,7 +741,7 @@
"start_graphic": "20,96",
"darkbow_graphic": "1106,96",
"projectile": "11,40,36,41,46,5,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "5619",
@ -749,7 +749,7 @@
"start_graphic": "21,96",
"darkbow_graphic": "1107,96",
"projectile": "12,40,36,41,46,5,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "5620",
@ -757,7 +757,7 @@
"start_graphic": "22,96",
"darkbow_graphic": "1108,96",
"projectile": "13,40,36,41,46,5,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "5621",
@ -773,7 +773,7 @@
"start_graphic": "19,96",
"darkbow_graphic": "1104,96",
"projectile": "10,40,36,41,46,5,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "5623",
@ -781,7 +781,7 @@
"start_graphic": "18,96",
"darkbow_graphic": "1105,96",
"projectile": "9,40,36,41,46,5,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "5624",
@ -789,7 +789,7 @@
"start_graphic": "20,96",
"darkbow_graphic": "1106,96",
"projectile": "11,40,36,41,46,5,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "5625",
@ -797,7 +797,7 @@
"start_graphic": "21,96",
"darkbow_graphic": "1107,96",
"projectile": "12,40,36,41,46,5,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "5626",
@ -805,7 +805,7 @@
"start_graphic": "22,96",
"darkbow_graphic": "1108,96",
"projectile": "13,40,36,41,46,5,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "5627",
@ -813,7 +813,7 @@
"start_graphic": "24,96",
"darkbow_graphic": "1109,96",
"projectile": "15,40,36,41,46,5,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "5628",
@ -821,7 +821,7 @@
"start_graphic": "232,96",
"darkbow_graphic": "",
"projectile": "226,40,36,32,32,15,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "5629",
@ -829,7 +829,7 @@
"start_graphic": "233,96",
"darkbow_graphic": "",
"projectile": "227,40,36,32,32,15,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "5630",
@ -837,7 +837,7 @@
"start_graphic": "235,96",
"darkbow_graphic": "",
"projectile": "229,40,36,32,32,15,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "5631",
@ -845,7 +845,7 @@
"start_graphic": "273,96",
"darkbow_graphic": "",
"projectile": "227,40,36,32,32,15,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "5633",
@ -853,7 +853,7 @@
"start_graphic": "236,96",
"darkbow_graphic": "",
"projectile": "230,40,36,32,32,15,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "5634",
@ -861,7 +861,7 @@
"start_graphic": "237,96",
"darkbow_graphic": "",
"projectile": "231,40,36,32,32,15,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "5635",
@ -869,7 +869,7 @@
"start_graphic": "232,96",
"darkbow_graphic": "",
"projectile": "226,40,36,32,32,15,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "5636",
@ -877,7 +877,7 @@
"start_graphic": "233,96",
"darkbow_graphic": "",
"projectile": "227,40,36,32,32,15,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "5637",
@ -885,7 +885,7 @@
"start_graphic": "234,96",
"darkbow_graphic": "",
"projectile": "228,40,36,32,32,15,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "5638",
@ -893,7 +893,7 @@
"start_graphic": "273,96",
"darkbow_graphic": "",
"projectile": "227,40,36,32,32,15,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "5639",
@ -901,7 +901,7 @@
"start_graphic": "235,96",
"darkbow_graphic": "",
"projectile": "229,40,36,32,32,15,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "5640",
@ -909,7 +909,7 @@
"start_graphic": "236,96",
"darkbow_graphic": "",
"projectile": "230,40,36,32,32,15,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "5641",
@ -917,7 +917,7 @@
"start_graphic": "237,96",
"darkbow_graphic": "",
"projectile": "231,40,36,32,32,15,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "5642",
@ -925,7 +925,7 @@
"start_graphic": "206,96",
"darkbow_graphic": "",
"projectile": "200,40,36,32,32,15,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "5643",
@ -933,7 +933,7 @@
"start_graphic": "207,96",
"darkbow_graphic": "",
"projectile": "201,40,36,32,32,15,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "5644",
@ -941,7 +941,7 @@
"start_graphic": "208,96",
"darkbow_graphic": "",
"projectile": "202,40,36,32,32,15,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "5645",
@ -949,7 +949,7 @@
"start_graphic": "209,96",
"darkbow_graphic": "",
"projectile": "203,40,36,32,32,15,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "5646",
@ -957,7 +957,7 @@
"start_graphic": "210,96",
"darkbow_graphic": "",
"projectile": "204,40,36,32,32,15,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "5647",
@ -965,7 +965,7 @@
"start_graphic": "211,96",
"darkbow_graphic": "",
"projectile": "205,40,36,32,32,15,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "5648",
@ -973,7 +973,7 @@
"start_graphic": "206,96",
"darkbow_graphic": "",
"projectile": "200,40,36,32,32,15,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "5649",
@ -981,7 +981,7 @@
"start_graphic": "207,96",
"darkbow_graphic": "",
"projectile": "201,40,36,32,32,15,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "5650",
@ -989,7 +989,7 @@
"start_graphic": "208,96",
"darkbow_graphic": "",
"projectile": "202,40,36,32,32,15,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "5651",
@ -997,7 +997,7 @@
"start_graphic": "209,96",
"darkbow_graphic": "",
"projectile": "203,40,36,32,32,15,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "5652",
@ -1005,7 +1005,7 @@
"start_graphic": "210,96",
"darkbow_graphic": "",
"projectile": "204,40,36,32,32,15,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "5653",
@ -1013,7 +1013,7 @@
"start_graphic": "211,96",
"darkbow_graphic": "",
"projectile": "205,40,36,32,32,15,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "5654",
@ -1021,7 +1021,7 @@
"start_graphic": "219,96",
"darkbow_graphic": "",
"projectile": "212,40,36,32,32,15,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "5655",
@ -1029,7 +1029,7 @@
"start_graphic": "220,96",
"darkbow_graphic": "",
"projectile": "213,40,36,32,32,15,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "5656",
@ -1037,7 +1037,7 @@
"start_graphic": "221,96",
"darkbow_graphic": "",
"projectile": "214,40,36,32,32,15,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "5657",
@ -1045,7 +1045,7 @@
"start_graphic": "223,96",
"darkbow_graphic": "",
"projectile": "216,40,36,32,32,15,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "5658",
@ -1053,7 +1053,7 @@
"start_graphic": "222,96",
"darkbow_graphic": "",
"projectile": "215,40,36,32,32,15,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "5659",
@ -1061,7 +1061,7 @@
"start_graphic": "224,96",
"darkbow_graphic": "",
"projectile": "217,40,36,32,32,15,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "5660",
@ -1069,7 +1069,7 @@
"start_graphic": "225,96",
"darkbow_graphic": "",
"projectile": "218,40,36,32,32,15,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "5661",
@ -1077,7 +1077,7 @@
"start_graphic": "219,96",
"darkbow_graphic": "",
"projectile": "212,40,36,32,32,15,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "5662",
@ -1085,7 +1085,7 @@
"start_graphic": "220,96",
"darkbow_graphic": "",
"projectile": "213,40,36,32,32,15,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "5663",
@ -1093,7 +1093,7 @@
"start_graphic": "221,96",
"darkbow_graphic": "",
"projectile": "214,40,36,32,32,15,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "5664",
@ -1101,7 +1101,7 @@
"start_graphic": "223,96",
"darkbow_graphic": "",
"projectile": "216,40,36,32,32,15,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "5665",
@ -1109,7 +1109,7 @@
"start_graphic": "222,96",
"darkbow_graphic": "",
"projectile": "215,40,36,32,32,15,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "5666",
@ -1117,7 +1117,7 @@
"start_graphic": "224,96",
"darkbow_graphic": "",
"projectile": "217,40,36,32,32,15,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "5667",
@ -1125,7 +1125,7 @@
"start_graphic": "225,96",
"darkbow_graphic": "",
"projectile": "218,40,36,32,32,15,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "6061",
@ -1133,7 +1133,7 @@
"start_graphic": "-1,0",
"darkbow_graphic": "",
"projectile": "27,38,36,41,32,5,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "6062",
@ -1141,7 +1141,7 @@
"start_graphic": "-1,0",
"darkbow_graphic": "",
"projectile": "27,38,36,41,32,5,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "6522",
@ -1293,7 +1293,7 @@
"start_graphic": "-1,0",
"darkbow_graphic": "",
"projectile": "27,38,36,41,32,5,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "9287",
@ -1301,7 +1301,7 @@
"start_graphic": "-1,0",
"darkbow_graphic": "",
"projectile": "27,38,36,41,32,5,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "9288",
@ -1309,7 +1309,7 @@
"start_graphic": "-1,0",
"darkbow_graphic": "",
"projectile": "27,38,36,41,32,5,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "9289",
@ -1317,7 +1317,7 @@
"start_graphic": "-1,0",
"darkbow_graphic": "",
"projectile": "27,38,36,41,32,5,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "9290",
@ -1325,7 +1325,7 @@
"start_graphic": "-1,0",
"darkbow_graphic": "",
"projectile": "27,38,36,41,32,5,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "9291",
@ -1333,7 +1333,7 @@
"start_graphic": "-1,0",
"darkbow_graphic": "",
"projectile": "27,38,36,41,32,5,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "9293",
@ -1341,7 +1341,7 @@
"start_graphic": "-1,0",
"darkbow_graphic": "",
"projectile": "27,38,36,41,32,5,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "9294",
@ -1349,7 +1349,7 @@
"start_graphic": "-1,0",
"darkbow_graphic": "",
"projectile": "27,38,36,41,32,5,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "9295",
@ -1357,7 +1357,7 @@
"start_graphic": "-1,0",
"darkbow_graphic": "",
"projectile": "27,38,36,41,32,5,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "9296",
@ -1365,7 +1365,7 @@
"start_graphic": "-1,0",
"darkbow_graphic": "",
"projectile": "27,38,36,41,32,5,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "9297",
@ -1373,7 +1373,7 @@
"start_graphic": "-1,0",
"darkbow_graphic": "",
"projectile": "27,38,36,41,32,5,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "9298",
@ -1381,7 +1381,7 @@
"start_graphic": "-1,0",
"darkbow_graphic": "",
"projectile": "27,38,36,41,32,5,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "9300",
@ -1389,7 +1389,7 @@
"start_graphic": "-1,0",
"darkbow_graphic": "",
"projectile": "27,38,36,41,32,5,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "9301",
@ -1397,7 +1397,7 @@
"start_graphic": "-1,0",
"darkbow_graphic": "",
"projectile": "27,38,36,41,32,5,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "9302",
@ -1405,7 +1405,7 @@
"start_graphic": "-1,0",
"darkbow_graphic": "",
"projectile": "27,38,36,41,32,5,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "9303",
@ -1413,7 +1413,7 @@
"start_graphic": "-1,0",
"darkbow_graphic": "",
"projectile": "27,38,36,41,32,5,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "9304",
@ -1421,7 +1421,7 @@
"start_graphic": "-1,0",
"darkbow_graphic": "",
"projectile": "27,38,36,41,32,5,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "9305",
@ -1429,7 +1429,7 @@
"start_graphic": "-1,0",
"darkbow_graphic": "",
"projectile": "27,38,36,41,32,5,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "9335",
@ -1557,7 +1557,7 @@
"start_graphic": "1116,96",
"darkbow_graphic": "1114,96",
"projectile": "1120,40,36,41,46,5,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "11228",
@ -1565,7 +1565,7 @@
"start_graphic": "1116,96",
"darkbow_graphic": "1114,96",
"projectile": "1120,40,36,41,46,5,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "11229",
@ -1573,7 +1573,7 @@
"start_graphic": "1116,96",
"darkbow_graphic": "1114,96",
"projectile": "1120,40,36,41,46,5,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "11230",
@ -1589,7 +1589,7 @@
"start_graphic": "1123,96",
"darkbow_graphic": "",
"projectile": "1122,40,36,32,32,15,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "11233",
@ -1597,7 +1597,7 @@
"start_graphic": "1123,96",
"darkbow_graphic": "",
"projectile": "1122,40,36,32,32,15,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "11234",
@ -1605,7 +1605,7 @@
"start_graphic": "1123,96",
"darkbow_graphic": "",
"projectile": "1122,40,36,32,32,15,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "13083",
@ -1621,7 +1621,7 @@
"start_graphic": "-1,0",
"darkbow_graphic": "",
"projectile": "27,38,36,41,32,5,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "13085",
@ -1629,7 +1629,7 @@
"start_graphic": "-1,0",
"darkbow_graphic": "",
"projectile": "27,38,36,41,32,5,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "13086",
@ -1637,7 +1637,7 @@
"start_graphic": "-1,0",
"darkbow_graphic": "",
"projectile": "27,38,36,41,32,5,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "13280",
@ -1661,7 +1661,7 @@
"start_graphic": "-1,0",
"darkbow_graphic": "",
"projectile": "1837,40,36,32,32,15,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "13881",
@ -1669,7 +1669,7 @@
"start_graphic": "-1,0",
"darkbow_graphic": "",
"projectile": "1837,40,36,32,32,15,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "13882",
@ -1677,7 +1677,7 @@
"start_graphic": "-1,0",
"darkbow_graphic": "",
"projectile": "1837,40,36,32,32,15,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "13883",
@ -1701,7 +1701,7 @@
"start_graphic": "-1,0",
"darkbow_graphic": "",
"projectile": "1837,40,36,32,32,15,0",
"poison_damage": "28"
"poison_damage": "10"
},
{
"itemId": "13955",
@ -1709,7 +1709,7 @@
"start_graphic": "1837,96",
"darkbow_graphic": "",
"projectile": "1840,40,36,32,32,15,0",
"poison_damage": "38"
"poison_damage": "15"
},
{
"itemId": "13956",
@ -1717,7 +1717,7 @@
"start_graphic": "1837,96",
"darkbow_graphic": "",
"projectile": "1840,40,36,32,32,15,0",
"poison_damage": "48"
"poison_damage": "20"
},
{
"itemId": "13957",

View file

@ -1439,6 +1439,12 @@
"fence": "false",
"metal": "false"
},
{
"id": "11470",
"replaceId": "11471",
"fence": "false",
"metal": "false"
},
{
"id": "11483",
"replaceId": "11708",

View file

@ -233,7 +233,7 @@
},
{
"item_id": "946",
"loc_data": "{1,2903,3148,0,80}-{1,3205,3212,0,80}-{1,3224,3202,0,80}-{1,3218,3416,1,90}-{1,2820,3450,0,90}-{1,3106,3956,0,60}-{1,2566,9526,0,30}-{1,3215,9625,0,80}-{1,3218,9887,0,33}-{1,2700,3407,0,100}-"
"loc_data": "{1,2903,3148,0,80}-{1,3205,3212,0,80}-{1,3224,3202,0,80}-{1,3218,3416,1,90}-{1,2820,3450,0,90}-{1,2700,3407,0,100}-{1,3106,3956,0,60}-{1,2566,9526,0,30}-{1,3215,9625,0,80}-{1,3218,9887,0,33}-"
},
{
"item_id": "952",
@ -415,6 +415,14 @@
"item_id": "1785",
"loc_data": "{1,2822,3355,0,150}-"
},
{
"item_id": "1812",
"loc_data": "{1,2747,3579,0,100}"
},
{
"item_id": "1813",
"loc_data": "{1,2746,3578,0,100}"
},
{
"item_id": "1856",
"loc_data": "{1,2638,3292,0,150}-"
@ -597,7 +605,7 @@
},
{
"item_id": "3138",
"loc_data": "{1,3463,9478,2,45}-{1,3461,9480,2,45}-{1,3461,9482,2,45}-{1,3461,9484,2,45}-"
"loc_data": "{1,3461,9480,2,30}-{1,3460,9484,2,30}-{1,3465,9477,2,30}-{1,3467,9493,0,30}-{1,3486,9517,0,30}-{1,3474,9509,0,30}-{1,3470,9502,0,30}-{1,3480,9483,0,30}-"
},
{
"item_id": "3711",

View file

@ -18946,7 +18946,7 @@
"equipment_slot": "2"
},
{
"examine": "Anna's shiny silver coated necklace.",
"examine": "Anna's shiny silver coated necklace coated with a thin layer of flour.",
"durability": null,
"name": "Silver necklace",
"weight": "1",
@ -18964,7 +18964,7 @@
"id": "1798"
},
{
"examine": "Bob's shiny silver coated tea cup.",
"examine": "Bob's shiny silver coated tea cup coated with a thin layer of flour.",
"durability": null,
"name": "Silver cup",
"tradeable": "false",
@ -18982,7 +18982,7 @@
"id": "1800"
},
{
"examine": "Carol's shiny silver coated bottle.",
"examine": "Carol's shiny silver coated bottle coated with a thin layer of flour.",
"durability": null,
"name": "Silver bottle",
"tradeable": "false",
@ -19000,7 +19000,7 @@
"id": "1802"
},
{
"examine": "David's shiny silver coated book.",
"examine": "David's shiny silver coated book coated with a thin layer of flour.",
"durability": null,
"name": "Silver book",
"tradeable": "false",
@ -19018,7 +19018,7 @@
"id": "1804"
},
{
"examine": "Elizabeth's shiny silver coated needle.",
"examine": "Elizabeth's shiny silver coated needle coated with a thin layer of flour.",
"durability": null,
"name": "Silver needle",
"tradeable": "false",
@ -19036,7 +19036,7 @@
"id": "1806"
},
{
"examine": "Frank's shiny silver coated pot.",
"examine": "Frank's shiny silver coated pot coated with a thin layer of flour.",
"durability": null,
"name": "Silver pot",
"tradeable": "false",
@ -19045,7 +19045,7 @@
"id": "1807"
},
{
"examine": "Some (colour) thread found at the murder scene.",
"examine": "Some red thread found at the murder scene.",
"durability": null,
"name": "Criminal's thread",
"tradeable": "false",
@ -19054,7 +19054,7 @@
"id": "1808"
},
{
"examine": "Some (colour) thread found at the murder scene.",
"examine": "Some green thread found at the murder scene.",
"durability": null,
"name": "Criminal's thread",
"tradeable": "false",
@ -19063,7 +19063,7 @@
"id": "1809"
},
{
"examine": "Some (colour) thread found at the murder scene.",
"examine": "Some blue thread found at the murder scene.",
"durability": null,
"name": "Criminal's thread",
"tradeable": "false",
@ -19090,7 +19090,7 @@
"id": "1812"
},
{
"examine": "A flimsy-looking dagger found at the crime scene./A flimsy looking dagger found at the crime scene coated with a thin layer of flour.",
"examine": "A flimsy-looking dagger found at the crime scene.",
"attack_audios": "2517,2517,2500,2517",
"durability": null,
"name": "Criminal's dagger",
@ -19098,7 +19098,7 @@
"id": "1813"
},
{
"examine": "A flimsy-looking dagger found at the crime scene./A flimsy looking dagger found at the crime scene coated with a thin layer of flour.",
"examine": "A flimsy looking dagger found at the crime scene coated with a thin layer of flour.",
"attack_audios": "2517,2517,2500,2517",
"durability": null,
"name": "Criminal's dagger",
@ -51573,6 +51573,7 @@
"equipment_slot": "3",
"grand_exchange_price": "483",
"attack_audios": "2517,2517,2500,2517",
"attack_anims": "400,400,401,400",
"name": "Iron dagger(p+)",
"tradeable": "true",
"archery_ticket_price": "0",
@ -51601,6 +51602,7 @@
"equipment_slot": "3",
"grand_exchange_price": "350",
"attack_audios": "2517,2517,2500,2517",
"attack_anims": "400,400,401,400",
"name": "Bronze dagger(p+)",
"tradeable": "true",
"archery_ticket_price": "0",
@ -51630,6 +51632,7 @@
"equipment_slot": "3",
"grand_exchange_price": "575",
"attack_audios": "2517,2517,2500,2517",
"attack_anims": "400,400,401,400",
"name": "Steel dagger(p+)",
"tradeable": "true",
"archery_ticket_price": "0",
@ -51659,6 +51662,7 @@
"equipment_slot": "3",
"grand_exchange_price": "538",
"attack_audios": "2517,2517,2500,2517",
"attack_anims": "400,400,401,400",
"name": "Mithril dagger(p+)",
"tradeable": "true",
"archery_ticket_price": "0",
@ -51684,6 +51688,7 @@
"equipment_slot": "3",
"grand_exchange_price": "800",
"attack_audios": "2517,2517,2500,2517",
"attack_anims": "400,400,401,400",
"name": "Adamant dagger(p+)",
"tradeable": "true",
"archery_ticket_price": "0",
@ -51711,6 +51716,7 @@
"equip_audio": "2248",
"render_anim": "2584",
"equipment_slot": "3",
"attack_anims": "400,400,401,400",
"lendable": "true",
"grand_exchange_price": "4538",
"attack_audios": "2517,2517,2500,2517",
@ -51779,6 +51785,7 @@
"equipment_slot": "3",
"grand_exchange_price": "664",
"attack_audios": "2517,2517,2500,2517",
"attack_anims": "400,400,401,400",
"name": "Black dagger(p+)",
"tradeable": "true",
"archery_ticket_price": "0",
@ -51826,6 +51833,7 @@
"equipment_slot": "3",
"grand_exchange_price": "4128",
"attack_audios": "2517,2517,2500,2517",
"attack_anims": "400,400,401,400",
"name": "Iron dagger(p++)",
"tradeable": "true",
"archery_ticket_price": "0",
@ -51854,6 +51862,7 @@
"equipment_slot": "3",
"grand_exchange_price": "5088",
"attack_audios": "2517,2517,2500,2517",
"attack_anims": "400,400,401,400",
"name": "Br'ze dagger(p++)",
"tradeable": "true",
"archery_ticket_price": "0",
@ -51883,6 +51892,7 @@
"equipment_slot": "3",
"grand_exchange_price": "4729",
"attack_audios": "2517,2517,2500,2517",
"attack_anims": "400,400,401,400",
"name": "Steel dagger(p++)",
"tradeable": "true",
"archery_ticket_price": "0",
@ -51912,6 +51922,7 @@
"equipment_slot": "3",
"grand_exchange_price": "3476",
"attack_audios": "2517,2517,2500,2517",
"attack_anims": "400,400,401,400",
"name": "Mithril dagger(p++)",
"tradeable": "true",
"archery_ticket_price": "0",
@ -51937,6 +51948,7 @@
"equipment_slot": "3",
"grand_exchange_price": "4612",
"attack_audios": "2517,2517,2500,2517",
"attack_anims": "400,400,401,400",
"name": "Adamant dagger(p++)",
"tradeable": "true",
"archery_ticket_price": "0",
@ -51967,6 +51979,7 @@
"lendable": "true",
"grand_exchange_price": "5061",
"attack_audios": "2517,2517,2500,2517",
"attack_anims": "400,400,401,400",
"name": "Rune dagger(p++)",
"tradeable": "true",
"archery_ticket_price": "0",
@ -52032,6 +52045,7 @@
"equipment_slot": "3",
"grand_exchange_price": "4921",
"attack_audios": "2517,2517,2500,2517",
"attack_anims": "400,400,401,400",
"name": "Black dagger(p++)",
"tradeable": "true",
"archery_ticket_price": "0",
@ -60306,6 +60320,7 @@
"equipment_slot": "3",
"grand_exchange_price": "497",
"attack_audios": "2517,2517,2500,2517",
"attack_anims": "400,400,401,400",
"name": "White dagger(p)",
"tradeable": "true",
"archery_ticket_price": "0",
@ -60335,6 +60350,7 @@
"equipment_slot": "3",
"grand_exchange_price": "982",
"attack_audios": "2517,2517,2500,2517",
"attack_anims": "400,400,401,400",
"name": "White dagger(p+)",
"tradeable": "true",
"archery_ticket_price": "0",
@ -60364,6 +60380,7 @@
"equipment_slot": "3",
"grand_exchange_price": "8422",
"attack_audios": "2517,2517,2500,2517",
"attack_anims": "400,400,401,400",
"name": "White dagger(p++)",
"tradeable": "true",
"archery_ticket_price": "0",
@ -89019,7 +89036,7 @@
"id": "10383"
},
{
"requirements": "{1,70}-{4,40}",
"requirements": "{1,40}-{4,70}",
"ge_buy_limit": "2",
"examine": "Saradomin blessed dragonhide vambraces.",
"durability": null,
@ -90178,9 +90195,13 @@
"weight": "1.1",
"attack_speed": "5",
"weapon_interface": "2",
"equip_audio": "2229",
"render_anim": "2586",
"defence_anim": "397",
"equipment_slot": "3",
"attack_anims": "395,395,401,395",
"destroy_message": "I can obtain a replacement axe from the Burthorpe Slayer Master.",
"attack_audios": "2498,2498,2497,2498",
"name": "Blessed axe",
"tradeable": "false",
"archery_ticket_price": "0",
@ -130463,7 +130484,7 @@
"tradeable": "true",
"archery_ticket_price": "0",
"id": "14497",
"bonuses": "0,0,0,20,0,0,0,0,20,0,20,0,0,2,0"
"bonuses": "0,0,0,20,0,0,0,0,20,0,20,0,2,0,0"
},
{
"shop_price": "120000",
@ -130519,7 +130540,7 @@
"tradeable": "true",
"archery_ticket_price": "0",
"id": "14501",
"bonuses": "0,0,0,15,0,0,0,0,15,0,15,0,0,2,0"
"bonuses": "0,0,0,15,0,0,0,0,15,0,15,0,2,0,0"
},
{
"shop_price": "80000",

View file

@ -1095,6 +1095,10 @@
"region": "10829",
"id": "378"
},
{
"region": "10831",
"id": "393"
},
{
"region": "10833",
"id": "249"

View file

@ -2006,7 +2006,7 @@
"defence_animation": "6255",
"weakness": "0",
"slayer_exp": "23",
"poison_amount": "3",
"poison_amount": "15",
"magic_animation": "0",
"death_animation": "6256",
"name": "Poison Scorpion",
@ -2517,7 +2517,7 @@
"respawn_delay": "30",
"defence_animation": "5328",
"weakness": "2",
"poison_amount": "6",
"poison_amount": "30",
"magic_animation": "0",
"death_animation": "5329",
"name": "Poison spider",
@ -3330,7 +3330,7 @@
"respawn_delay": "50",
"defence_animation": "0",
"weakness": "8",
"poison_amount": "11",
"poison_amount": "55",
"magic_animation": "0",
"death_animation": "836",
"name": "Tribesman",
@ -8816,7 +8816,7 @@
"attack_level": "1"
},
{
"examine": "Big",
"examine": "Big, noisy, and scary looking!",
"melee_animation": "0",
"range_animation": "0",
"defence_animation": "0",
@ -10513,7 +10513,7 @@
"respawn_delay": "30",
"defence_animation": "5328",
"weakness": "2",
"poison_amount": "6",
"poison_amount": "30",
"magic_animation": "0",
"death_animation": "5329",
"name": "Poison spider",
@ -12353,7 +12353,7 @@
"defence_animation": "6227",
"weakness": "7",
"slayer_exp": "90",
"poison_amount": "4",
"poison_amount": "20",
"magic_animation": "0",
"death_animation": "6228",
"name": "Kalphite Soldier",
@ -12377,7 +12377,7 @@
"respawn_delay": "65",
"defence_animation": "6232",
"weakness": "7",
"poison_amount": "6",
"poison_amount": "30",
"magic_animation": "6223",
"death_animation": "6230",
"name": "Kalphite Guardian",
@ -12424,7 +12424,7 @@
"respawn_delay": "65",
"defence_animation": "6232",
"weakness": "7",
"poison_amount": "6",
"poison_amount": "30",
"magic_animation": "6223",
"death_animation": "6230",
"name": "Kalphite Guardian",
@ -12444,7 +12444,7 @@
"melee_animation": "6241",
"range_animation": "6241",
"attack_speed": "4",
"poisonous": "true",
"poisonous": "",
"magic_level": "150",
"respawn_delay": "0",
"defence_animation": "6232",
@ -13455,6 +13455,7 @@
"respawn_delay": "60",
"defence_animation": "0",
"weakness": "3",
"poison_amount": "30",
"magic_animation": "811",
"death_animation": "836",
"name": "Saradomin wizard",
@ -16454,6 +16455,7 @@
"defence_animation": "267",
"weakness": "1",
"slayer_exp": "22",
"poison_amount": "40",
"magic_animation": "266",
"death_animation": "265",
"name": "Cave crawler",
@ -16476,6 +16478,7 @@
"respawn_delay": "25",
"defence_animation": "267",
"slayer_exp": "22",
"poison_amount": "40",
"magic_animation": "266",
"death_animation": "265",
"name": "Cave crawler",
@ -16498,6 +16501,7 @@
"respawn_delay": "25",
"defence_animation": "267",
"slayer_exp": "22",
"poison_amount": "40",
"magic_animation": "266",
"death_animation": "265",
"name": "Cave crawler",
@ -16520,6 +16524,7 @@
"respawn_delay": "25",
"defence_animation": "267",
"slayer_exp": "22",
"poison_amount": "40",
"magic_animation": "266",
"death_animation": "265",
"name": "Cave crawler",
@ -19313,7 +19318,7 @@
"defence_animation": "0",
"weakness": "1",
"slayer_exp": "25",
"poison_amount": "3",
"poison_amount": "15",
"magic_animation": "0",
"death_animation": "1792",
"name": "Cave slime",
@ -20627,6 +20632,7 @@
"poisonous": "true",
"defence_animation": "1946",
"weakness": "7",
"poison_amount": "15",
"magic_animation": "0",
"death_animation": "5464",
"name": "Scarabs",
@ -20964,6 +20970,7 @@
"respawn_delay": "60",
"defence_animation": "0",
"weakness": "6",
"poison_amount": "15",
"magic_animation": "0",
"death_animation": "1946",
"name": "Scarab swarm",
@ -21678,7 +21685,7 @@
"range_animation": "0",
"combat_audio": "931,923,922",
"attack_speed": "5",
"respawn_delay": "60",
"respawn_delay": "0",
"defence_animation": "0",
"weakness": "7",
"slayer_exp": "30",
@ -25076,7 +25083,7 @@
"respawn_delay": "60",
"defence_animation": "0",
"weakness": "1",
"poison_amount": "11",
"poison_amount": "55",
"magic_animation": "0",
"death_animation": "278",
"name": "Bush snake",
@ -25095,7 +25102,7 @@
"poisonous": "true",
"respawn_delay": "60",
"defence_animation": "276",
"poison_amount": "11",
"poison_amount": "55",
"death_animation": "278",
"name": "Bush snake",
"defence_level": "1",
@ -25211,7 +25218,7 @@
"respawn_delay": "50",
"defence_animation": "0",
"weakness": "9",
"poison_amount": "11",
"poison_amount": "55",
"magic_animation": "0",
"death_animation": "836",
"name": "Tribesman",
@ -29571,6 +29578,7 @@
"respawn_delay": "60",
"defence_animation": "2937",
"weakness": "9",
"poison_amount": "40",
"magic_animation": "2936",
"death_animation": "2938",
"name": "Jogre Champion",
@ -29609,7 +29617,7 @@
"examine": "Champion of the jogres.",
"melee_animation": "5485",
"range_animation": "5493",
"poisonous": "true",
"poisonous": "",
"respawn_delay": "60",
"defence_animation": "5493",
"weakness": "9",
@ -32631,6 +32639,7 @@
"respawn_delay": "60",
"defence_animation": "0",
"weakness": "10",
"poison_amount": "35",
"magic_animation": "0",
"death_animation": "7249",
"name": "Wild jade vine",
@ -32652,6 +32661,7 @@
"respawn_delay": "60",
"defence_animation": "0",
"weakness": "10",
"poison_amount": "35",
"magic_animation": "0",
"death_animation": "7249",
"name": "Wild jade vine",
@ -32673,6 +32683,7 @@
"respawn_delay": "60",
"defence_animation": "0",
"weakness": "10",
"poison_amount": "35",
"magic_animation": "0",
"death_animation": "7249",
"name": "Wild jade vine",
@ -32694,6 +32705,7 @@
"respawn_delay": "60",
"defence_animation": "0",
"weakness": "10",
"poison_amount": "35",
"magic_animation": "0",
"death_animation": "7249",
"name": "Wild jade vine",
@ -33773,7 +33785,7 @@
"respawn_delay": "60",
"defence_animation": "6227",
"weakness": "6",
"poison_amount": "4",
"poison_amount": "20",
"magic_animation": "0",
"death_animation": "6228",
"name": "Kalphite Soldier",
@ -46891,15 +46903,15 @@
{
"examine": "A fiendish embodiment of water.",
"combat_style": "1",
"melee_animation": "1582",
"range_animation": "1582",
"melee_animation": "299",
"range_animation": "299",
"combat_audio": "3774,3773,3772",
"attack_speed": "4",
"magic_level": "105",
"defence_animation": "1581",
"defence_animation": "301",
"weakness": "4",
"magic_animation": "1582",
"death_animation": "1580",
"magic_animation": "299",
"death_animation": "300",
"name": "Waterfiend",
"defence_level": "128",
"poison_immune": "true",
@ -53854,11 +53866,11 @@
"examine": "A servant of the god Zamorak. ",
"melee_animation": "6945",
"attack_speed": "6",
"poisonous": "true",
"poisonous": "",
"respawn_delay": "150",
"weakness": "9",
"slayer_exp": "350",
"poison_amount": "16",
"poison_amount": "",
"magic_animation": "6945",
"death_animation": "6946",
"lifepoints": "255",
@ -54957,7 +54969,7 @@
"combat_style": "2",
"melee_animation": "811",
"range_animation": "811",
"poisonous": "true",
"poisonous": "",
"magic_level": "60",
"respawn_delay": "25",
"end_gfx": "76",
@ -58380,11 +58392,11 @@
"examine": "A ghost of a knight slain during the god wars.",
"melee_animation": "7441",
"range_animation": "7522",
"poisonous": "true",
"poisonous": "",
"magic_level": "80",
"defence_animation": "7443",
"slayer_exp": "143",
"poison_amount": "8",
"poison_amount": "",
"magic_animation": "7508",
"death_animation": "7442",
"name": "Revenant knight",
@ -58536,11 +58548,11 @@
"examine": "A ghost of a knight slain during the god wars.",
"melee_animation": "7441",
"range_animation": "7522",
"poisonous": "true",
"poisonous": "",
"magic_level": "80",
"defence_animation": "7443",
"slayer_exp": "143",
"poison_amount": "8",
"poison_amount": "",
"magic_animation": "7508",
"death_animation": "7442",
"name": "Revenant knight",
@ -58695,11 +58707,11 @@
"examine": "A ghost of a knight slain during the god wars.",
"melee_animation": "7441",
"range_animation": "7522",
"poisonous": "true",
"poisonous": "",
"magic_level": "80",
"defence_animation": "7443",
"slayer_exp": "143",
"poison_amount": "8",
"poison_amount": "",
"magic_animation": "7508",
"death_animation": "7442",
"name": "Revenant knight",
@ -58756,11 +58768,11 @@
"examine": "A ghost of a knight slain during the god wars.",
"melee_animation": "7441",
"range_animation": "7522",
"poisonous": "true",
"poisonous": "",
"magic_level": "80",
"defence_animation": "7443",
"slayer_exp": "143",
"poison_amount": "8",
"poison_amount": "",
"magic_animation": "7508",
"death_animation": "7442",
"name": "Revenant knight",
@ -58836,11 +58848,11 @@
"examine": "A ghost of a knight slain during the god wars.",
"melee_animation": "7441",
"range_animation": "7522",
"poisonous": "true",
"poisonous": "",
"magic_level": "80",
"defence_animation": "7443",
"slayer_exp": "143",
"poison_amount": "8",
"poison_amount": "",
"magic_animation": "7508",
"death_animation": "7442",
"name": "Revenant knight",
@ -59159,11 +59171,11 @@
"examine": "A ghost of a knight slain during the god wars.",
"melee_animation": "7441",
"range_animation": "7522",
"poisonous": "true",
"poisonous": "",
"magic_level": "80",
"defence_animation": "7443",
"slayer_exp": "143",
"poison_amount": "8",
"poison_amount": "",
"magic_animation": "7508",
"death_animation": "7442",
"name": "Revenant knight",
@ -59239,11 +59251,11 @@
"examine": "A ghost of a knight slain during the god wars.",
"melee_animation": "7441",
"range_animation": "7522",
"poisonous": "true",
"poisonous": "",
"magic_level": "80",
"defence_animation": "7443",
"slayer_exp": "143",
"poison_amount": "8",
"poison_amount": "",
"magic_animation": "7508",
"death_animation": "7442",
"name": "Revenant knight",
@ -59441,6 +59453,7 @@
"examine": "A ghost of an ork slain during the god wars.",
"melee_animation": "7411",
"range_animation": "7518",
"poisonous": "",
"magic_level": "70",
"defence_animation": "7413",
"magic_animation": "7505",
@ -59460,11 +59473,11 @@
"examine": "A ghost of a knight slain during the god wars.",
"melee_animation": "7441",
"range_animation": "7522",
"poisonous": "true",
"poisonous": "",
"magic_level": "80",
"defence_animation": "7443",
"slayer_exp": "143",
"poison_amount": "8",
"poison_amount": "",
"magic_animation": "7508",
"death_animation": "7442",
"name": "Revenant knight",
@ -59619,11 +59632,11 @@
"examine": "A ghost of a knight slain during the god wars.",
"melee_animation": "7441",
"range_animation": "7522",
"poisonous": "true",
"poisonous": "",
"magic_level": "80",
"defence_animation": "7443",
"slayer_exp": "143",
"poison_amount": "8",
"poison_amount": "",
"magic_animation": "7508",
"death_animation": "7442",
"name": "Revenant knight",
@ -59634,7 +59647,8 @@
"id": "6673",
"clue_level": "2",
"range_level": "80",
"attack_level": "80"
"attack_level": "80",
"prj_height": ""
},
{
"spawn_animation": "7426",
@ -59680,11 +59694,11 @@
"examine": "A ghost of a knight slain during the god wars.",
"melee_animation": "7441",
"range_animation": "7522",
"poisonous": "true",
"poisonous": "",
"magic_level": "80",
"defence_animation": "7443",
"slayer_exp": "143",
"poison_amount": "8",
"poison_amount": "",
"magic_animation": "7508",
"death_animation": "7442",
"name": "Revenant knight",
@ -60003,11 +60017,11 @@
"examine": "A ghost of a knight slain during the god wars.",
"melee_animation": "7441",
"range_animation": "7522",
"poisonous": "true",
"poisonous": "",
"magic_level": "80",
"defence_animation": "7443",
"slayer_exp": "143",
"poison_amount": "8",
"poison_amount": "",
"magic_animation": "7508",
"death_animation": "7442",
"name": "Revenant knight",
@ -60440,11 +60454,11 @@
"examine": "A ghost of a knight slain during the god wars.",
"melee_animation": "7441",
"range_animation": "7522",
"poisonous": "true",
"poisonous": "",
"magic_level": "80",
"defence_animation": "7443",
"slayer_exp": "143",
"poison_amount": "8",
"poison_amount": "",
"magic_animation": "7508",
"death_animation": "7442",
"name": "Revenant knight",
@ -60681,11 +60695,11 @@
"examine": "A ghost of a knight slain during the god wars.",
"melee_animation": "7441",
"range_animation": "7522",
"poisonous": "true",
"poisonous": "",
"magic_level": "80",
"defence_animation": "7443",
"slayer_exp": "143",
"poison_amount": "8",
"poison_amount": "",
"magic_animation": "7508",
"death_animation": "7442",
"name": "Revenant knight",
@ -60760,11 +60774,11 @@
"examine": "A ghost of a knight slain during the god wars.",
"melee_animation": "7441",
"range_animation": "7522",
"poisonous": "true",
"poisonous": "",
"magic_level": "80",
"defence_animation": "7443",
"slayer_exp": "143",
"poison_amount": "8",
"poison_amount": "",
"magic_animation": "7508",
"death_animation": "7442",
"name": "Revenant knight",
@ -63824,9 +63838,9 @@
"melee_animation": "8591",
"range_animation": "8594",
"combat_audio": "408,410,409",
"poisonous": "true",
"poisonous": "",
"defence_animation": "8592",
"poison_amount": "8",
"poison_amount": "",
"magic_animation": "8594",
"death_animation": "8593",
"name": "Revenant dragon",
@ -63845,9 +63859,9 @@
"melee_animation": "8591",
"range_animation": "8594",
"combat_audio": "408,410,409",
"poisonous": "true",
"poisonous": "",
"defence_animation": "8592",
"poison_amount": "8",
"poison_amount": "",
"magic_animation": "8594",
"death_animation": "8593",
"name": "Revenant dragon",
@ -64590,6 +64604,7 @@
"death_animation": "8756",
"name": "Bork",
"defence_level": "80",
"poison_immune": "true",
"lifepoints": "300",
"strength_level": "90",
"id": "7133",
@ -64707,6 +64722,7 @@
"name": "Bork",
"defence_level": "1",
"safespot": null,
"poison_immune": "true",
"lifepoints": "300",
"strength_level": "1",
"id": "7134",
@ -68962,13 +68978,13 @@
"examine": "A big, scary hand! ",
"melee_animation": "1802",
"attack_speed": "6",
"respawn_delay": "60",
"respawn_delay": "0",
"defence_animation": "1803",
"slayer_exp": "105",
"death_animation": "1804",
"name": "Wall Beast",
"defence_level": "38",
"movement_radius": "1",
"movement_radius": "0",
"safespot": null,
"lifepoints": "105",
"strength_level": "38",
@ -73958,46 +73974,57 @@
"id": "797"
},
{
"examine": "His job doesn't look very fun...",
"name": "Pierre",
"id": "807"
},
{
"examine": "He looks kind of stuck up...",
"name": "Hobbes",
"id": "808"
},
{
"examine": "She looks like she enjoys her job.",
"name": "Louisa",
"id": "809"
},
{
"examine": "She looks very nervous...",
"name": "Mary",
"id": "810"
},
{
"examine": "He looks like he spends a lot of time outdoor.",
"name": "Stanford",
"id": "811"
},
{
"examine": "She's dressed in a red top and green trousers.",
"name": "Anna",
"id": "814"
},
{
"examine": "He's dressed all in red.",
"name": "Bob",
"id": "815"
},
{
"examine": "She's wearing a blue top and red trousers.",
"name": "Carol",
"id": "816"
},
{
"examine": "He's dressed all in green.",
"name": "David",
"id": "817"
},
{
"examine": "She's wearing a green top and blue trousers.",
"name": "Elizabeth",
"id": "818"
},
{
"examine": "He's dressed all in blue.",
"name": "Frank",
"id": "819"
},

View file

@ -2351,14 +2351,46 @@
"npc_id": "805",
"loc_data": "{2936,3288,0,1,4}-"
},
{
"npc_id": "806",
"loc_data": "{2745,3576,1,0,4}-"
},
{
"npc_id": "807",
"loc_data": "{2750,3576,0,0,4}-"
},
{
"npc_id": "808",
"loc_data": "{2736,3575,0,1,1}-"
},
{
"npc_id": "809",
"loc_data": "{2734,3581,0,1,1}-"
},
{
"npc_id": "810",
"loc_data": "{2736,3576,1,1,1}-"
},
{
"npc_id": "811",
"loc_data": "{2731,3579,0,1,4}-"
},
{
"npc_id": "812",
"loc_data": "{2738,3473,0,0,1}-{2733,3473,0,0,1}-"
"loc_data": "{2741,3562,0,1,0}-"
},
{
"npc_id": "813",
"loc_data": "{2741,3552,0,1,1}-"
},
{
"npc_id": "820",
"loc_data": "{2697,3496,0,0,0}-"
},
{
"npc_id": "821",
"loc_data": "{2750,3580,0,1,0}-"
},
{
"npc_id": "822",
"loc_data": "{3302,9466,0,1,6}-"
@ -4863,6 +4895,10 @@
"npc_id": "2057",
"loc_data": "{2442,9436,2,1,0}-{2458,9413,2,1,0}-{2470,9435,2,1,0}-{2472,9460,2,1,0}-{2483,9413,2,1,0}-{2485,9447,2,1,0}-{2480,3046,0,1,0}-{2453,9393,2,1,0}-{2461,9403,2,1,0}-{2464,9380,2,1,0}-"
},
{
"npc_id": "2058",
"loc_data": "{3161,9547,0,0,7}-{3164,9556,0,0,7}-{3162,9574,0,0,7}-{3198,9554,0,0,7}-{3198,9572,0,0,7}-{3215,9560,0,0,7}-{3216,9588,0,0,7}-"
},
{
"npc_id": "2059",
"loc_data": "{2588,3088,0,1,3}-"
@ -6991,6 +7027,10 @@
"npc_id": "3288",
"loc_data": "{2987,3446,0,1,7}-{3034,3437,0,1,0}-"
},
{
"npc_id": "3293",
"loc_data": "{3113,3369,1,0,0}-{3122,3353,0,0,3}-{3124,3360,0,0,2}-{3115,3362,0,0,1}-"
},
{
"npc_id": "3294",
"loc_data": "{3014,3339,0,1,2}-"
@ -10459,6 +10499,38 @@
"npc_id": "6190",
"loc_data": "{1906,4270,0,1,0}-"
},
{
"npc_id": "6191",
"loc_data": "{2739,3577,0,1,0}-{2739,3579,1,1,0}-"
},
{
"npc_id": "6192",
"loc_data": "{2734,3575,0,1,0}-"
},
{
"npc_id": "6193",
"loc_data": "{2748,3559,0,1,0}-"
},
{
"npc_id": "6194",
"loc_data": "{2734,3581,1,1,0}-"
},
{
"npc_id": "6195",
"loc_data": "{2739,3581,0,1,0}-"
},
{
"npc_id": "6196",
"loc_data": "{2746,3581,1,1,0}-"
},
{
"npc_id": "6197",
"loc_data": "{2742,3577,0,1,0}-"
},
{
"npc_id": "6199",
"loc_data": "{2737,3466,0,1,0}-"
},
{
"npc_id": "6200",
"loc_data": "{2947,3366,0,0,1}-{2949,3366,0,0,1}-{2946,3366,0,0,1}-{2948,3366,0,0,1}-{2945,3366,0,0,1}-{3010,3353,0,0,1}-{3011,3353,0,0,1}-{3012,3353,0,0,1}-{3013,3353,0,0,1}-{3014,3353,0,0,1}-{3015,3353,0,0,1}-"
@ -12065,7 +12137,7 @@
},
{
"npc_id": "7823",
"loc_data": "{3161,9547,0,0,3}-{3164,9556,0,0,4}-{3162,9574,0,0,3}-{3198,9554,0,0,7}-{3198,9572,0,0,1}-{3215,9560,0,0,1}-{3216,9588,0,0,1}-"
"loc_data": ""
},
{
"npc_id": "7891",

View file

@ -1,103 +0,0 @@
package content.data.skill;
import core.game.node.entity.skill.Skills;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import core.game.world.repository.Repository;
/**
* Represents the skilling pets obtained randomly.
* @author Empathy
*
*/
public enum SkillingPets {
BABY_RED_CHINCHOMPA(new Item(14823), "Baby Chinchompa", Skills.HUNTER),
BABY_GREY_CHINCHOMPA(new Item(14824), "Baby Chinchompa", Skills.HUNTER),
BEAVER(new Item(14821), "Beaver", Skills.WOODCUTTING),
GOLEM(new Item(14822), "Rock Golem", Skills.MINING),
HERON(new Item(14827), "Heron", Skills.FISHING);
/**
* The pet item drop.
*/
private final Item pet;
/**
* The name.
*/
private final String name;
/**
* The skill.
*/
private final int skill;
/**
* Constructs a new {@code SkillingPets} object.
* @param skill The skill id.
* @param pet The pet item.
*/
SkillingPets(Item pet, String name, int skill) {
this.pet = pet;
this.name = name;
this.skill = skill;
}
/**
* Checks the pet drop.
* @param player The player.
* @param pet The pet drop to check.
*/
public static void checkPetDrop(Player player, SkillingPets pet) {
if (pet == null) {
return;
}
int defaultChance = 15000;
int newChance = (defaultChance / player.getSkills().getStaticLevel(pet.getSkill()) * 55);
int outOf = (newChance > defaultChance ? defaultChance : newChance);
int getChance = outOf;
if (getChance != 1) {
return;
}
if (player.hasItem(pet.getPet())) {
return;
}
if (player.getFamiliarManager().hasFamiliar() && player.getInventory().isFull()) {
return;
}
if (player.getFamiliarManager().hasFamiliar()) {
if (player.getFamiliarManager().getFamiliar().getName().equalsIgnoreCase(pet.getName())) {
return;
}
player.getInventory().add(pet.getPet());
player.sendNotificationMessage("You feel something weird sneaking into your backpack.");
} else {
player.getFamiliarManager().summon(pet.getPet(), true);
player.sendNotificationMessage("You have a funny feeling like you're being followed.");
}
Repository.sendNews(player.getUsername() + " has found a " + pet.getPet().getName() + "!");
}
/**
* @return the pet
*/
public Item getPet() {
return pet;
}
/**
* @return the pet name.
*/
public String getName() {
return name;
}
/**
* @return the skill.
*/
public int getSkill() {
return skill;
}
}

View file

@ -1,10 +1,13 @@
package content.global.bots
import content.data.Quests
import core.game.bots.*
import core.game.interaction.DestinationFlag
import core.game.interaction.IntType
import core.game.interaction.InteractionListeners
import core.game.interaction.MovementPulse
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import core.game.world.map.Location
import core.game.world.map.zone.ZoneBorders
import org.rs09.consts.Items
@ -24,6 +27,11 @@ class VarrockEssenceMiner : Script(){
when(state){
State.TO_ESSENCE -> {
bot.interfaceManager.close()
if (bot.bank.getAmount(Items.PURE_ESSENCE_7936) > 500) {
state = State.TELE_GE
return
}
if(!auburyZone.insideBorder(bot))
scriptAPI.walkTo(auburyZone.randomLoc)
else {
@ -99,7 +107,6 @@ class VarrockEssenceMiner : Script(){
scriptAPI.sellOnGE(Items.PURE_ESSENCE_7936)
state = State.TO_ESSENCE
}
}
}
@ -118,4 +125,10 @@ class VarrockEssenceMiner : Script(){
script.bot = SkillingBotAssembler().produce(SkillingBotAssembler.Wealth.POOR,bot.startLocation)
return script
}
init {
quests.add(Quests.RUNE_MYSTERIES)
inventory.add(Item(Items.ADAMANT_PICKAXE_1271))
skills[Skills.MINING] = 31
}
}

View file

@ -12,7 +12,6 @@ class MysticStaffEnchantInterface : InterfaceListener {
override fun defineInterfaceListeners() {
on(INTERFACE_332) { player, _, _, buttonID, _, _ ->
val staff = buttonMap[buttonID] ?: return@on true
val price = if (inEquipment(player, Items.SEERS_HEADBAND_14631)) 27000 else 40000
if (!inInventory(player, staff.basicID)) {
sendMessage(player, "You don't have a${if (StringUtils.isPlusN(getItemName(staff.basicID))) "n" else ""} ${getItemName(staff.basicID)} to enchant.")
@ -21,12 +20,12 @@ class MysticStaffEnchantInterface : InterfaceListener {
closeInterface(player)
if (!inInventory(player, Items.COINS_995, price)) {
sendNPCDialogue(player, NPCs.THORMAC_389, "I need ${String.format("%,d", price)} coins for materials. Come back when you have the money!", FacialExpression.NEUTRAL)
if (!inInventory(player, Items.COINS_995, 40000)) {
sendNPCDialogue(player, NPCs.THORMAC_389, "I need ${String.format("%,d", 40000)} coins for materials. Come back when you have the money!", FacialExpression.NEUTRAL)
return@on true
}
if (removeItem(player, Item(staff.basicID, 1)) && removeItem(player, Item(Items.COINS_995, price))) {
if (removeItem(player, Item(staff.basicID, 1)) && removeItem(player, Item(Items.COINS_995, 40000))) {
sendNPCDialogue(player, NPCs.THORMAC_389, "Just a moment... hang on... hocus pocus abra-cadabra... there you go! Enjoy your enchanted staff!", FacialExpression.NEUTRAL)
addItem(player, staff.enchantedID, 1)
}

View file

@ -93,7 +93,7 @@ public final class ChinchompaSwingHandler extends RangeSwingHandler {
}
}
entity.getSkills().addExperience(Skills.HITPOINTS, hit * 1.33, true);
if (entity.getProperties().getAttackStyle().getStyle() == WeaponInterface.STYLE_DEFENSIVE) {
if (entity.getProperties().getAttackStyle().getStyle() == WeaponInterface.STYLE_LONG_RANGE) {
entity.getSkills().addExperience(Skills.RANGE, hit * 2, true);
entity.getSkills().addExperience(Skills.DEFENCE, hit * 2, true);
} else {

View file

@ -17,6 +17,10 @@ class BattlestaffListener : InteractionListener {
onUseWith(IntType.ITEM, orbs, battlestaff) { player, used, with ->
val product = BattlestaffProduct.productMap[used.id] ?: return@onUseWith true
fun getMaxAmount(_unused: Int = 0): Int {
return min(amountInInventory(player, with.id), amountInInventory(player, used.id))
}
if (!hasLevelDyn(player, Skills.CRAFTING, product.minimumLevel)) {
sendMessage(player, "You need a Crafting level of ${product.minimumLevel} to make this.")
return@onUseWith true
@ -41,7 +45,7 @@ class BattlestaffListener : InteractionListener {
withItems(product.producedItemId)
create { _, amount ->
runTask(player, 2, amount) {
runTask(player, 2, min(amount, getMaxAmount())) {
if (amount < 1) return@runTask
if (removeItem(player, product.requiredOrbItemId) && removeItem(player, Items.BATTLESTAFF_1391)) {
@ -55,9 +59,7 @@ class BattlestaffListener : InteractionListener {
}
}
calculateMaxAmount { _ ->
min(amountInInventory(player, with.id), amountInInventory(player, used.id))
}
calculateMaxAmount(::getMaxAmount)
}
return@onUseWith true

View file

@ -5,6 +5,7 @@ import core.cache.def.impl.SceneryDefinition
import core.game.interaction.OptionHandler
import core.game.node.Node
import core.game.node.entity.player.Player
import core.game.node.entity.player.link.diary.DiaryType
import core.game.node.entity.skill.Skills
import core.plugin.Initializable
import core.plugin.Plugin
@ -42,6 +43,9 @@ class HealthChecker : OptionHandler() {
}
PatchType.FRUIT_TREE_PATCH -> {
patch.setCurrentState(patch.getCurrentState() - 14)
if (fPatch == FarmingPatch.BRIMHAVEN_FRUIT_TREE) {
player.achievementDiaryManager.finishTask(player, DiaryType.KARAMJA, 1, 12)
}
sendMessage(player, "You examine the tree for signs of disease and find that it is in perfect health.")
}
PatchType.SPIRIT_TREE_PATCH -> {

View file

@ -373,8 +373,6 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl
setCurrentState(getCurrentState() + 1)
isWatered = false
}
regrowIfTreeStump()
}
fun regrowIfTreeStump() {

View file

@ -0,0 +1,5 @@
package content.global.skill.farming
class Stump(val varbit: Int, val TTL: Long) {
}

View file

@ -0,0 +1,59 @@
package content.global.skill.farming.timers
import core.game.node.entity.Entity
import core.game.system.timer.*
import core.game.node.entity.player.Player
import content.global.skill.farming.*
import core.tools.ticksToSeconds
import java.util.concurrent.TimeUnit
import org.json.simple.*
class StumpGrowth : PersistTimer (1, "farming:stump", isSoft = true) {
val stumps = ArrayList<Stump>()
lateinit var player: Player
fun addStump(varbit: Int, ttl: Int){
stumps.add(
Stump(
varbit,
System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(ticksToSeconds(ttl).toLong())
)
)
}
override fun onRegister (entity: Entity) {
player = (entity as? Player)!!
}
override fun run (entity: Entity) : Boolean {
val removeList = ArrayList<Stump>()
for (stump in stumps) {
if (System.currentTimeMillis() > stump.TTL) {
FarmingPatch.patches[stump.varbit]?.getPatchFor(player)?.regrowIfTreeStump()
removeList.add(stump)
}
}
stumps.removeAll(removeList)
return stumps.isNotEmpty()
}
override fun save(root: JSONObject, entity: Entity) {
val stumpArray = JSONArray()
for(s in stumps){
val seed = JSONObject()
seed["patch"] = s.varbit
seed["ttl"] = s.TTL
stumpArray.add(seed)
}
root.put("stumps",stumpArray)
}
override fun parse(root: JSONObject, entity: Entity) {
(root["stumps"] as JSONArray).forEach {
val s = it as JSONObject
val id = s["patch"].toString().toInt()
val ttl = s["ttl"].toString().toLong()
stumps.add(Stump(id,ttl))
}
}
}

View file

@ -1,6 +1,5 @@
package content.global.skill.gather.fishing
import content.data.skill.SkillingPets
import content.global.skill.fishing.Fish
import content.global.skill.fishing.FishingOption
import content.global.skill.skillcapeperks.SkillcapePerks
@ -124,7 +123,6 @@ class FishingPulse(player: Player?, npc: NPC, private val option: FishingOption?
updateSkillTask()
}
player.dispatch(ResourceProducedEvent(fish!!.id, 1, node!!))
SkillingPets.checkPetDrop(player, SkillingPets.HERON)
val item = fish!!
if (isActive(SkillcapePerks.GREAT_AIM, player) && RandomFunction.random(100) <= 5) {
addItemOrDrop(player, item.id)

View file

@ -1,6 +1,5 @@
package content.global.skill.gather.mining
import content.data.skill.SkillingPets
import content.data.skill.SkillingTool
import content.global.skill.skillcapeperks.SkillcapePerks
import content.global.activity.shootingstar.StarBonus
@ -67,7 +66,6 @@ class MiningListener : InteractionListener {
rewardAmount = calculateRewardAmount(player, isEssence, reward) // calculate amount
player.dispatch(ResourceProducedEvent(reward, rewardAmount, node))
SkillingPets.checkPetDrop(player, SkillingPets.GOLEM) // roll for pet
// Reward mining experience
val experience = resource!!.experience * rewardAmount

View file

@ -3,7 +3,6 @@ package content.global.skill.gather.mining
import core.api.*
import core.game.event.ResourceProducedEvent
import core.cache.def.impl.ItemDefinition
import content.data.skill.SkillingPets
import core.game.node.Node
import core.game.node.entity.impl.Animator
import core.game.node.entity.npc.drop.DropFrequency
@ -132,7 +131,6 @@ class MiningSkillPulse(private val player: Player, private val node: Node) : Pul
rewardAmount = calculateRewardAmount(reward) // calculate amount
player.dispatch(ResourceProducedEvent(reward, rewardAmount, node))
SkillingPets.checkPetDrop(player, SkillingPets.GOLEM) // roll for pet
// Reward mining experience
val experience = resource!!.experience * rewardAmount

View file

@ -1,9 +1,9 @@
package content.global.skill.gather.woodcutting
import content.data.skill.SkillingPets
import content.data.skill.SkillingTool
import content.data.tables.BirdNest
import content.global.skill.farming.FarmingPatch.Companion.forObject
import content.global.skill.farming.timers.StumpGrowth
import content.global.skill.firemaking.Log
import content.global.skill.skillcapeperks.SkillcapePerks
import content.global.skill.skillcapeperks.SkillcapePerks.Companion.isActive
@ -72,7 +72,7 @@ class WoodcuttingListener : InteractionListener {
if (clockReady(player, Clocks.SKILLING)) {
animateWoodcutting(player)
if (!checkReward(player, resource, tool))
if (!checkReward(player, resource, tool) && !getAttribute(player, "instachop", false))
return delayClock(player, Clocks.SKILLING, 3)
val reward = resource.getReward()
@ -93,7 +93,9 @@ class WoodcuttingListener : InteractionListener {
).send()
//add woodcutting experience
player.getSkills().addExperience(Skills.WOODCUTTING, resource.getExperience())
rewardAmount = calculateRewardAmount(player, reward) // calculate amount
val experience: Double = calculateExperience(player, resource, rewardAmount)
player.getSkills().addExperience(Skills.WOODCUTTING, experience, true)
//nullcheck the fire, and only if it exists award the firemaking XP
val fire = Log.forId(reward)
@ -107,7 +109,6 @@ class WoodcuttingListener : InteractionListener {
if (reward > 0) {
rewardAmount = calculateRewardAmount(player, reward) // calculate amount
SkillingPets.checkPetDrop(player, SkillingPets.BEAVER) // roll for pet
//add experience
val experience: Double = calculateExperience(player, resource, rewardAmount)
@ -156,7 +157,7 @@ class WoodcuttingListener : InteractionListener {
//OSRS: https://oldschool.runescape.wiki/w/Woodcutting scroll down to the mechanics section
//RS3 : https://runescape.wiki/w/Woodcutting scroll down to the mechanics section, and expand the tree felling chances table
if (resource.getRespawnRate() > 0) {
if (RandomFunction.roll(8) || listOf(1, 2, 3, 4, 6).contains(resource.identifier.toInt())){
if (RandomFunction.roll(8) || listOf(1, 2, 3, 4, 6).contains(resource.identifier.toInt()) || getAttribute(player, "instachop", false)){
if (resource.isFarming()) {
val fPatch = forObject(node.asScenery())
if (fPatch != null) {
@ -168,6 +169,8 @@ class WoodcuttingListener : InteractionListener {
node.isActive = true
return@queueScript stopExecuting(player)
}
val stumps = getOrStartTimer <StumpGrowth> (player)
stumps.addStump(fPatch.varbit, resource.respawnDuration)
}
return true
}

View file

@ -8,7 +8,6 @@ import core.game.event.ResourceProducedEvent;
import core.cache.def.impl.ItemDefinition;
import core.game.container.impl.EquipmentContainer;
import core.game.dialogue.FacialExpression;
import content.data.skill.SkillingPets;
import core.game.node.entity.impl.Animator;
import core.game.node.entity.impl.Projectile;
import core.game.node.entity.player.Player;
@ -157,7 +156,6 @@ public class WoodcuttingSkillPulse extends Pulse {
if (reward > 0) {
reward = calculateReward(reward); // calculate rewards
rewardAmount = calculateRewardAmount(reward); // calculate amount
SkillingPets.checkPetDrop(player, SkillingPets.BEAVER); // roll for pet
//add experience
double experience = calculateExperience(resource.reward, rewardAmount);

View file

@ -1,6 +1,5 @@
package content.global.skill.hunter;
import content.data.skill.SkillingPets;
import core.game.node.entity.skill.SkillPulse;
import core.game.node.entity.skill.Skills;
import core.game.node.entity.player.Player;
@ -95,13 +94,6 @@ public final class TrapDismantlePulse extends SkillPulse<Scenery> {
if (wrapper.getType().getSettings().clear(wrapper, 1)) {
instance.deregister(wrapper);
if (wrapper.isCaught()) {
if (wrapper.getType().equals(Traps.BOX_TRAP)) {
for (int i : wrapper.getReward().getNpcIds()) {
if (i == 5080 || i == 5079) {
SkillingPets.checkPetDrop(player, i == 5080 ? SkillingPets.BABY_RED_CHINCHOMPA : SkillingPets.BABY_GREY_CHINCHOMPA);
}
}
}
player.getSkills().addExperience(Skills.HUNTER, wrapper.getReward().getExperience(), true);
}
player.getPacketDispatch().sendMessage("You dismantle the trap.");

View file

@ -1,6 +1,5 @@
package content.global.skill.hunter;
import content.data.skill.SkillingPets;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player;
import core.game.node.entity.skill.Skills;
@ -123,8 +122,4 @@ public class TrapNode {
return objectIds;
}
public SkillingPets getPet() {
return null;
}
}

View file

@ -21,6 +21,7 @@ import org.rs09.consts.Items
import org.rs09.consts.NPCs
import core.game.interaction.InteractionListener
import core.game.interaction.IntType
import core.game.node.entity.player.link.diary.DiaryType
import core.game.world.GameWorld
import org.rs09.consts.Sounds
@ -262,6 +263,7 @@ class PitfallListeners : InteractionListener {
}
on(GRAAHK_PIT, IntType.SCENERY, "dismantle") { player, node ->
lootCorpse(player, node as Scenery, 240.0, Items.GRAAHK_FUR_10099, Items.TATTY_GRAAHK_FUR_10097)
player.achievementDiaryManager.finishTask(player, DiaryType.KARAMJA, 1, 13)
sendMessage(player, "You've caught a horned graahk!")
return@on true
}

View file

@ -21,6 +21,7 @@ import core.game.node.scenery.Scenery
import core.game.system.command.Privilege
import core.game.system.config.NPCConfigParser
import core.game.system.task.Pulse
import core.game.system.timer.impl.PoisonImmunity
import core.game.world.map.Location
import core.game.world.map.RegionManager
import core.game.world.repository.Repository
@ -379,7 +380,7 @@ class LunarListeners : SpellListener("lunar"), Commands {
setInterfaceText(player, "Hitpoints : ${npc.definition.handlers[NPCConfigParser.LIFEPOINTS] ?: 0}", Components.DREAM_MONSTER_STAT_522, 2)
setInterfaceText(player, "Max hit : ${npc.getSwingHandler(false).calculateHit(npc, player, 1.0)}", Components.DREAM_MONSTER_STAT_522, 3)
val poisonStatus = if(npc.definition.handlers.getOrDefault(NPCConfigParser.POISON_IMMUNE,false) == true){
val poisonStatus = if(npc.isPoisonImmune){
"This creature is immune to poison."
} else "This creature is not immune to poison."
@ -437,7 +438,7 @@ class LunarListeners : SpellListener("lunar"), Commands {
if(playerEmpties.isEmpty()) {
sendMessage(player, "You have nothing in your inventory that this spell can humidify.")
return
throw IllegalStateException()
}
removeRunes(player)
@ -818,7 +819,10 @@ class LunarListeners : SpellListener("lunar"), Commands {
return@define
}
if(dmg != null) {
p.let { applyPoison(it, it, dmg) }
p.let {
removeTimer<PoisonImmunity>(it)
applyPoison(it, it, dmg)
}
} else {
sendMessage(player, "Damage must be an integer. Format:")
sendMessage(player, "::poison username damage")

View file

@ -16,7 +16,7 @@ class WaterfiendBehavior : NPCBehavior(*Tasks.WATERFIENDS.ids) {
true,
SwitchAttack(
CombatStyle.MAGIC.swingHandler,
Animation(1581, Priority.HIGH),
Animation(302, Priority.HIGH), // 299 = attack animation, 302 = idle animation. (authentic bug)
null,
null,
Projectile.create(
@ -33,7 +33,7 @@ class WaterfiendBehavior : NPCBehavior(*Tasks.WATERFIENDS.ids) {
),
SwitchAttack(
CombatStyle.RANGE.swingHandler,
Animation(1581, Priority.HIGH),
Animation(302, Priority.HIGH), // 299 = attack animation, 302 = idle animation. (authentic bug)
null,
null,
Projectile.create(

View file

@ -28,7 +28,6 @@ import java.util.Map;
* Handles the lumbridge dungeon.
* @author Vexia
*/
@Initializable
public final class LumbridgeDungeon extends MapZone implements Plugin<Object> {
/**

View file

@ -55,31 +55,6 @@ public enum Pets {
*/
TERRIER(12512, 12513, -1, 6958, 6959, -1, 0.0033333333333333, 4, 2132, 2134, 2136, 2138, 10816, 9986, 9978, 526), TERRIER_1(12700, 12701, -1, 7237, 7238, -1, 0.0033333333333333, 4, 2132, 2134, 2136, 2138, 10816, 9986, 9978, 526), TERRIER_2(12702, 12703, -1, 7239, 7240, -1, 0.0033333333333333, 4, 2132, 2134, 2136, 2138, 10816, 9986, 9978, 526),
/**
* A creeping hand pet.
*/
//CREEPING_HAND(14652, -1, -1, 8619, -1, -1, 0.0033333333333333, 4, 1059),
/**
* Minitrice pet.
*/
//MINITRICE(14653, -1, -1, 8620, -1, -1, 0.0033333333333333, 4, 225),
/**
* Baby basilisk pet.
*/
//BABY_BASILISK(14654, -1, -1, 8621, -1, -1, 0.0033333333333333, 4, 221),
/**
* Baby kurask pet.
*/
//BABY_KURASK(14655, -1, -1, 8622, -1, -1, 0.0033333333333333, 4, 526),
/**
* Abyssal minion pet.
*/
//ABYSSAL_MINION(14651, -1, -1, 8624, -1, -1, 0.0033333333333333, 4, 592),
/**
* Gecko pet.
*/

View file

@ -85,7 +85,7 @@ public final class ShipCharter {
*/
public static int getCost(final Player player, Destination destination) {
int cost = destination.getCost(player, destination);
if (player.getQuestRepository().isComplete(Quests.CABIN_FEVER)) {
if (hasRequirement(player, Quests.CABIN_FEVER)) {
cost -= Math.round((cost / 2.));
}
if (player.getEquipment().containsItem(RING_OF_CHAROS)) {
@ -139,7 +139,7 @@ public final class ShipCharter {
* @author 'Vexia
*/
public enum Destination {
CATHERBY(Location.create(2792, 3417, 1), 25, new int[] { 480, 0, 480, 625, 1600, 3250, 1000, 1600, 3200, 3400 }, Location.create(2797, 3414, 0), 3, 14),
CATHERBY(Location.create(2792, 3417, 1), 25, new int[] { 480, 0, 480, 1250, 1600, 3250, 1000, 1600, 3200, 3400 }, Location.create(2797, 3414, 0), 3, 14),
PORT_PHASMATYS(Location.create(3705, 3503, 1), 24, new int[] { 3650, 3250, 1850, 0, 0, 0, 2050, 1850, 3200, 1100 }, Location.create(3702, 3502, 0), 2, 13) {
@Override
public boolean checkTravel(Player player) {
@ -152,7 +152,7 @@ public final class ShipCharter {
return requireQuest(player, Quests.DRAGON_SLAYER, "to go there.");
}
},
BRIMHAVEN(Location.create(2763, 3238, 1), 28, new int[] { 0, 480, 480, 925, 400, 3650, 1600, 400, 3200, 3800 }, Location.create(2760, 3238, 0), 6, 17){
BRIMHAVEN(Location.create(2763, 3238, 1), 28, new int[] { 0, 480, 480, 1950, 400, 3650, 1600, 400, 3200, 3800 }, Location.create(2760, 3238, 0), 6, 17){
@Override
public int getCost(Player player, Destination destination) {
boolean hasGloves = DiaryType.KARAMJA.hasRewardEquipment(player);
@ -160,7 +160,7 @@ public final class ShipCharter {
return super.getCost(player, destination);
}
},
PORT_SARIM(Location.create(3038, 3189, 1), 30, new int[] { 1600, 1000, 0, 325, 1280, 650, 1280, 400, 3200, 1400 }, Location.create(3039, 3193, 0), 8, 19){
PORT_SARIM(Location.create(3038, 3189, 1), 30, new int[] { 1600, 1000, 0, 650, 1280, 650, 1280, 400, 3200, 1400 }, Location.create(3039, 3193, 0), 8, 19){
@Override
public int getCost(Player player, Destination destination) {
boolean hasGloves = DiaryType.KARAMJA.hasRewardEquipment(player);
@ -168,14 +168,14 @@ public final class ShipCharter {
return super.getCost(player, destination);
}
},
PORT_TYRAS(Location.create(2142, 3122, 0), 23, new int[] { 3200, 3200, 3200, 1600, 3200, 3200, 3200, 3200, 0, 3200 }, Location.create(2143, 3122, 0), 1, 12) {
PORT_TYRAS(Location.create(2142, 3122, 0), 23, new int[] { 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 0, 3200 }, Location.create(2143, 3122, 0), 1, 12) {
@Override
public boolean checkTravel(Player player) {
return hasRequirement(player, Quests.REGICIDE);
}
},
KARAMJA(Location.create(2957, 3158, 1), 27, new int[] { 200, 480, 0, 225, 400, 1850, 0, 200, 3200, 2000 }, Location.create(2954, 3156, 0), 5, 16) {
KARAMJA(Location.create(2957, 3158, 1), 27, new int[] { 200, 480, 0, 450, 400, 1850, 0, 200, 3200, 2000 }, Location.create(2954, 3156, 0), 5, 16) {
@Override
public int getCost(Player player, Destination destination) {
boolean hasGloves = DiaryType.KARAMJA.hasRewardEquipment(player);
@ -183,7 +183,7 @@ public final class ShipCharter {
return super.getCost(player, destination);
}
},
PORT_KHAZARD(Location.create(2674, 3141, 1), 29, new int[] { 1600, 1000, 0, 325, 180, 650, 1280, 400, 3200, 1400 }, Location.create(2674, 3144, 0), 7, 18){
PORT_KHAZARD(Location.create(2674, 3141, 1), 29, new int[] { 1600, 1000, 0, 2050, 180, 650, 1280, 400, 3200, 1400 }, Location.create(2674, 3144, 0), 7, 18){
@Override
public int getCost(Player player, Destination destination) {
boolean hasGloves = DiaryType.KARAMJA.hasRewardEquipment(player);
@ -191,14 +191,14 @@ public final class ShipCharter {
return super.getCost(player, destination);
}
},
SHIPYARD(Location.create(3001, 3032, 0), 26, new int[] { 400, 1600, 200, 225, 720, 1850, 400, 0, 3200, 900 }, Location.create(3001, 3032, 0), 4, 15) {
SHIPYARD(Location.create(3001, 3032, 0), 26, new int[] { 400, 1600, 200, 450, 720, 1850, 400, 0, 3200, 900 }, Location.create(3001, 3032, 0), 4, 15) {
@Override
public boolean checkTravel(Player player) {
return requireQuest(player, Quests.THE_GRAND_TREE, "to go there.");
}
},
OO_GLOG(Location.create(2623, 2857, 0), 33, new int[] { 300, 3400, 2000, 550, 5000, 2800, 1400, 900, 3200, 0}, Location.create(2622, 2857, 0), 11, 22),
MOS_LE_HARMLESS(Location.create(3671, 2931, 0), 31, new int[] { 725, 625, 1025, 0, 1025, 0, 325, 275, 1600, 500 }, Location.create(3671, 2933, 0), 9, 20) {
OO_GLOG(Location.create(2623, 2857, 0), 33, new int[] { 300, 3400, 2000, 1100, 5000, 2800, 1400, 900, 3200, 0}, Location.create(2622, 2857, 0), 11, 22),
MOS_LE_HARMLESS(Location.create(3671, 2931, 0), 31, new int[] { 1550, 1250, 2050, 0, 2050, 0, 650, 550, 3200, 1000 }, Location.create(3671, 2933, 0), 9, 20) {
@Override
public boolean checkTravel(Player player) {
return hasRequirement(player, Quests.CABIN_FEVER);

View file

@ -13,7 +13,6 @@ import org.rs09.consts.Items
import core.game.interaction.InteractionListener
import core.game.interaction.IntType
import core.api.*
import java.util.*
/**
* Handles repairing and climbing of the 3 beacon shortcuts needed to access them
@ -55,8 +54,8 @@ class AFURepairClimbHandler : InteractionListener {
private fun repair(player: Player,rco: RepairClimbObject){
if (rco == RepairClimbObject.TEMPLE){
// You can do this 2 different ways
val hasSmithingLevel = getDynLevel(player, Skills.SMITHING) >= 70
val hasConstructionLevel = getDynLevel(player, Skills.CONSTRUCTION) >= 59
val hasSmithingLevel = getStatLevel(player, Skills.SMITHING) >= 70
val hasConstructionLevel = getStatLevel(player, Skills.CONSTRUCTION) >= 59
if (!hasConstructionLevel && !hasSmithingLevel){
sendDialogue(player, "You need level 70 smithing or 59 construction for this.")
@ -93,8 +92,8 @@ class AFURepairClimbHandler : InteractionListener {
}
val skill = rco.levelRequirement?.first ?: 0
val level = rco.levelRequirement?.second ?: 0
if(player.skills.getLevel(skill) < level){
player.dialogueInterpreter.sendDialogue("You need level $level ${Skills.SKILL_NAME[skill]} for this.")
if(getStatLevel(player, skill) < level){
sendDialogue(player, "You need level $level ${Skills.SKILL_NAME[skill]} for this.")
return
}
@ -102,40 +101,37 @@ class AFURepairClimbHandler : InteractionListener {
val requiredItems = when(rco){
RepairClimbObject.DEATH_PLATEAU -> {
arrayOf(Item(Items.PLANK_960,2))
Item(Items.PLANK_960,2)
}
RepairClimbObject.BURTHORPE -> {
arrayOf(Item(Items.IRON_BAR_2351,2))
Item(Items.IRON_BAR_2351,2)
}
RepairClimbObject.GWD -> {
requiresNeedle = true
arrayOf(Item(Items.JUTE_FIBRE_5931,3))
Item(Items.JUTE_FIBRE_5931,3)
}
else -> return
}
if(requiresNeedle){
if(player.inventory.containsItem(Item(Items.NEEDLE_1733)) && player.inventory.containItems(*requiredItems.map { it.id }.toIntArray())) {
player.inventory.remove(*requiredItems)
if (Random().nextBoolean()) player.inventory.remove(Item(Items.NEEDLE_1733))
} else {
player.dialogueInterpreter.sendDialogue("You need a needle and ${requiredItems.map { "${it.amount} ${it.name.lowercase()}s" }.toString().replace("[","").replace("]","")} for this.")
if (!inInventory(player, Items.NEEDLE_1733) || !removeItem(player, requiredItems)) {
sendDialogue(player, "You need a needle and ${requiredItems.amount} ${requiredItems.name.lowercase()}s for this.")
return
}
} else {
if(player.inventory.containsItem(Item(Items.HAMMER_2347)) && player.inventory.containItems(*requiredItems.map { it.id }.toIntArray())) {
if(inInventory(player, Items.HAMMER_2347) && inInventory(player, requiredItems.id, requiredItems.amount)) {
val nails = NailType.get(player,4)
if(nails == null && rco == RepairClimbObject.DEATH_PLATEAU){
player.dialogueInterpreter.sendDialogue("You need 4 nails for this.")
sendDialogue(player, "You need 4 nails for this.")
return
} else if (rco == RepairClimbObject.DEATH_PLATEAU){
player.inventory.remove(Item(nails.itemId,4))
removeItem(player, Item(nails.itemId,4))
}
player.inventory.remove(*requiredItems)
removeItem(player, requiredItems)
} else {
player.dialogueInterpreter.sendDialogue("You need a hammer and ${requiredItems.map { "${it.amount} ${it.name.lowercase()}s" }.toString().replace("[","").replace("]","")} for this.")
sendDialogue(player, "You need a hammer and ${requiredItems.amount} ${requiredItems.name.lowercase()}s for this.")
return
}
}

View file

@ -73,7 +73,7 @@ public final class GWDTsutsarothSwingHandler extends CombatSwingHandler {
hit = RandomFunction.random(max);
state.setMaximumHit(max);
if (style == CombatStyle.MELEE) {
applyPoison(victim, entity, 16);
applyPoison(victim, entity, 80);
}
if (special) {
((Player) victim).getSkills().decrementPrayerPoints((double) hit / 2);

View file

@ -2,6 +2,7 @@ package content.region.desert.bandits.handlers
import core.api.God
import core.api.hasGodItem
import core.api.inEquipment
import core.game.node.entity.Entity
import core.game.node.entity.combat.BattleState
import core.game.node.entity.npc.AbstractNPC
@ -9,6 +10,7 @@ import core.game.node.entity.player.Player
import core.game.world.map.Location
import core.game.world.map.RegionManager
import core.plugin.Initializable
import org.rs09.consts.Items
import org.rs09.consts.NPCs
@Initializable
@ -28,7 +30,7 @@ class BanditNPC(id: Int = NPCs.BANDIT_1926, location: Location? = null) : Abstra
sendChat("Time to die, Saradominist filth!")
attack(player)
break
} else if (hasGodItem(player, God.ZAMORAK)) {
} else if (hasGodItem(player, God.ZAMORAK) || inEquipment(player, Items.DAGONHAI_HAT_14499) || inEquipment(player, Items.DAGONHAI_ROBE_TOP_14497) || inEquipment(player, Items.DAGONHAI_ROBE_BOTTOM_14501)) {
sendChat("Prepare to suffer, Zamorakian scum!")
attack(player)
break

View file

@ -14,8 +14,23 @@ import org.rs09.consts.Items
import org.rs09.consts.NPCs
class DamisBehavior : NPCBehavior(NPCs.DAMIS_1974, NPCs.DAMIS_1975) {
private var disappearing = false
var clearTime = 0
override fun tick(self: NPC): Boolean {
if (disappearing) {
return true
}
val player: Player? = getAttribute<Player?>(self, "target", null)
if (player == null || !self.location.withinDistance(self.properties.spawnLocation, self.walkRadius)) {
if (player != null && !disappearing) {
disappearing = true
sendMessage(player, "Damis has vanished once more into the shadows...")
removeAttribute(player, DesertTreasure.attributeDamisInstance)
}
poofClear(self)
}
return true
}
override fun canBeAttackedBy(self: NPC, attacker: Entity, style: CombatStyle, shouldSendMessage: Boolean): Boolean {
if (attacker is Player) {
@ -27,19 +42,6 @@ class DamisBehavior : NPCBehavior(NPCs.DAMIS_1974, NPCs.DAMIS_1975) {
return false
}
override fun tick(self: NPC): Boolean {
val player: Player? = getAttribute<Player?>(self, "target", null)
if (clearTime++ > 800) {
clearTime = 0
if (player != null) {
sendMessage(player, "Damis has vanished once more into the shadows...")
removeAttribute(player, DesertTreasure.attributeDamisInstance)
}
poofClear(self)
}
return true
}
override fun beforeDamageReceived(self: NPC, attacker: Entity, state: BattleState) {
if (attacker is Player) {
if (state.estimatedHit + Integer.max(state.secondaryHit, 0) >= self.skills.lifepoints && self.id == NPCs.DAMIS_1974) {
@ -65,8 +67,6 @@ class DamisBehavior : NPCBehavior(NPCs.DAMIS_1974, NPCs.DAMIS_1975) {
}
}
override fun onDeathFinished(self: NPC, killer: Entity) {
if (killer is Player) {
if (self.id == NPCs.DAMIS_1975) {

View file

@ -20,8 +20,7 @@ import core.tools.END_DIALOGUE
import org.rs09.consts.NPCs
class DessousMeleeBehavior : NPCBehavior(NPCs.DESSOUS_1914, NPCs.DESSOUS_1915) {
var clearTime = 0
private var disappearing = false;
override fun canBeAttackedBy(self: NPC, attacker: Entity, style: CombatStyle, shouldSendMessage: Boolean): Boolean {
if (attacker is Player) {
@ -34,12 +33,24 @@ class DessousMeleeBehavior : NPCBehavior(NPCs.DESSOUS_1914, NPCs.DESSOUS_1915) {
}
override fun tick(self: NPC): Boolean{
if (disappearing) {
return true
}
val player: Player? = getAttribute<Player?>(self, "target", null)
if (player == null || !self.location.withinDistance(self.properties.spawnLocation, self.walkRadius)) {
if (player != null && !disappearing) {
disappearing = true
sendMessage(player, "Dessous returns to his grave, bored of toying with you.")
removeAttribute(player, DesertTreasure.attributeDessousInstance)
}
poofClear(self)
}
// Dessous just continually hisses independently of projectile fires.
if (self.id == NPCs.DESSOUS_1915 && self.properties.combatPulse.isInCombat) {
animate(self, Animation(1914))
}
// This is probably the prayer flicking nonsense.
val player: Player? = getAttribute<Player?>(self, "target", null)
if (self.id == NPCs.DESSOUS_1914 && player != null && player.prayer.get(PrayerType.PROTECT_FROM_MELEE)) {
self.transform(NPCs.DESSOUS_1915)
Graphics.send(Graphics(86), self.location)
@ -47,16 +58,7 @@ class DessousMeleeBehavior : NPCBehavior(NPCs.DESSOUS_1914, NPCs.DESSOUS_1915) {
self.transform(NPCs.DESSOUS_1914)
Graphics.send(Graphics(86), self.location)
}
if (clearTime++ > 800) {
self.transform(NPCs.DESSOUS_1914)
clearTime = 0
if (player != null) {
removeAttribute(player, DesertTreasure.attributeDessousInstance)
sendMessage(player, "Dessous returns to his grave, bored of toying with you.")
}
poofClear(self)
}
return false
return true
}
override fun getSwingHandlerOverride(self: NPC, original: CombatSwingHandler): CombatSwingHandler {

View file

@ -261,5 +261,4 @@ class ShadowDungeonAttack : MapArea {
}
}
}
}

View file

@ -14,8 +14,7 @@ import org.rs09.consts.Items
import org.rs09.consts.NPCs
class FareedBehavior : NPCBehavior(NPCs.FAREED_1977) {
var clearTime = 0
private var disappearing = false
override fun canBeAttackedBy(self: NPC, attacker: Entity, style: CombatStyle, shouldSendMessage: Boolean): Boolean {
if (attacker is Player) {
@ -28,10 +27,13 @@ class FareedBehavior : NPCBehavior(NPCs.FAREED_1977) {
}
override fun tick(self: NPC): Boolean {
if (disappearing) {
return true
}
val player: Player? = getAttribute<Player?>(self, "target", null)
if (clearTime++ > 800) {
clearTime = 0
if (player != null) {
if (player == null || !self.location.withinDistance(self.properties.spawnLocation, self.walkRadius)) {
if (player != null && !disappearing) {
disappearing = true
sendMessage(player, "Fareed has lost interest in you, and returned to his flames.")
removeAttribute(player, DesertTreasure.attributeFareedInstance)
}
@ -50,14 +52,14 @@ class FareedBehavior : NPCBehavior(NPCs.FAREED_1977) {
if (victim is Player) {
if (!inEquipment(victim, Items.ICE_GLOVES_1580)) {
val weapon = getItemFromEquipment(victim, EquipmentSlot.WEAPON)
if(weapon != null) {
if (weapon != null) {
EquipHandler.unequip(victim, EquipmentContainer.SLOT_WEAPON, weapon.id)
sendMessage(victim, "The heat from the warrior causes you to drop your weapon.")
}
// val weapon = getItemFromEquipment(victim, EquipmentSlot.WEAPON)
// if(weapon != null && removeItem(victim, weapon.id, Container.EQUIPMENT)) {
// addItemOrDrop(victim, weapon.id)
// }
sendMessage(victim, "The heat from the warrior causes you to drop your weapon.")
}
}
}
@ -72,5 +74,4 @@ class FareedBehavior : NPCBehavior(NPCs.FAREED_1977) {
}
}
}
}

View file

@ -14,8 +14,7 @@ import org.rs09.consts.NPCs
// https://www.youtube.com/watch?v=xeu6Ncmt1fY
class KamilBehavior : NPCBehavior(NPCs.KAMIL_1913) {
var clearTime = 0
private var disappearing = false
override fun canBeAttackedBy(self: NPC, attacker: Entity, style: CombatStyle, shouldSendMessage: Boolean): Boolean {
if (attacker is Player) {
@ -28,10 +27,13 @@ class KamilBehavior : NPCBehavior(NPCs.KAMIL_1913) {
}
override fun tick(self: NPC): Boolean {
if (disappearing) {
return true
}
val player: Player? = getAttribute<Player?>(self, "target", null)
if (clearTime++ > 800) {
clearTime = 0
if (player != null) {
if (player == null || !self.location.withinDistance(self.properties.spawnLocation, (self.walkRadius*1.5).toInt())) {
if (player != null && !disappearing) {
disappearing = true
sendMessage(player, "Kamil vanishes on an icy wind...")
removeAttribute(player, DesertTreasure.attributeKamilInstance)
}
@ -64,16 +66,19 @@ class KamilCombatHandler: MultiSwingHandler(
// This is following RevenantCombatHandler.java, no idea if this is good.
// I can't be bothered to fix fucking frozen. The player can hit through frozen. What the fuck is frozen for then, to glue his fucking legs???
if (RandomFunction.roll(3) && !hasTimerActive(victim, "frozen") && !hasTimerActive(victim, "frozen:immunity")) {
sendChat(entity as NPC, "Sallamakar Ro!") // Salad maker roll.
impact(victim, 5)
impact(victim, 5)
registerTimer(victim, spawnTimer("frozen", 7, true))
sendMessage(victim, "You've been frozen!")
sendChat(entity as NPC, "Sallamakar Ro!") // Salad maker roll.
// FIXME: before the below vfx hits, there should be another one that looks kinda like a wind wave exploding at the player's feet. Hope somebody finds the id.
sendGraphics(539, victim.location)
victim.properties.combatPulse.stop() // Force the victim to stop fighting. Whatever.
// Audio?
// FIXME: sfx
}else {
animate(entity!!, Animation(440))
}
}
super.impact(entity, victim, state)
}
}
}

View file

@ -1,19 +1,20 @@
package content.region.fremennik.rellekka.quest.thefremenniktrials
import core.api.addItem
import core.api.dumpContainer
import core.api.getQuestStage
import core.api.removeItem
import core.game.node.entity.player.Player
import core.game.node.entity.player.link.diary.DiaryType
import core.plugin.Initializable
import core.tools.RandomFunction
import core.tools.END_DIALOGUE
import kotlin.random.Random
import content.data.Quests
import core.api.*
import core.game.dialogue.DialoguePlugin
import core.game.dialogue.FacialExpression
import core.game.node.entity.player.link.IronmanMode
import org.rs09.consts.Items
import org.rs09.consts.NPCs
@Initializable
class PeerTheSeerDialogue(player: Player? = null) : core.game.dialogue.DialoguePlugin(player) {
class PeerTheSeerDialogue(player: Player? = null) : DialoguePlugin(player) {
val predictionOne = arrayOf("one","two","three","four","five","six","seven","eight","ten")
val predictionTwo = arrayOf("black","blue","brown","cyan","green","pink","purple","red","yellow")
val predictionThree = arrayOf("fire giant","ghosts","giant","goblin","green dragon","hobgoblin","lesser demon","moss giant","ogre","zombie")
@ -31,232 +32,230 @@ class PeerTheSeerDialogue(player: Player? = null) : core.game.dialogue.DialogueP
override fun open(vararg args: Any?): Boolean {
if(player.inventory.contains(3710,1)){
playerl(core.game.dialogue.FacialExpression.HAPPY,"Can I have a weather forecast now please?")
playerl(FacialExpression.HAPPY,"Can I have a weather forecast now please?")
stage = 15
return true
}
else if(player.inventory.contains(3705,1)){
playerl(core.game.dialogue.FacialExpression.ASKING,"So, about this forecast...")
playerl(FacialExpression.ASKING,"So, about this forecast...")
stage = 20
return true
}
else if(player.getAttribute("sigmundreturning",false) == true){
playerl(core.game.dialogue.FacialExpression.ASKING,"I've got an item to trade but I don't know if it's for you.")
playerl(FacialExpression.ASKING,"I've got an item to trade but I don't know if it's for you.")
stage = 26
return true
}
else if(player.getAttribute("sigmund-steps", 0) == 10){
playerl(core.game.dialogue.FacialExpression.ASKING,"I don't suppose you have any idea where I could find a brave and powerful warrior to act as a bodyguard?")
playerl(FacialExpression.ASKING,"I don't suppose you have any idea where I could find a brave and powerful warrior to act as a bodyguard?")
stage = 8
return true
}
else if(player.getAttribute("sigmund-steps", 0) == 9){
playerl(core.game.dialogue.FacialExpression.ASKING,"I don't suppose you have any idea where I could find a weather forecast from the Fremennik Seer do you?")
playerl(FacialExpression.ASKING,"I don't suppose you have any idea where I could find a weather forecast from the Fremennik Seer do you?")
stage = 1
return true
}
else if(player.getAttribute("PeerStarted",false) && !player.inventory.isEmpty || !player.equipment.isEmpty){
npcl(core.game.dialogue.FacialExpression.SAD,"Uuuh... What was that dark presence I felt?")
else if(player.getAttribute("PeerStarted",false) && !(player.inventory.isEmpty && player.equipment.isEmpty)){
npcl(FacialExpression.SAD,"Uuuh... What was that dark presence I felt?")
stage = 100
return true
}
else if(player.getAttribute("PeerStarted",false) && player.inventory.isEmpty && player.equipment.isEmpty){
npcl(core.game.dialogue.FacialExpression.SAD,"Uuuh... What was that dark presence I felt?")
npcl(FacialExpression.SAD,"Uuuh... What was that dark presence I felt?")
stage = 110
return true
}
else if (getQuestStage(player, Quests.THE_FREMENNIK_TRIALS) > 0 && player.getAttribute("fremtrials:peer-vote",false)) {
npcl(core.game.dialogue.FacialExpression.SAD,"Uuuh... What was that dark presence I felt?")
npcl(FacialExpression.SAD,"Uuuh... What was that dark presence I felt?")
stage = 120
return true
}
else if(player.questRepository.isComplete(Quests.THE_FREMENNIK_TRIALS)){
npcl(core.game.dialogue.FacialExpression.SAD,"Uuuh... What was that dark presence I felt?")
npcl(FacialExpression.SAD,"Uuuh... What was that dark presence I felt?")
stage = 150
return true
}
else if(getQuestStage(player, Quests.THE_FREMENNIK_TRIALS) > 0){
npcl(core.game.dialogue.FacialExpression.SAD,"Uuuh... What was that dark presence I felt?")
npcl(FacialExpression.SAD,"Uuuh... What was that dark presence I felt?")
stage = 50
return true
}
if (getQuestStage(player, Quests.THE_FREMENNIK_TRIALS) == 0) {
npc(core.game.dialogue.FacialExpression.SAD,"Uuuh... What was that dark presence I felt?").also { stage = 300 }
npc(FacialExpression.SAD,"Uuuh... What was that dark presence I felt?").also { stage = 300 }
}
return true
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
when(stage){
1 -> npcl(core.game.dialogue.FacialExpression.ANNOYED,"Er.... Yes, because I AM the Fremennik Seer.").also { stage++ }
2 -> playerl(core.game.dialogue.FacialExpression.ASKING,"Can I have a weather forecast then please?").also { stage++ }
3 -> npcl(core.game.dialogue.FacialExpression.THINKING,"You require a divination of the weather? This is a simple matter for me, but I will require something in return from you for this small service.").also { stage++ }
4 -> playerl(core.game.dialogue.FacialExpression.ASKING,"I knew you were going to say that...").also { stage++ }
5 -> npcl(core.game.dialogue.FacialExpression.HAPPY,"Do not fret, outerlander; it is a fairly simple matter. I require a bodyguard for protection. Find someone willing to offer me this service.").also { stage++ }
6 -> playerl(core.game.dialogue.FacialExpression.ASKING,"That's all?").also { stage++ }
7 -> npcl(core.game.dialogue.FacialExpression.HAPPY,"That is all.").also {
1 -> npcl(FacialExpression.ANNOYED,"Er.... Yes, because I AM the Fremennik Seer.").also { stage++ }
2 -> playerl(FacialExpression.ASKING,"Can I have a weather forecast then please?").also { stage++ }
3 -> npcl(FacialExpression.THINKING,"You require a divination of the weather? This is a simple matter for me, but I will require something in return from you for this small service.").also { stage++ }
4 -> playerl(FacialExpression.ASKING,"I knew you were going to say that...").also { stage++ }
5 -> npcl(FacialExpression.HAPPY,"Do not fret, outerlander; it is a fairly simple matter. I require a bodyguard for protection. Find someone willing to offer me this service.").also { stage++ }
6 -> playerl(FacialExpression.ASKING,"That's all?").also { stage++ }
7 -> npcl(FacialExpression.HAPPY,"That is all.").also {
player?.incrementAttribute("sigmund-steps",1)
stage = 1000
}
10 -> npcl(core.game.dialogue.FacialExpression.ANNOYED,"If I did, then I would simply have asked them myself now, wouldn't I, outerlander?").also { stage = 1000 }
10 -> npcl(FacialExpression.ANNOYED,"If I did, then I would simply have asked them myself now, wouldn't I, outerlander?").also { stage = 1000 }
15 -> npcl(core.game.dialogue.FacialExpression.ANNOYED,"I have already told you outerlander; You may have a reading from me when I have a signed contract from a warrior guaranteeing my protection.").also { stage++ }
16 -> playerl(core.game.dialogue.FacialExpression.HAPPY,"Yeah, I know; I have one right here from Thorvald.").also {
15 -> npcl(FacialExpression.ANNOYED,"I have already told you outerlander; You may have a reading from me when I have a signed contract from a warrior guaranteeing my protection.").also { stage++ }
16 -> playerl(FacialExpression.HAPPY,"Yeah, I know; I have one right here from Thorvald.").also {
removeItem(player,3710)
addItem(player,3705)
stage++
}
17 -> npcl(core.game.dialogue.FacialExpression.AMAZED,"You have not only persuaded one of the Fremennik to act as a servant to me, but you have enlisted the aid of mighty Thorvald himself???").also { stage++ }
18 -> npcl(core.game.dialogue.FacialExpression.HAPPY,"You may take this forecast with my blessing outerlander. You have offered me the greatest security I can imagine.").also { stage = 1000 }
17 -> npcl(FacialExpression.AMAZED,"You have not only persuaded one of the Fremennik to act as a servant to me, but you have enlisted the aid of mighty Thorvald himself???").also { stage++ }
18 -> npcl(FacialExpression.HAPPY,"You may take this forecast with my blessing outerlander. You have offered me the greatest security I can imagine.").also { stage = 1000 }
20 -> npcl(core.game.dialogue.FacialExpression.THINKING,"Yes, outerlander?").also { stage++ }
21 -> playerl(core.game.dialogue.FacialExpression.ASKING,"I still don't know why you didn't just let me have one anyway in the first place. Surely it means nothing to you?").also { stage++ }
22 -> npcl(core.game.dialogue.FacialExpression.THINKING,"That is not true, outerlander. Although I see glimpses of the future all of the time, using my powers brings the attention of the gods to me.").also { stage++ }
23 -> npcl(core.game.dialogue.FacialExpression.THINKING,"Some of the gods are spiteful and cruel, and I fear if I use my powers too much then I will meet with unpredictable accidents.").also { stage++ }
24 -> npcl(core.game.dialogue.FacialExpression.HAPPY,"This is why I needed protection.").also { stage++ }
25 -> playerl(core.game.dialogue.FacialExpression.THINKING,"Okay... I... think I understand...").also { stage = 1000 }
20 -> npcl(FacialExpression.THINKING,"Yes, outerlander?").also { stage++ }
21 -> playerl(FacialExpression.ASKING,"I still don't know why you didn't just let me have one anyway in the first place. Surely it means nothing to you?").also { stage++ }
22 -> npcl(FacialExpression.THINKING,"That is not true, outerlander. Although I see glimpses of the future all of the time, using my powers brings the attention of the gods to me.").also { stage++ }
23 -> npcl(FacialExpression.THINKING,"Some of the gods are spiteful and cruel, and I fear if I use my powers too much then I will meet with unpredictable accidents.").also { stage++ }
24 -> npcl(FacialExpression.HAPPY,"This is why I needed protection.").also { stage++ }
25 -> playerl(FacialExpression.THINKING,"Okay... I... think I understand...").also { stage = 1000 }
26 -> npcl(core.game.dialogue.FacialExpression.ANNOYED,"Not me, I'm afraid.").also { stage++ }
26 -> npcl(FacialExpression.ANNOYED,"Not me, I'm afraid.").also { stage++ }
//The Seer's Trial
50 -> npcl(core.game.dialogue.FacialExpression.AMAZED,"!").also { stage++ }
51 -> npcl(core.game.dialogue.FacialExpression.HAPPY,"Ahem, sorry about that. Hello outerlander. What do you want?").also { stage++ }
52 -> playerl(core.game.dialogue.FacialExpression.ASKING,"Hello. I'm looking for members of the council of elders to vote for me to become a Fremennik.").also { stage++ }
53 -> npcl(core.game.dialogue.FacialExpression.THINKING,"Are you now? Well that is interesting. Usually outerlanders do not concern themselves with our ways like that.").also { stage++ }
54 -> npcl(core.game.dialogue.FacialExpression.HAPPY,"I am one of the members of the council of elders, and should you be able to prove to me that you have something to offer my clan I will vote in your favour at the next meeting.").also { stage++ }
55 -> playerl(core.game.dialogue.FacialExpression.ASKING,"How can I prove that to you?").also { stage++ }
56 -> npcl(core.game.dialogue.FacialExpression.HAPPY,"Well, I have but a simple test. This building behind me is my house. Inside I have constructed a puzzle.").also { stage++ }
57 -> npcl(core.game.dialogue.FacialExpression.HAPPY,"As a Seer to the clan, I value intelligence very highly, so you may think of it as an intelligence test of sorts.").also { stage++ }
58 -> playerl(core.game.dialogue.FacialExpression.THINKING,"An intelligence test? I thought barbarians were stupid!").also { stage++ }
59 -> npcl(core.game.dialogue.FacialExpression.ANNOYED,"That is the opinion that outerlanders usually hold of my people, it is true. But that is because people often confuse knowledge with wisdom.").also { stage++ }
60 -> npcl(core.game.dialogue.FacialExpression.ANNOYED,"My puzzle tests not what you know, but what you can work out. All members of our clan have been tested when they took their trials.").also { stage++ }
61 -> playerl(core.game.dialogue.FacialExpression.ASKING,"So what exactly does this puzzle consist of, then?").also { stage++ }
62 -> npcl(core.game.dialogue.FacialExpression.HAPPY,"Well, firstly you must enter my house with no items, weapons or armour. Then it is a simple matter of entering through one door and leaving by the other.").also { stage++ }
63 -> playerl(core.game.dialogue.FacialExpression.ASKING,"I can't take anything in there with me?").also { stage++ }
64 -> npcl(core.game.dialogue.FacialExpression.HAPPY,"That is correct outerlander. Everything you need to complete the puzzle you will find inside the building. Nothing more.").also { stage++ }
65 -> npcl(core.game.dialogue.FacialExpression.HAPPY,"So what say you outerlander? You think you have the wit to earn yourself my vote?").also { stage++ }
50 -> npcl(FacialExpression.AMAZED,"!").also { stage++ }
51 -> npcl(FacialExpression.HAPPY,"Ahem, sorry about that. Hello outerlander. What do you want?").also { stage++ }
52 -> playerl(FacialExpression.ASKING,"Hello. I'm looking for members of the council of elders to vote for me to become a Fremennik.").also { stage++ }
53 -> npcl(FacialExpression.THINKING,"Are you now? Well that is interesting. Usually outerlanders do not concern themselves with our ways like that.").also { stage++ }
54 -> npcl(FacialExpression.HAPPY,"I am one of the members of the council of elders, and should you be able to prove to me that you have something to offer my clan I will vote in your favour at the next meeting.").also { stage++ }
55 -> playerl(FacialExpression.ASKING,"How can I prove that to you?").also { stage++ }
56 -> npcl(FacialExpression.HAPPY,"Well, I have but a simple test. This building behind me is my house. Inside I have constructed a puzzle.").also { stage++ }
57 -> npcl(FacialExpression.HAPPY,"As a Seer to the clan, I value intelligence very highly, so you may think of it as an intelligence test of sorts.").also { stage++ }
58 -> playerl(FacialExpression.THINKING,"An intelligence test? I thought barbarians were stupid!").also { stage++ }
59 -> npcl(FacialExpression.ANNOYED,"That is the opinion that outerlanders usually hold of my people, it is true. But that is because people often confuse knowledge with wisdom.").also { stage++ }
60 -> npcl(FacialExpression.ANNOYED,"My puzzle tests not what you know, but what you can work out. All members of our clan have been tested when they took their trials.").also { stage++ }
61 -> playerl(FacialExpression.ASKING,"So what exactly does this puzzle consist of, then?").also { stage++ }
62 -> npcl(FacialExpression.HAPPY,"Well, firstly you must enter my house with no items, weapons or armour. Then it is a simple matter of entering through one door and leaving by the other.").also { stage++ }
63 -> playerl(FacialExpression.ASKING,"I can't take anything in there with me?").also { stage++ }
64 -> npcl(FacialExpression.HAPPY,"That is correct outerlander. Everything you need to complete the puzzle you will find inside the building. Nothing more.").also { stage++ }
65 -> npcl(FacialExpression.HAPPY,"So what say you outerlander? You think you have the wit to earn yourself my vote?").also { stage++ }
66 -> options("Yes","No").also { stage++ }
67 -> when(buttonId){
1 ->{ playerl(core.game.dialogue.FacialExpression.HAPPY,"Yes, I accept your challenge, I have one small question, however...")
1 ->{ playerl(FacialExpression.HAPPY,"Yes, I accept your challenge, I have one small question, however...")
player?.setAttribute("/save:PeerStarted",true)
player?.setAttribute("/save:PeerRiddle", Random.nextInt(0,3))
stage = 70
}
2 ->{ playerl(core.game.dialogue.FacialExpression.HAPPY,"No, thinking about stuff isn't really my 'thing'. I'd rather go kill something. I'll find someone else to vote for me")
2 ->{ playerl(FacialExpression.HAPPY,"No, thinking about stuff isn't really my 'thing'. I'd rather go kill something. I'll find someone else to vote for me")
stage++
}
}
//No to challenge
68 -> npcl(core.game.dialogue.FacialExpression.HAPPY,"As you wish, outerlander.").also { stage = 1000 }
68 -> npcl(FacialExpression.HAPPY,"As you wish, outerlander.").also { stage = 1000 }
//Yes to challenge
70 -> npcl(core.game.dialogue.FacialExpression.ASKING,"Yes outerlander?").also { stage++ }
71 -> playerl(core.game.dialogue.FacialExpression.THINKING,"Well... you say I can bring nothing with me when I enter your house...").also { stage++ }
72 -> npcl(core.game.dialogue.FacialExpression.ANNOYED,"Yes outerlander??").also { stage++ }
73 -> playerl(core.game.dialogue.FacialExpression.THINKING,"Well...").also { stage++ }
74 -> npcl(core.game.dialogue.FacialExpression.ANGRY,"Yes, outerlander???").also { stage++ }
75 -> playerl(core.game.dialogue.FacialExpression.ASKING,"Where is the nearest bank?").also { stage++ }
76 -> npcl(core.game.dialogue.FacialExpression.HAPPY,"Ah, I see your problem outerlander. The nearest bank to here is the place known to outerlanders as the Seers Village.").also { stage++ }
77 -> npcl(core.game.dialogue.FacialExpression.HAPPY,"It is some way South. I do however have an alternative, should you wish to take it.").also { stage++ }
78 -> playerl(core.game.dialogue.FacialExpression.ASKING,"And what is that?").also { stage++ }
79 -> npcl(core.game.dialogue.FacialExpression.HAPPY,"I can store all the weapons, armour and items that you have upon you directly into your bank account.").also { stage++ }
80 -> npcl(core.game.dialogue.FacialExpression.HAPPY,"This will tax what little magic I possess however, so you will have to travel to the bank to withdraw them again.").also { stage++ }
81 -> npcl(core.game.dialogue.FacialExpression.HAPPY,"What say you outerlander? Do you wish me to do this for you?").also { stage++ }
70 -> npcl(FacialExpression.ASKING,"Yes outerlander?").also { stage++ }
71 -> playerl(FacialExpression.THINKING,"Well... you say I can bring nothing with me when I enter your house...").also { stage++ }
72 -> npcl(FacialExpression.ANNOYED,"Yes outerlander??").also { stage++ }
73 -> playerl(FacialExpression.THINKING,"Well...").also { stage++ }
74 -> npcl(FacialExpression.ANGRY,"Yes, outerlander???").also { stage++ }
75 -> playerl(FacialExpression.ASKING,"Where is the nearest bank?").also { stage++ }
76 -> npcl(FacialExpression.HAPPY,"Ah, I see your problem outerlander. The nearest bank to here is the place known to outerlanders as the Seers Village.").also { stage++ }
77 -> npcl(FacialExpression.HAPPY,"It is some way South. I do however have an alternative, should you wish to take it.").also { stage++ }
78 -> playerl(FacialExpression.ASKING,"And what is that?").also { stage++ }
79 -> npcl(FacialExpression.HAPPY,"I can store all the weapons, armour and items that you have upon you directly into your bank account.").also { stage++ }
80 -> npcl(FacialExpression.HAPPY,"This will tax what little magic I possess however, so you will have to travel to the bank to withdraw them again.").also { stage++ }
81 -> npcl(FacialExpression.HAPPY,"What say you outerlander? Do you wish me to do this for you?").also { stage++ }
82 -> options("Yes","No").also { stage++ }
83 -> when(buttonId){
1 -> {
val slotAmount = player.inventory.itemCount() + player.equipment.itemCount()
if (slotAmount < player.bank.freeSlots()){
npcl(core.game.dialogue.FacialExpression.HAPPY,"The task is done. I wish you luck with your test, outerlander.")
dumpContainer(player,player.inventory)
dumpContainer(player,player.equipment)
if (slotAmount < player.bank.freeSlots() && slotAmount == dumpContainer(player,player.inventory) + dumpContainer(player,player.equipment)){
npcl(FacialExpression.HAPPY,"The task is done. I wish you luck with your test, outerlander.")
stage = 1000
}
else {
npcl(core.game.dialogue.FacialExpression.SAD,"I am sorry outerlander, the spell is not working. I believe you may have some objects that you cannot bank with you")
npcl(FacialExpression.SAD,"I am sorry outerlander, the spell is not working. I believe you may have some objects that you cannot bank with you.")
stage = 1000
}
}
2 -> playerl(core.game.dialogue.FacialExpression.HAPPY,"No thanks. Nobody touches my stuff but me!").also { stage++ }
2 -> playerl(FacialExpression.HAPPY,"No thanks. Nobody touches my stuff but me!").also { stage++ }
}
//No to banking
84 -> npcl(core.game.dialogue.FacialExpression.HAPPY,"As you wish, outerlander. You may attempt my little task when you have deposited your equipment in the bank").also {
84 -> npcl(FacialExpression.HAPPY,"As you wish, outerlander. You may attempt my little task when you have deposited your equipment in the bank.").also {
stage = 1000
}
//Yes to banking but cannot bank
90 -> npcl(core.game.dialogue.FacialExpression.SAD,"I am sorry outerlander, the spell is not working. I believe you may have some objects that you cannot bank with you").also {
90 -> npcl(FacialExpression.SAD,"I am sorry outerlander, the spell is not working. I believe you may have some objects that you cannot bank with you.").also {
stage = 1000
}
//Returning after accepting with items.
100 -> npcl(core.game.dialogue.FacialExpression.AMAZED,"!").also { stage++ }
101 -> npcl(core.game.dialogue.FacialExpression.HAPPY,"Ahem, sorry about that. Hello outerlander. What do you want?").also { stage++ }
102 -> playerl(core.game.dialogue.FacialExpression.ASKING,"So I can bring nothing with me when I enter your house?").also { stage++ }
103 -> npcl(core.game.dialogue.FacialExpression.HAPPY,"That is correct outerlander, but as I say, I can use my small skill in magic to send your items directly into your bank account from here.").also { stage++ }
104 -> npcl(core.game.dialogue.FacialExpression.HAPPY,"You will need to manually go to the bank to withdraw them again however.").also { stage++ }
105 -> npcl(core.game.dialogue.FacialExpression.HAPPY,"Would you like me to perform this small spell upon you, outerlander?").also { stage = 82 }
100 -> npcl(FacialExpression.AMAZED,"!").also { stage++ }
101 -> npcl(FacialExpression.HAPPY,"Ahem, sorry about that. Hello outerlander. What do you want?").also { stage++ }
102 -> playerl(FacialExpression.ASKING,"So I can bring nothing with me when I enter your house?").also { stage++ }
103 -> npcl(FacialExpression.HAPPY,"That is correct outerlander, but as I say, I can use my small skill in magic to send your items directly into your bank account from here.").also { stage++ }
104 -> npcl(FacialExpression.HAPPY,"You will need to manually go to the bank to withdraw them again however.").also { stage++ }
105 -> npcl(FacialExpression.HAPPY,"Would you like me to perform this small spell upon you, outerlander?").also { stage = 82 }
//Returning after accepting without items.
110 -> npcl(core.game.dialogue.FacialExpression.AMAZED,"!").also { stage++ }
111 -> npcl(core.game.dialogue.FacialExpression.HAPPY,"Ahem, sorry about that. Hello outerlander. What do you want?").also { stage++ }
112 -> playerl(core.game.dialogue.FacialExpression.ASKING,"So I just have to enter by one door of your house, and leave by the other?").also { stage++ }
113 -> npcl(core.game.dialogue.FacialExpression.HAPPY,"That is correct outerlander. Be warned it is not as easy as it may at first sound...").also { stage = 1000 }
110 -> npcl(FacialExpression.AMAZED,"!").also { stage++ }
111 -> npcl(FacialExpression.HAPPY,"Ahem, sorry about that. Hello outerlander. What do you want?").also { stage++ }
112 -> playerl(FacialExpression.ASKING,"So I just have to enter by one door of your house, and leave by the other?").also { stage++ }
113 -> npcl(FacialExpression.HAPPY,"That is correct outerlander. Be warned it is not as easy as it may at first sound...").also { stage = 1000 }
//After completing the Seer's Trial.
120 -> npcl(core.game.dialogue.FacialExpression.AMAZED,"!").also { stage++ }
121 -> npcl(core.game.dialogue.FacialExpression.HAPPY,"Ahem, sorry about that.").also { stage++ }
122 -> playerl(core.game.dialogue.FacialExpression.HAPPY,"So you will vote for me at the council?").also { stage++ }
123 -> npcl(core.game.dialogue.FacialExpression.HAPPY,"Absolutely, outerlander. Your wisdom in passing my test marks you as worthy in my eyes.").also { stage = 1000 }
120 -> npcl(FacialExpression.AMAZED,"!").also { stage++ }
121 -> npcl(FacialExpression.HAPPY,"Ahem, sorry about that.").also { stage++ }
122 -> playerl(FacialExpression.HAPPY,"So you will vote for me at the council?").also { stage++ }
123 -> npcl(FacialExpression.HAPPY,"Absolutely, outerlander. Your wisdom in passing my test marks you as worthy in my eyes.").also { stage = 1000 }
//After The Fremennik Trials
150 -> npcl(core.game.dialogue.FacialExpression.AMAZED,"!").also { stage++ }
151 -> npcl(core.game.dialogue.FacialExpression.HAPPY,"Ahem, sorry about that.").also {
stage = if(player.achievementDiaryManager.getDiary(DiaryType.FREMENNIK).isComplete(0)){
150 -> npcl(FacialExpression.AMAZED,"!").also { stage++ }
151 -> npcl(FacialExpression.HAPPY,"Ahem, sorry about that.").also {
stage = if(anyInEquipment(player, Items.FREMENNIK_SEA_BOOTS_1_14571, Items.FREMENNIK_SEA_BOOTS_2_14572, Items.FREMENNIK_SEA_BOOTS_3_14573) && !hasIronmanRestriction(player, IronmanMode.ULTIMATE)){
200
}else 152
}
152 -> playerl(core.game.dialogue.FacialExpression.HAPPY,"Hello Peer.").also { stage++ }
153 -> npcl(core.game.dialogue.FacialExpression.HAPPY,"Greetings to you, brother ${player.getAttribute("fremennikname","dingle")}! What brings you to see me again?").also { stage++ }
152 -> playerl(FacialExpression.HAPPY,"Hello Peer.").also { stage++ }
153 -> npcl(FacialExpression.HAPPY,"Greetings to you, brother ${player.getAttribute("fremennikname","dingle")}! What brings you to see me again?").also { stage++ }
154 -> options("Can you tell my future?","Nothing really.").also{stage++}
155 -> when(buttonId){
1 -> playerl(core.game.dialogue.FacialExpression.ASKING,"I was wondering if you could give me a reading on my future...?").also { stage++ }
2 -> playerl(core.game.dialogue.FacialExpression.HAPPY,"Nothing really, I just stopped by to say hello").also { stage = 160 }
1 -> playerl(FacialExpression.ASKING,"I was wondering if you could give me a reading on my future...?").also { stage++ }
2 -> playerl(FacialExpression.HAPPY,"Nothing really, I just stopped by to say hello").also { stage = 160 }
}
156 -> npcl(core.game.dialogue.FacialExpression.HAPPY,"Ah, you would like a prediction? I do not see that that would be so difficult... Wait a moment...").also {
156 -> npcl(FacialExpression.HAPPY,"Ah, you would like a prediction? I do not see that that would be so difficult... Wait a moment...").also {
stage++
}
157 -> npcl(core.game.dialogue.FacialExpression.HAPPY,"Here is your prediction: ${PREDICTIONS[prediction]}").also { stage = 1000 }
157 -> npcl(FacialExpression.HAPPY,"Here is your prediction: ${PREDICTIONS[prediction]}").also { stage = 1000 }
160 -> npcl(core.game.dialogue.FacialExpression.HAPPY,"Well, hello to you too!").also { stage = 1000 }
160 -> npcl(FacialExpression.HAPPY,"Well, hello to you too!").also { stage = 1000 }
200 -> options("Deposit service","Can you tell my future?","Nothing really.").also{ stage++ }
201 -> when(buttonId){
1 -> playerl(core.game.dialogue.FacialExpression.HAPPY,"Could you deposit some things for me, please?").also { stage++ }
2 -> playerl(core.game.dialogue.FacialExpression.ASKING,"I was wondering if you could give me a reading on my future...?").also { stage = 156 }
3 -> playerl(core.game.dialogue.FacialExpression.HAPPY,"Nothing really, I just stopped by to say hello").also { stage = 160 }
1 -> playerl(FacialExpression.HAPPY,"Could you deposit some things for me, please?").also { stage++ }
2 -> playerl(FacialExpression.ASKING,"I was wondering if you could give me a reading on my future...?").also { stage = 156 }
3 -> playerl(FacialExpression.HAPPY,"Nothing really, I just stopped by to say hello").also { stage = 160 }
}
202 -> npcl(core.game.dialogue.FacialExpression.HAPPY,"Of course, ${player.getAttribute("fremennikname","dingle")}. I am always happy to aid those who have earned the right to wear Fremennik sea boots.").also {
202 -> npcl(FacialExpression.HAPPY,"Of course, ${player.getAttribute("fremennikname","dingle")}. I am always happy to aid those who have earned the right to wear Fremennik sea boots.").also {
player.bank.openDepositBox()
stage = 1000
}
300 -> npc(core.game.dialogue.FacialExpression.NEUTRAL,"!").also { stage++ }
301 -> npcl(core.game.dialogue.FacialExpression.NEUTRAL,"Ahem, sorry about that. I have no interest in talking to you just now outerlander.").also { stage = END_DIALOGUE }
300 -> npc(FacialExpression.NEUTRAL,"!").also { stage++ }
301 -> npcl(FacialExpression.NEUTRAL,"Ahem, sorry about that. I have no interest in talking to you just now outerlander.").also { stage = END_DIALOGUE }
1000 -> end()
}
return true
}
override fun newInstance(player: Player?): core.game.dialogue.DialoguePlugin {
override fun newInstance(player: Player?): DialoguePlugin {
return PeerTheSeerDialogue(player)
}
override fun getIds(): IntArray {
return intArrayOf(1288)
return intArrayOf(NPCs.PEER_THE_SEER_1288)
}
}

View file

@ -1,11 +1,18 @@
package content.region.fremennik.rellekka.quest.thefremenniktrials
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributePoisonClue
import core.api.inInventory
import core.api.setAttribute
import core.game.dialogue.DialoguePlugin
import core.game.dialogue.FacialExpression
import core.game.dialogue.IfTopic
import core.game.dialogue.Topic
import core.game.node.entity.player.Player
import core.game.node.item.Item
import core.plugin.Initializable
import core.tools.END_DIALOGUE
import core.tools.START_DIALOGUE
import org.rs09.consts.Items
import content.data.Quests
@Initializable
@ -18,12 +25,18 @@ class PoisonSalesman(player: Player? = null) : DialoguePlugin(player) {
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
//val murderMysteryStage = player.questRepository.isComplete(Quests.MURDER_MYSTERY)
val murderMysteryStage = player.questRepository.getStage(Quests.MURDER_MYSTERY)
val fremennikTrialsStage = player.questRepository.getStage(Quests.THE_FREMENNIK_TRIALS)
when (stage) {
START_DIALOGUE -> when (buttonId) {
1 -> { player("Err... nevermind"); stage = END_DIALOGUE }
1 -> {
when (murderMysteryStage) {
0 -> npcl(FacialExpression.NEUTRAL, "I'm afraid I'm all sold out of poison at the moment. People know a bargain when they see it!").also { stage = END_DIALOGUE }
1 -> playerl(FacialExpression.NEUTRAL, "I'm investigating the murder at the Sinclair house.").also { stage = 50 }
100 -> npcl(FacialExpression.NEUTRAL, "I hear you're pretty smart to have solved the Sinclair Murder!").also { stage = END_DIALOGUE }
}
}
2 -> { player("Hello."); stage = 10 }
}
@ -88,6 +101,42 @@ class PoisonSalesman(player: Player? = null) : DialoguePlugin(player) {
stage++
}
45 -> { npc("Well come back when you do!"); stage = END_DIALOGUE }
//Murder Mystery
50 -> npcl(FacialExpression.NEUTRAL, "There was a murder at the Sinclair house??? That's terrible! And I was only there the other day too! They bought the last of my Patented Multi Purpose Poison!").also { stage++ }
51 -> showTopics(
Topic("Patented Multi Purpose Poison?", 52),
Topic("Who did you sell Poison to at the house?", 61),
Topic("Can I buy some Poison?", 65),
IfTopic("I have this pot I found at the murder scene...", 69, inInventory(player, Items.PUNGENT_POT_1812))
)
52 -> npcl(FacialExpression.NEUTRAL, "Aaaaah... a miracle of modern apothecaries!").also { stage++ }
53 -> npcl(FacialExpression.NEUTRAL, "This exclusive concoction has been tested on all known forms of life and been proven to kill them all in varying dilutions from cockroaches to king dragons!").also { stage++ }
54 -> npcl(FacialExpression.NEUTRAL, "So incredibly versatile, it can be used as pest control, a cleansing agent, drain cleaner, metal polish and washes whiter than white,").also { stage++ }
55 -> npcl(FacialExpression.NEUTRAL, "all with our uniquely fragrant concoction that is immediately recognisable across the land as Peter Potter's Patented Poison potion!!!").also { stage++ }
56 -> sendDialogue("The salesman stops for breath.").also { stage ++ }
57 -> npcl(FacialExpression.NEUTRAL, "I'd love to sell you some but I've sold out recently. That's just how good it is! Three hundred and twenty eight people in this area alone cannot be wrong!").also { stage++ }
58 -> npcl(FacialExpression.NEUTRAL, "Nine out of Ten poisoners prefer it in controlled tests!").also { stage++ }
59 -> npcl(FacialExpression.NEUTRAL, "Can I help you with anything else? Perhaps I can take your name and add it to our mailing list of poison users? We will only send you information related to the use of poison and other Peter Potter Products!").also { stage++ }
60 -> playerl(FacialExpression.NEUTRAL, "Uh... no, it's ok. Really.").also { stage = END_DIALOGUE }
61 -> npcl(FacialExpression.HAPPY, "Well, Peter Potter's Patented Multi Purpose Poison is a product of such obvious quality that I am glad to say I managed to sell a bottle to each of the Sinclairs!").also { stage++ }
62 -> npcl(FacialExpression.HAPPY, "Anna, Bob, Carol, David, Elizabeth and Frank all bought a bottle! In fact they bought the last of my supplies!").also { stage++ }
63 -> npcl(FacialExpression.HAPPY, "Maybe I can take your name and address and I will personally come and visit you when stocks return?").also { stage++ }
64 -> playerl(FacialExpression.THINKING, "Uh...no, it's ok.")
.also { setAttribute(player, attributePoisonClue, 1)}
.also { stage = END_DIALOGUE }
65 -> npcl(FacialExpression.NEUTRAL, "I'm afraid I am totally out of stock at the moment after my successful trip to the Sinclairs' House the other day.").also { stage++ }
66 -> npcl(FacialExpression.NEUTRAL, "But don't worry! Our factories are working overtime to produce Peter Potter's Patented Multi Purpose Poison!").also { stage++ }
67 -> npcl(FacialExpression.NEUTRAL, "Possibly the finest multi purpose poison and cleaner yet available to the general market.").also { stage++ }
68 -> npcl(FacialExpression.NEUTRAL, "And its unique fragrance makes it the number one choice for cleaners and exterminators the whole country over!").also { stage = END_DIALOGUE }
69 -> sendDialogue("You show the poison salesman the pot you found at the murder", "scene with the unusual smell.").also { stage ++ }
70 -> npcl(FacialExpression.THINKING, "Hmmm... yes, that smells exactly like my Patented Multi Purpose Poison, but I don't see how it could be. It quite clearly says on the label of all bottles").also { stage++ }
71 -> npcl(FacialExpression.THINKING, "'Not to be taken internally - EXTREMELY POISONOUS'.").also { stage++ }
72 -> playerl(FacialExpression.THINKING, "Perhaps someone else put it in his wine?").also { stage++ }
73 -> npcl(FacialExpression.THINKING, "Yes... I suppose that could have happened...").also { stage = END_DIALOGUE }
END_DIALOGUE -> end()
}
return true

View file

@ -9,7 +9,6 @@ import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.plugin.Initializable
import core.tools.END_DIALOGUE
import org.rs09.consts.Items
import org.rs09.consts.NPCs
import content.data.Quests
@ -43,8 +42,7 @@ class ThormacDialogue(player: Player? = null) : DialoguePlugin(player) {
)
ENCHANT_DIALOGUE -> {
val cost = if (player.equipment.contains(Items.SEERS_HEADBAND_14631, 1)) 27 else 40
npcl(FacialExpression.HAPPY, "Yes, it'll cost you $cost,000 coins for the materials needed though. " +
npcl(FacialExpression.HAPPY, "Yes, it'll cost you 40,000 coins for the materials needed though. " +
"Which sort of staff did you want enchanting?").also { stage++ }
}
ENCHANT_DIALOGUE + 1 -> {

View file

@ -0,0 +1,110 @@
package content.region.kandarin.gnomestronghold.dialogue
import core.api.addItem
import core.api.inInventory
import core.api.openDialogue
import core.api.openNpcShop
import core.api.removeItem
import core.api.sendMessage
import core.game.dialogue.ChatAnim
import core.game.dialogue.DialogueLabeller
import core.game.dialogue.DialogueOption
import core.game.dialogue.DialoguePlugin
import core.game.node.entity.player.Player
import core.game.node.item.Item
import core.plugin.Initializable
import org.rs09.consts.Items
import org.rs09.consts.NPCs
private const val INGREDIENT_COST = 20
private const val NOT_ENOUGH_MONEY_MESSAGE = "You do not have enough money to buy that."
/**
* Handles the dialogue for the Gnome Barman NPCs in the Tree Gnome Stronghold.
* @author Broseki
*/
@Initializable
class GnomeBarmanDialogue(player: Player? = null) : DialoguePlugin(player) {
override fun newInstance(player: Player?): DialoguePlugin {
return GnomeBarmanDialogue(player)
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
openDialogue(player, GnomeBarmanDialogueStart(), npc)
return false
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.BARMAN_849)
}
}
class GnomeBarmanDialogueStart : DialogueLabeller() {
override fun addConversation() {
npc(ChatAnim.OLD_HAPPY, "Good day to you. What can I get you to drink?")
options(
DialogueOption("store", "What do you have?", expression = ChatAnim.FRIENDLY, spokenText = "What do you have."),
DialogueOption("nothing", "Nothing thanks.", expression = ChatAnim.FRIENDLY),
DialogueOption(
"ingredients", "Can I buy some ingredients?",
spokenText = "I was just wanting to buy a cocktail ingredient actually.",
expression = ChatAnim.FRIENDLY
),
)
label("store")
npc(ChatAnim.OLD_HAPPY, "Here, take a look at our menu.")
exec { player, npc ->
openNpcShop(player, npc.id)
}
label("nothing")
npc(ChatAnim.OLD_HAPPY, "Okay, take it easy.")
label("ingredients")
npc(ChatAnim.OLD_HAPPY, "Sure thing, what did you want?")
options(
DialogueOption("lemon", "A lemon.", expression = ChatAnim.FRIENDLY),
DialogueOption("orange", "An orange.", expression = ChatAnim.FRIENDLY),
DialogueOption("shaker", "A cocktail shaker.", expression = ChatAnim.FRIENDLY),
DialogueOption(
"buynothing", "Nothing thanks.",
spokenText = "Actually nothing thanks.",
expression = ChatAnim.FRIENDLY
),
)
label("lemon")
npc(ChatAnim.OLD_HAPPY, "$INGREDIENT_COST coins please.")
exec { player, _ ->
if (removeItem(player, Item(Items.COINS_995, INGREDIENT_COST))) {
addItem(player, Items.LEMON_2102)
} else {
sendMessage(player, NOT_ENOUGH_MONEY_MESSAGE)
}
}
label("orange")
npc(ChatAnim.OLD_HAPPY, "$INGREDIENT_COST coins please.")
exec { player, _ ->
if (removeItem(player, Item(Items.COINS_995, INGREDIENT_COST))) {
addItem(player, Items.ORANGE_2108)
} else {
sendMessage(player, NOT_ENOUGH_MONEY_MESSAGE)
}
}
label("shaker")
npc(ChatAnim.OLD_HAPPY, "$INGREDIENT_COST coins please.")
exec { player, _ ->
if (removeItem(player, Item(Items.COINS_995, INGREDIENT_COST))) {
addItem(player, Items.COCKTAIL_SHAKER_2025)
} else {
sendMessage(player, NOT_ENOUGH_MONEY_MESSAGE)
}
}
label("buynothing")
// Just end the conversation here without any further dialogue
}
}

View file

@ -0,0 +1,60 @@
package content.region.kandarin.quest.murdermystery
import content.data.Quests
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributeAskPoisonAnna
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributePoisonClue
import core.api.*
import core.game.dialogue.*
import core.game.node.entity.player.Player
import core.plugin.Initializable
import core.tools.END_DIALOGUE
import org.rs09.consts.Items
import org.rs09.consts.NPCs
@Initializable
class AnnaDialogue (player: Player? = null) : DialoguePlugin(player) {
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
openDialogue(player, AnnaDialogueFile(), npc)
return true
}
override fun newInstance(player: Player): DialoguePlugin {
return AnnaDialogue(player)
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.ANNA_814, NPCs.ANNA_6192)
}
}
class AnnaDialogueFile : DialogueFile() {
override fun handle(componentID: Int, buttonID: Int) {
when (getQuestStage(player!!, Quests.MURDER_MYSTERY)){
0 -> sendDialogue(player!!, "They are ignoring you.").also { stage = END_DIALOGUE }
1 -> when (stage) {
0 -> playerl(FacialExpression.NEUTRAL, "I'm here to help the guards with their investigation.").also { stage++ }
1 -> npcl(FacialExpression.ASKING, "Oh really? What do you want to know then?").also { stage++ }
2 -> showTopics(
Topic("Who do you think is responsible?", 3),
Topic( "Where were you when the murder happened?", 6),
IfTopic("Do you recognise this thread?", 7, inInventory(player!!, Items.CRIMINALS_THREAD_1808) || inInventory(player!!, Items.CRIMINALS_THREAD_1809) || inInventory(player!!, Items.CRIMINALS_THREAD_1810)),
IfTopic("Why'd you buy poison the other day?", 10, getAttribute(player!!, attributePoisonClue, 0) > 0)
)
3 -> npcl("It was clearly an intruder.").also { stage++ }
4 -> playerl("Well, I don't think it was.").also { stage++ }
5 -> npcl("It was one of our lazy servants then.").also { stage = END_DIALOGUE }
6 -> npcl("In the library. No one else was there so you'll just have to take my word for it.").also { stage = END_DIALOGUE }
7 -> sendDialogue(player!!, "You show Anna the thread from the study.")
.also { if (inInventory(player!!, Items.CRIMINALS_THREAD_1809)) stage++ else stage = 9 }
8 -> npcl("It's some Green thread. It's not exactly uncommon is it? My trousers are made of the same material.").also { stage = END_DIALOGUE }
9 -> npcl("Not really, no. Thread is fairly common.").also { stage = END_DIALOGUE }
10 -> npcl(FacialExpression.ANNOYED, "That useless Gardener Stanford let his compost heap fester. It's an eyesore to the garden! So I bought some poison from a travelling salesman so that I could kill off some of the wildlife living in it.")
.also { setAttribute(player!!, attributeAskPoisonAnna, true)}
.also { stage = END_DIALOGUE }
}
100 -> npcl("Apparently you aren't as stupid as you look.").also { stage = END_DIALOGUE }
}
}
}

View file

@ -0,0 +1,61 @@
package content.region.kandarin.quest.murdermystery
import content.data.Quests
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributeAskPoisonBob
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributePoisonClue
import core.api.*
import core.game.dialogue.*
import core.game.node.entity.player.Player
import core.plugin.Initializable
import core.tools.END_DIALOGUE
import org.rs09.consts.Items
import org.rs09.consts.NPCs
@Initializable
class BobDialogue (player: Player? = null) : DialoguePlugin(player) {
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
openDialogue(player, BobDialogueFile(), npc)
return true
}
override fun newInstance(player: Player): DialoguePlugin {
return BobDialogue(player)
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.BOB_815, NPCs.BOB_6193)
}
}
class BobDialogueFile : DialogueFile() {
override fun handle(componentID: Int, buttonID: Int) {
when (getQuestStage(player!!, Quests.MURDER_MYSTERY)){
0 -> sendDialogue(player!!, "They are ignoring you.").also { stage = END_DIALOGUE }
1 -> when (stage) {
0 -> playerl(FacialExpression.NEUTRAL, "I'm here to help the guards with their investigation.").also { stage++ }
1 -> npcl("I suppose I had better talk to you then.").also { stage++ }
2 -> showTopics(
Topic("Who do you think is responsible?", 3),
Topic( "Where were you when the murder happened?", 4),
IfTopic(FacialExpression.THINKING, "Do you recognise this thread?", 7, inInventory(player!!, Items.CRIMINALS_THREAD_1808) || inInventory(player!!, Items.CRIMINALS_THREAD_1809) || inInventory(player!!, Items.CRIMINALS_THREAD_1810)),
IfTopic("Why'd you buy poison the other day?", 10, getAttribute(player!!, attributePoisonClue, 0) > 0)
)
3 -> npcl("I don't really care as long as no one thinks it's me. Maybe it was that strange poison seller who headed towards the seers village.").also { stage = END_DIALOGUE }
4 -> npcl("I was walking by myself in the garden.").also { stage++ }
5 -> playerl("And can anyone vouch for that?").also { stage++ }
6 -> npcl("No. But I was.").also { stage = END_DIALOGUE }
7 -> sendDialogue(player!!, "You show him the thread you discovered.")
.also { if (inInventory(player!!, Items.CRIMINALS_THREAD_1808)) stage++ else stage = 9 }
8 -> npcl("It's some red thread. I suppose you think that's some kind of clue? It looks like the material my trousers are made of.").also { stage = END_DIALOGUE }
9 -> npcl(FacialExpression.THINKING, "It's some thread. Great clue. No, really.").also { stage = END_DIALOGUE }
10 -> npcl(FacialExpression.THINKING, "What's it to you anyway?").also { stage++ }
11 -> npcl(FacialExpression.ANGRY, "If you absolutely must know, we had a problem with the beehive in the garden, and as all of our servants are so pathetically useless, I decided I would deal with it myself. So I did.")
.also { setAttribute(player!!, attributeAskPoisonBob, true)}
.also { stage = END_DIALOGUE }
}
100 -> npcl("Apparently you aren't as stupid as you look.").also { stage = END_DIALOGUE }
}
}
}

View file

@ -0,0 +1,59 @@
package content.region.kandarin.quest.murdermystery
import content.data.Quests
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributeAskPoisonCarol
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributePoisonClue
import core.api.*
import core.game.dialogue.*
import core.game.node.entity.player.Player
import core.plugin.Initializable
import core.tools.END_DIALOGUE
import org.rs09.consts.Items
import org.rs09.consts.NPCs
@Initializable
class CarolDialogue (player: Player? = null) : DialoguePlugin(player) {
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
openDialogue(player, CarolDialogueFile(), npc)
return true
}
override fun newInstance(player: Player): DialoguePlugin {
return CarolDialogue(player)
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.CAROL_816, NPCs.CAROL_6194)
}
}
class CarolDialogueFile : DialogueFile() {
override fun handle(componentID: Int, buttonID: Int) {
when (getQuestStage(player!!, Quests.MURDER_MYSTERY)){
0 -> sendDialogue(player!!, "They are ignoring you.").also { stage = END_DIALOGUE }
1 -> when (stage) {
0 -> playerl(FacialExpression.NEUTRAL, "I'm here to help the guards with their investigation.").also { stage++ }
1 -> npcl("Well, ask what you want to know then.").also { stage++ }
2 -> showTopics(
Topic("Who do you think is responsible?", 3),
Topic( "Where were you when the murder happened?", 4),
IfTopic("Do you recognise this thread?", 5, inInventory(player!!, Items.CRIMINALS_THREAD_1808) || inInventory(player!!, Items.CRIMINALS_THREAD_1809) || inInventory(player!!, Items.CRIMINALS_THREAD_1810)),
IfTopic("Why'd you buy poison the other day?", 8, getAttribute(player!!, attributePoisonClue, 0) > 0)
)
3 -> npcl("I don't know. I think it's very convenient that you have arrived here so soon after it happened. Maybe it was you.").also { stage = END_DIALOGUE }
4 -> npcl("Why? Are you accusing me of something? You seem to have a very high opinion of yourself. I was in my room if you must know, alone.").also { stage = END_DIALOGUE }
5 -> sendDialogue(player!!, "You show Carol the thread found at the crime scene.")
.also { if (inInventory(player!!, Items.CRIMINALS_THREAD_1808)) stage++ else stage = 7 }
6 -> npcl("It's some red thread... it kind of looks like the Same material as my trousers. But obviously it's not.").also { stage = END_DIALOGUE }
7 -> npcl("It's some thread. Sorry, do you have a point here? Or do you just enjoy wasting peoples time?").also { stage = END_DIALOGUE }
8 -> npcl(FacialExpression.THINKING, "I don't see what on earth it has to do with you, but the drain outside was").also { stage++ }
9 -> npcl(FacialExpression.ANNOYED, "blocked, and as nobody else here has the intelligence to even unblock a simple drain I felt I had to do it myself.")
.also { setAttribute(player!!, attributeAskPoisonCarol, true)}
.also { stage = END_DIALOGUE }
}
100 -> npcl("Apparently you aren't as stupid as you look.").also { stage = END_DIALOGUE }
}
}
}

View file

@ -0,0 +1,60 @@
package content.region.kandarin.quest.murdermystery
import content.data.Quests
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributeAskPoisonDavid
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributePoisonClue
import core.api.*
import core.game.dialogue.*
import core.game.node.entity.player.Player
import core.plugin.Initializable
import core.tools.END_DIALOGUE
import org.rs09.consts.Items
import org.rs09.consts.NPCs
@Initializable
class DavidDialogue (player: Player? = null) : DialoguePlugin(player) {
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
openDialogue(player, DavidDialogueFile(), npc)
return true
}
override fun newInstance(player: Player): DialoguePlugin {
return DavidDialogue(player)
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.DAVID_817, NPCs.DAVID_6195)
}
}
class DavidDialogueFile : DialogueFile() {
override fun handle(componentID: Int, buttonID: Int) {
when (getQuestStage(player!!, Quests.MURDER_MYSTERY)){
0 -> sendDialogue(player!!, "They are ignoring you.").also { stage = END_DIALOGUE }
1 -> when (stage) {
0 -> playerl(FacialExpression.NEUTRAL, "I'm here to help the guards with their investigation.").also { stage++ }
1 -> npcl("And? Make this quick. I have better things to do than be interrogated by halfwits all day.").also { stage++ }
2 -> showTopics(
Topic("Who do you think is responsible?", 3),
Topic( "Where were you when the murder happened?", 5),
IfTopic("Do you recognise this thread?", 6, inInventory(player!!, Items.CRIMINALS_THREAD_1808) || inInventory(player!!, Items.CRIMINALS_THREAD_1809) || inInventory(player!!, Items.CRIMINALS_THREAD_1810)),
IfTopic("Why'd you buy poison the other day?", 9, getAttribute(player!!, attributePoisonClue, 0) > 0)
)
3 -> npcl("I don't really know or care. Frankly, the old man deserved to die.").also { stage++ }
4 -> npcl("There was a suspicious red headed man who came to the house the other day selling poison now I think about it. Last I saw he was headed towards the tavern in the Seers village.").also { stage = END_DIALOGUE }
5 -> npcl("That is none of your business. Are we finished now, or are you just going to stand there irritating me with your idiotic questions all day?").also { stage = END_DIALOGUE }
6 -> sendDialogue(player!!, "You show him the thread you found on the study window.")
.also { if (inInventory(player!!, Items.CRIMINALS_THREAD_1809)) stage++ else stage = 8 }
7 -> npcl("It's some Green thread, like my trousers are made of. Are you finished? I'm not sure which I dislike more bout you, your face or your general bad odour.").also { stage = END_DIALOGUE }
8 -> npcl("No. Can I go yet? Your face irritates me.").also { stage = END_DIALOGUE }
9 -> npcl(FacialExpression.ANGRY, "There was a nest of spiders upstairs between the two servants' quarters. Obviously I had to kill them before our pathetic servants whined at my father some more.").also { stage++ }
10 -> npcl(FacialExpression.THINKING, "Honestly, it's like they expect to be treated like royalty! If I had my way I would fire the whole workshy lot of them!")
.also { setAttribute(player!!, attributeAskPoisonDavid, true)}
.also { stage = END_DIALOGUE }
}
100 -> npcl("Apparently you aren't as stupid as you look.").also { stage = END_DIALOGUE }
}
}
}

View file

@ -0,0 +1,57 @@
package content.region.kandarin.quest.murdermystery
import content.data.Quests
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributeNoiseClue
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributePoisonClue
import core.api.*
import core.game.dialogue.*
import core.game.node.entity.player.Player
import core.plugin.Initializable
import core.tools.END_DIALOGUE
import org.rs09.consts.NPCs
@Initializable
class DonovanDialogue (player: Player? = null) : DialoguePlugin(player) {
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
openDialogue(player, DonovanDialogueFile(), npc)
return true
}
override fun newInstance(player: Player): DialoguePlugin {
return DonovanDialogue(player)
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.DONOVAN_THE_FAMILY_HANDYMAN_806)
}
}
class DonovanDialogueFile : DialogueFile() {
override fun handle(componentID: Int, buttonID: Int) {
when (getQuestStage(player!!, Quests.MURDER_MYSTERY)){
0 -> npcl("I have no interest in talking to gawkers.").also { stage = END_DIALOGUE }
1 -> when (stage) {
0 -> playerl("I'm here to help the guards with their investigation.").also { stage++ }
1 -> npcl("How can I help?").also { stage++ }
2 -> showTopics(
Topic("Who do you think is responsible?", 3),
Topic( "Where were you at the time of the murder?", 5),
IfTopic("Did you hear any suspicious noises at all?", 6, getAttribute(player!!, attributeNoiseClue, false)),
IfTopic("Do you know why so much poison was bought recently?", 9, getAttribute(player!!, attributePoisonClue, 0) > 0)
)
3 -> npcl("Oh... I really couldn't say. I wouldn't really want to point any fingers at anybody. If I had to make a guess I'd have to say it was probably Bob though.").also { stage++ }
4 -> npcl("I saw him arguing with Lord Sinclair about some missing silverware from the Kitchen. It was a very heated argument.").also { stage = END_DIALOGUE }
5 -> npcl("Me? I was sound asleep here in the servants Quarters. It's very hard work as a handyman around here. There's always something to do!").also { stage = END_DIALOGUE }
6 -> npcl("Hmmm... No, I didn't, but I sleep very soundly at night.").also { stage++ }
7 -> playerl("So you didn't hear any sounds of a struggle or any barking from the guard dog next to his study window?").also { stage++ }
8 -> npcl("Now you mention it, no. It is odd I didn't hear anything like that. But I do sleep very soundly as I said and wouldn't necessarily have heard it if there was any such noise.").also { stage = END_DIALOGUE }
9 -> npcl("Well, I do know Frank bought some poison recently to clean the family crest that's outside.").also { stage++ }
10 -> npcl("It's very old and rusty, and I couldn't clean it myself, so he said he would buy some cleaner and clean it himself. He probably just got some from that Poison Salesman who came to the door the other day...").also { stage++ }
11 -> npcl("You'd really have to ask him though.").also { stage = END_DIALOGUE }
}
100 -> npcl("Thank you for all your help in solving the murder.").also { stage = END_DIALOGUE }
}
}
}

View file

@ -0,0 +1,64 @@
package content.region.kandarin.quest.murdermystery
import content.data.Quests
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributeAskPoisonElizabeth
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributePoisonClue
import core.api.*
import core.game.dialogue.*
import core.game.node.entity.player.Player
import core.plugin.Initializable
import core.tools.END_DIALOGUE
import org.rs09.consts.Items
import org.rs09.consts.NPCs
@Initializable
class ElizabethDialogue (player: Player? = null) : DialoguePlugin(player) {
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
openDialogue(player, ElizabethDialogueFile(), npc)
return true
}
override fun newInstance(player: Player): DialoguePlugin {
return ElizabethDialogue(player)
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.ELIZABETH_818, NPCs.ELIZABETH_6196)
}
}
class ElizabethDialogueFile : DialogueFile() {
override fun handle(componentID: Int, buttonID: Int) {
when (getQuestStage(player!!, Quests.MURDER_MYSTERY)){
0 -> sendDialogue(player!!, "They are ignoring you.").also { stage = END_DIALOGUE }
1 -> when (stage) {
0 -> playerl(FacialExpression.NEUTRAL, "I'm here to help the guards with their investigation.").also { stage++ }
1 -> npcl("What's so important you need to bother me with then?").also { stage++ }
2 -> showTopics(
Topic("Who do you think is responsible?", 3),
Topic( "Where were you when the murder happened?", 4),
IfTopic("Do you recognise this thread?", 7, inInventory(player!!, Items.CRIMINALS_THREAD_1808) || inInventory(player!!, Items.CRIMINALS_THREAD_1809) || inInventory(player!!, Items.CRIMINALS_THREAD_1810)),
IfTopic("Why'd you buy poison the other day?", 12, getAttribute(player!!, attributePoisonClue, 0) > 0)
)
3 -> npcl("Could have been anyone. The old man was an idiot. He's been asking for it for years.").also { stage = END_DIALOGUE }
4 -> npcl("I was out.").also { stage++ }
5 -> playerl("Care to be any more specific?").also { stage++ }
6 -> npcl("Not really. I don't have to justify myself to the likes of you, you know. I know the King personally you know. Now are we finished here?").also { stage = END_DIALOGUE }
7 -> sendDialogue(player!!, "You show her the thread from the study window.")
.also { if (inInventory(player!!, Items.CRIMINALS_THREAD_1810)) stage++ else stage = 11 }
8 -> npcl(" Looks like Blue thread to me. If you can't work that out for yourself I don't hold much hope of you solving this crime.").also { stage++ }
9 -> playerl("It looks a lot like the material your trousers are made of doesn't it?").also { stage++ }
10 -> npcl("I suppose it does. So what?").also { stage = END_DIALOGUE }
11 -> npcl(" It's some thread. You're not very good at this whole investigation thing are you?").also { stage = END_DIALOGUE }
12 -> npcl("There was a nest of mosquitos under the fountain in the garden, which I killed with poison the other day. You can see for yourself if you're capable of managing that, which I somehow doubt.").also { stage++ }
13 -> playerl(FacialExpression.ANNOYED, "I hate mosquitos!").also { stage++ }
14 -> npcl("Doesn't everyone?")
.also { setAttribute(player!!, attributeAskPoisonElizabeth, true)}
.also { stage = END_DIALOGUE }
}
100 -> npcl("Apparently you aren't as stupid as you look.").also { stage = END_DIALOGUE }
}
}
}

View file

@ -0,0 +1,26 @@
package content.region.kandarin.quest.murdermystery
import core.api.*
import core.game.dialogue.DialogueFile
import core.tools.END_DIALOGUE
import org.rs09.consts.Items
class FlypaperDialogue : DialogueFile() {
override fun handle(componentID: Int, buttonID: Int) {
when (stage) {
0 -> sendDialogue(player!!, "There's some flypaper in there. Should I take it?").also { stage++ }
1 -> options("Yes, it might be useful.", "No, I don't see any need for it.").also { stage++ }
2 -> when(buttonID) {
1 -> if (addItem(player!!, Items.FLYPAPER_1811)){
sendDialogue(player!!, "You take a piece of fly paper. There is still plenty of fly paper left.")
.also { stage = END_DIALOGUE }
}
else {
sendDialogue(player!!, "You don't have enough space in your inventory.")
.also { stage = END_DIALOGUE }
}
2 -> sendDialogue(player!!, "You leave the paper in the sack.").also { stage = END_DIALOGUE }
}
}
}
}

View file

@ -0,0 +1,15 @@
package content.region.kandarin.quest.murdermystery
import core.api.*
import core.game.dialogue.DialogueFile
import core.tools.END_DIALOGUE
class FountainDialogue : DialogueFile() {
override fun handle(componentID: Int, buttonID: Int) {
when (stage) {
0 -> sendDialogue(player!!, "The fountain is swarming with mosquitos. There's a nest of them underneath the fountain.").also { stage++ }
1 -> playerl("I hate mosquitos, they're so annoying!").also { stage++ }
2 -> sendDialogue(player!!, "It's certainly clear nobody's used poison here.").also { stage = END_DIALOGUE }
}
}
}

View file

@ -0,0 +1,60 @@
package content.region.kandarin.quest.murdermystery
import content.data.Quests
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributeAskPoisonFrank
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributePoisonClue
import core.api.*
import core.game.dialogue.*
import core.game.node.entity.player.Player
import core.plugin.Initializable
import core.tools.END_DIALOGUE
import org.rs09.consts.Items
import org.rs09.consts.NPCs
@Initializable
class FrankDialogue (player: Player? = null) : DialoguePlugin(player) {
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
openDialogue(player, FrankDialogueFile(), npc)
return true
}
override fun newInstance(player: Player): DialoguePlugin {
return FrankDialogue(player)
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.FRANK_819, NPCs.FRANK_6197)
}
}
class FrankDialogueFile : DialogueFile() {
override fun handle(componentID: Int, buttonID: Int) {
when (getQuestStage(player!!, Quests.MURDER_MYSTERY)){
0 -> sendDialogue(player!!, "They are ignoring you.").also { stage = END_DIALOGUE }
1 -> when (stage) {
0 -> playerl(FacialExpression.NEUTRAL, "I'm here to help the guards with their investigation.").also { stage++ }
1 -> npcl("Good for you. Now what do you want?").also { stage++ }
2 -> npcl(FacialExpression.SAD, "...And can you spare me any money? I'm a little short...").also { stage++ }
3 -> showTopics(
Topic("Who do you think is responsible?", 4),
Topic( "Where were you when the murder happened?", 5),
IfTopic("Do you recognise this thread?", 6, inInventory(player!!, Items.CRIMINALS_THREAD_1808) || inInventory(player!!, Items.CRIMINALS_THREAD_1809) || inInventory(player!!, Items.CRIMINALS_THREAD_1810)),
IfTopic("Why'd you buy poison the other day?", 9, getAttribute(player!!, attributePoisonClue, 0) > 0)
)
4 -> npcl("I don't know. You don't know how long it takes an inheritance to come through do you? I could really use that money pretty soon...").also { stage = END_DIALOGUE }
5 -> npcl("I don't know, somewhere around here probably. Could you spare me a few coins? I'll be able to pay you back double tomorrow it's just there's this poker night tonight in town...").also { stage = END_DIALOGUE }
6 -> sendDialogue(player!!, "Frank examines the thread from the crime scene.")
.also { if (inInventory(player!!, Items.CRIMINALS_THREAD_1810)) stage++ else stage = 8 }
7 -> npcl("It kind of looks like the same material as my trousers are made of... same colour anyway. Think it's worth anything? Can I have it? Or just some money?").also { stage = END_DIALOGUE }
8 -> npcl("It looks like thread to me, but I'm not exactly an expert. Is it worth something? Can I have it? Actually, can you spare me a few gold?").also { stage = END_DIALOGUE }
9 -> npcl("Would you like to buy some? I'm kind of strapped for cash right now. I'll sell it to you cheap. It's hardly been used at all.").also { stage++ }
10 -> npcl("I just used a bit to clean that family crest outside up a bit. Do you think I could get much money for the family crest, actually? It's cleaned up a bit now.")
.also { setAttribute(player!!, attributeAskPoisonFrank, true)}
.also { stage = END_DIALOGUE }
}
100 -> npcl("Apparently you aren't as stupid as you look.").also { stage = END_DIALOGUE }
}
}
}

View file

@ -0,0 +1,133 @@
package content.region.kandarin.quest.murdermystery
import content.data.Quests
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributeNoiseClue
import core.api.*
import core.game.dialogue.*
import core.game.node.entity.player.Player
import core.plugin.Initializable
import core.tools.END_DIALOGUE
import core.tools.RandomFunction
import org.rs09.consts.NPCs
@Initializable
class GossipDialogue (player: Player? = null) : DialoguePlugin(player) {
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
openDialogue(player, GossipDialogueFile(), npc)
return true
}
override fun newInstance(player: Player): DialoguePlugin {
return GossipDialogue(player)
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.GOSSIP_813)
}
}
class GossipDialogueFile : DialogueFile() {
override fun handle(componentID: Int, buttonID: Int) {
when (getQuestStage(player!!, Quests.MURDER_MYSTERY)){
0 -> npcl("There's some kind of commotion up at the Sinclair place I hear. Not surprising all things considered.").also { stage = END_DIALOGUE}
1 -> when (stage) {
0 -> playerl("I'm investigating the murder up at the Sinclair place.").also { stage++ }
1 -> npcl("Murder is it? Well, I'm not really surprised...").also { stage++ }
2 -> options("What can you tell me about the Sinclairs?", "Who do you think was responsible?", "I think the butler did it.", "I am so confused about who did it.").also { stage++ }
3 -> when(buttonID) {
1 -> playerl("What can you tell me about the Sinclairs?").also { stage = 4 }
2 -> playerl("Who do you think was responsible?").also { stage = 40 }
3 -> playerl("I think the butler did it.").also { stage = 42 }
4 -> playerl("I am so confused about who did it.").also { stage = 43 }
}
4 -> npcl("Well, what do you want to know?").also { stage++ }
5 -> options("Tell me about Lord Sinclair.", "Why do the Sinclairs live so far from town?", "What can you tell me about his sons?", "What can you tell me about his daughters?").also { stage++ }
6 -> when(buttonID) {
1 -> playerl("Tell me about Lord Sinclair.").also { stage = 7 }
2 -> playerl("Why do the Sinclairs live so far from town?").also { stage = 10 }
3 -> playerl("What can you tell me about his sons?").also { stage = 12 }
4 -> playerl("What can you tell me about his daughters?").also { stage = 15 }
}
7 -> npcl("Old Lord Sinclair was a great man with a lot of respect around these parts. More than his worthless children have anyway.").also { stage++ }
8 -> playerl("His children? They have something to gain by his death?").also { stage++ }
9 -> npcl("Yes. You could say that. Not that I am one to gossip.").also { stage = END_DIALOGUE }
10 -> npcl("Well, they used to live in the big castle, but old Lord Sinclair gave it up so that those strange knights could live there instead. So the king built him a new house to the North.").also { stage++ }
11 -> npcl("It's more cramped than his old place, but he seemed to like it. His children were furious at him for doing it though!").also { stage = END_DIALOGUE }
12 -> npcl("His sons eh? They all have their own skeletons in their cupboards. You'll have to be more specific. Who are you interested in exactly?").also { stage++ }
13 -> options("Tell me about Bob.", "Tell me about David.", "Tell me about Frank.").also { stage++ }
14 -> when(buttonID) {
1 -> playerl("Tell me about Bob.").also { stage = 18 }
2 -> playerl("Tell me about David.").also { stage = 23 }
3 -> playerl("Tell me about Frank.").also { stage = 27 }
}
15 -> npcl("His daughters eh? They're all nasty pieces of work, which of them specifically did you want to know about?").also { stage++ }
16 -> options("Tell me about Anna.", "Tell me about Carol.", "Tell me about Elizabeth.").also { stage++ }
17 -> when(buttonID) {
1 -> playerl("Tell me about Anna.").also { stage = 30 }
2 -> playerl("Tell me about Carol.").also { stage = 33 }
3 -> playerl("Tell me about Elizabeth.").also { stage = 36 }
}
18 -> npcl("Bob is an odd character indeed... I'm not one to gossip, but I heard Bob is addicted to Tea. He can't make").also { stage++ }
19 -> npcl("it through the day without having at least 20 cups!").also { stage++ }
20 -> npcl("You might not think that's such a big thing, but he has spent thousands of gold to feed his habit!").also { stage++ }
21 -> npcl("At one point he stole a lot of silverware from the kitchen and pawned it just so he could afford to buy his daily tea allowance.").also { stage++ }
22 -> npcl("If his father ever found out, he would be in so much trouble... he might even get disowned!").also { stage = END_DIALOGUE }
23 -> npcl("David... oh David... not many people know this, but David really has an anger problem. He's always screaming and shouting").also { stage++ }
24 -> npcl("at the household servants when he's angry, and they live in a state of fear, always walking on eggshells around him, but none of them have the courage").also { stage++ }
25 -> npcl("to talk to his father about his behaviour. If they did, Lord Sinclair would almost certainly").also { stage++ }
26 -> npcl("kick him out of the house, as some of the servants have been there longer than he has, and he definitely has no right to treat them like he does... but I'm not one to gossip about people.").also { stage = END_DIALOGUE }
27 -> npcl("I'm not one to talk ill of people behind their back, but Frank is a real piece of work. He is an absolutely terrible gambler...he can't pass 2 dogs in the street without putting a bet on which one will bark first!").also { stage++ }
28 -> npcl("He has already squandered all of his allowance, and I heard he had stolen a number of paintings of his fathers to sell to try and cover his debts, but he still owes a lot of people a lot of").also { stage++ }
29 -> npcl("money. If his father ever found out, he would stop his income, and then he would be in serious trouble!").also { stage = END_DIALOGUE }
30 -> npcl("Anna... ah yes... Anna has 2 great loves:").also { stage++ }
31 -> npcl("Sewing and gardening. But one thing she has kept secret is that she once had an affair with Stanford the gardener, and tried to get him fired when they broke up,").also { stage++ }
32 -> npcl("by killing all of the flowers in the garden. If her father ever found out she had done that he would be so furious he would probably disown her.").also { stage = END_DIALOGUE }
33 -> npcl("Oh Carol... she is such a fool. You didn't hear this from me, but I heard a while ago she was conned out of a lot of money by a travelling salesman who sold her a box full").also { stage++ }
34 -> npcl("of beans by telling her they were magic. But they weren't. She sold some rare books from the library to cover her debts, but").also { stage++ }
35 -> npcl("her father would be incredibly annoyed if he ever found out - he might even throw her out of the house!").also { stage = END_DIALOGUE }
36 -> npcl("Elizabeth? Elizabeth has a strange problem... She cannot help herself, but is always stealing small objects - it's pretty sad that she is rich enough to afford to buy things, but would rather steal them instead.").also { stage++ }
37 -> npcl("Now, I don't want to spread stories, but I heard she even stole a silver needle from her father that had great sentimental value for him.").also { stage++ }
38 -> npcl("He was devastated when it was lost, and cried for a week thinking he had lost it!").also { stage++ }
39 -> npcl("If he ever found out that it was her who had stolen it he would go absolutely mental, maybe even disowning her!").also { stage = END_DIALOGUE }
40 -> npcl("Well, I guess it could have been an intruder, but with that big guard dog of theirs I seriously doubt it. I suspect it was someone closer to home...").also { stage ++ }
41 -> npcl("Especially as I heard that the poison salesman in the Seers' village made a big sale to one of the family the other day.")
.also { setAttribute(player!!, attributeNoiseClue, true)}
.also { stage = END_DIALOGUE }
42 -> npcl("And I think you've been reading too many cheap detective novels. Hobbes is kind of uptight, but his loyalty to old Lord Sinclair is beyond question.").also { stage = END_DIALOGUE }
43 -> playerl("Think you could give me any hints?")
.also { when (RandomFunction.random(4)) { //RS3 wiki seems to indicate this is fully random, not based off of progression
0 -> stage = 44
1 -> stage = 46
2 -> stage = 47
3 -> stage = 48
4 -> stage = 51
}
}
44 -> npcl("Well, I don't know if it's related, but I heard from that Poison Salesman in town that he sold some poison to one of the Sinclair family").also { stage++ }
45 -> npcl("the other day. I don't think he has any stock left now though...").also { stage = END_DIALOGUE }
46 -> npcl("Well, I don't know how much help this is, but I heard their guard dog will bark loudly at anyone it doesn't recognise. Maybe you should find out if anyone heard anything suspicious?")
.also { stage = END_DIALOGUE }
47 -> npcl("Well, this might be of some help to you. My father was in the guards when he was younger and he always said that there isn't a crime that can't be solved through careful examination of the crime scene and all surrounding areas.").also { stage = END_DIALOGUE }
48 -> npcl("I don't know how much help this is to you, but my dad was in the guard once and he told me the marks on your hands are totally unique. He calls them 'finger prints'.").also { stage++ }
49 -> npcl("He said you can find them easily on any shiny metallic surface, by using a fine powder to mark out where the marks are and then using some sticky paper to lift the print from the object.").also { stage++ }
50 -> npcl("I bet if you could find a way to get everyone's 'finger prints' you could solve the crime pretty easily!").also { stage = END_DIALOGUE }
51 -> npcl("My father used to be in the guard, he always wrote himself notes on a piece of paper so he could keep track of information easily.").also { stage++ }
52 -> npcl("Maybe you should try that? Don't forget to thank me if I help you solve the case!").also { stage = END_DIALOGUE }
}
}
}
}

View file

@ -0,0 +1,220 @@
package content.region.kandarin.quest.murdermystery
import content.data.Quests
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributePoisonClue
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributeRandomMurderer
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.clueCount
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.solvedMystery
import core.ServerConstants.Companion.SERVER_NAME
import core.api.*
import core.game.dialogue.*
import core.game.node.entity.player.Player
import core.plugin.Initializable
import core.tools.END_DIALOGUE
import core.tools.RandomFunction
import org.rs09.consts.Items
import org.rs09.consts.NPCs
@Initializable
class GuardDialogue (player: Player? = null) : DialoguePlugin(player) {
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
openDialogue(player, GuardDialogueFile(), npc)
return true
}
override fun newInstance(player: Player): DialoguePlugin {
return GuardDialogue(player)
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.GUARD_812, NPCs.GUARD_6191)
}
}
class GuardDialogueFile : DialogueFile() {
override fun handle(componentID: Int, buttonID: Int) {
val KILLER = when (getAttribute(player!!, attributeRandomMurderer, 0)) {
0 -> "Anna"
1 -> "Bob"
2 -> "Carol"
3 -> "David"
4 -> "Elizabeth"
5 -> "Frank"
else -> "Anna"
}
val POISONSPOT = when (getAttribute(player!!, attributeRandomMurderer, 0)) {
0 -> "compost heap"
1 -> "beehive"
2 -> "drain"
3 -> "spiders nest"
4 -> "fountain"
5 -> "Sinclair Crest"
else -> "compost heap"
}
val KILLERMALE = when (getAttribute(player!!, attributeRandomMurderer, 0)) {
1, 3, 5 -> true
else -> false
}
val EVIDENCE = (1796..1822).toList().toIntArray() //All Murder Mystery related items are between these item ids
when (getQuestStage(player!!, Quests.MURDER_MYSTERY)){
0 -> when (stage) {
0 -> playerl(FacialExpression.NEUTRAL, "What's going on here?").also { stage++ }
1 -> npcl(FacialExpression.SAD, "Oh, it's terrible! Lord Sinclair has been murdered and we don't have any clues as to who or why. We're totally baffled!").also { stage++ }
2 -> npcl(FacialExpression.SAD, "If you can help us we will be very grateful.").also { stage++ }
3 -> options("Sure, I'll help.", "You should do your own dirty work.").also { stage++ }
4 -> when (buttonID) {
1 -> playerl(FacialExpression.HAPPY, "Sure, I'll help.").also { stage++ }
2 -> playerl("You should do your own dirty work.").also { stage = 8 }
}
5 -> npcl(FacialExpression.HAPPY, "Thanks a lot!").also { stage++ }
6 -> playerl(FacialExpression.NEUTRAL, "What should I be doing to help?").also { stage++ }
7 -> npcl(FacialExpression.NEUTRAL, "Look around and investigate who might be responsible. The Sarge said every murder leaves clues to who done it, but frankly we're out of our depth here.")
.also { setAttribute(player!!, attributeRandomMurderer, RandomFunction.random(5))}
.also { setQuestStage(player!!, Quests.MURDER_MYSTERY, 1) }
.also { stage = END_DIALOGUE }
8 -> npcl("Get lost then, this is private property! ...Unless you'd like to be taken in for questioning yourself?").also { stage = END_DIALOGUE }
}
1 -> when (stage) {
0 -> options("What should I be doing to help again?", "How did Lord Sinclair die?", "I know who did it!").also { stage++ }
1 -> when(buttonID) {
1 -> playerl("What should I be doing to help?").also { stage = 2 }
2 -> playerl("How did Lord Sinclair die?").also { stage = 3 }
3 -> playerl(FacialExpression.HAPPY, "I know who did it!")
.also {
stage = if (solvedMystery(player!!)) 46
else if (clueCount(player!!) == 1) {
if (inInventory(player!!, Items.KILLERS_PRINT_1815)) {
41
}
else if (getAttribute(player!!, attributePoisonClue,0) == 2) {
37
}
else 33
}
else if (clueCount(player!!) > 1) 32
else 6
}
}
2 -> npcl("Look around and investigate who might be responsible. The Sarge said every murder leaves clues to who done it, but frankly we're out of our depth here.").also { stage = END_DIALOGUE }
3 -> npcl("Well, it's all very mysterious. Mary, the maid, found the body in the study next to his bedroom on the east wing of the ground floor.").also { stage++ }
4 -> npcl("The door was found locked from the inside, and he seemed to have been stabbed, but there was an odd smell in the room. Frankly, I'm stumped.").also { stage = END_DIALOGUE }
5 -> npcl("Really? That was quick work! Who?").also { stage++ }
6 -> options("It was an intruder!", "The butler did it!", "It was one of the servants!", "It was one of his family!").also { stage++ }
7 -> when (buttonID) {
1 -> playerl("It was an intruder!").also { stage = 10 }
2 -> playerl("The butler did it!").also { stage = 8 }
3 -> playerl("It was one of the servants!").also { stage = 13 }
4 -> playerl("It was one of his family!").also { stage = 20 }
}
8 -> npcl("I hope you have proof to that effect. We have to arrest someone for this and it seems to me that only the actual murderer would gain by falsely accusing someone.").also { stage++ }
9 -> npcl("Although having said that the butler is kind of shifty looking...").also { stage = END_DIALOGUE }
10 -> npcl("That's what we were thinking too. That someone broke in to steal something, was discovered by Lord Sinclair, stabbed him and ran.").also { stage++ }
11 -> npcl("It's odd that apparently nothing was stolen though... Find out something has been stolen,").also { stage++ }
12 -> npcl("and the case is closed, but the murdered man was a friend of the King and it's more than my job's worth not to investigate fully.").also { stage = END_DIALOGUE }
13 -> npcl("Oh really? Which one?").also { stage++ }
14 -> options("It was one of the women.", "It was one of the men.").also { stage++ }
15 -> when (buttonID) {
1 -> playerl("It was one of the women.").also { stage = 16 }
2 -> playerl("It was one of the men.").also { stage = 18 }
}
16 -> options("It was so obviously Louisa The Cook.", "It must have been Mary The Maid.").also { stage++ }
17 -> when (buttonID) {
1 -> playerl("It was so obviously Louisa The Cook.").also { stage = 27 }
2 -> playerl("It must have been Mary The Maid.").also { stage = 27 }
}
18 -> options("It can only be Donovan the Handyman.", "Pierre the Dog Handler. No question", "Hobbes the Butler. The butler *always* did it.", "You must know it was Stanford The Gardener.").also { stage++ }
19-> when (buttonID) {
1 -> playerl("It can only be Donovan the Handyman.").also { stage = 27 }
2 -> playerl("Pierre the Dog Handler. No question.").also { stage = 27 }
3 -> playerl("Hobbes the Butler. The butler *always* did it.").also { stage = 8 }
4 -> playerl("You must know it was Stanford The Gardener.").also { stage = 27 }
}
20 -> npcl("Oh really? Which one?").also { stage++ }
21 -> options("It was one of the women.", "It was one of the men.").also { stage++ }
22 -> when (buttonID) {
1 -> playerl("It was one of the women.").also { stage = 23 }
2 -> playerl("It was one of the men.").also { stage = 25 }
}
23 -> options("I know it was Anna.", "I am so sure it was Carol.", "I'll bet you anything it was Elizabeth.").also { stage++ }
24 -> when (buttonID) {
1 -> playerl("I know it was Anna.").also { stage = 27 }
2 -> playerl("I am so sure it was Carol.").also { stage = 27 }
3 -> playerl("I'll bet you anything it was Elizabeth.").also { stage = 27 }
}
25 -> options("I'm certain it was Bob.", "It was David. No doubt about it.", "If it wasn't Frank I'll eat my shoes.").also { stage++ }
26 -> when (buttonID) {
1 -> playerl("I'm certain it was Bob.").also { stage = 27 }
2 -> playerl("It was David. No doubt about it.").also { stage = 27 }
3 -> playerl("If it wasn't Frank I'll eat my shoes.").also { stage = 27 }
}
27 -> sendDialogue(player!!, "You tell the guard who you suspect of the crime.").also { stage++ }
28 -> npcl("Great work, show me the evidence and we'll take them to the dungeons.").also { stage++ }
29 -> npcl("You *DO* have evidence of their crime, right?").also { stage++ }
30 -> playerl("Uh...").also { stage++ }
31 -> npcl("Tch. You wouldn't last a day in the guards with sloppy thinking like that. Come see me when you have some proof of your accusations.").also { stage = END_DIALOGUE }
32 -> showTopics(
IfTopic("I have proof that it wasn't any of the servants.", 33, inInventory(player!!, Items.CRIMINALS_THREAD_1808) || inInventory(player!!, Items.CRIMINALS_THREAD_1809) || inInventory(player!!, Items.CRIMINALS_THREAD_1810), true),
IfTopic("I have proof one of the family lied about the poison.", 37, getAttribute(player!!, attributePoisonClue, 0) == 2, true),
IfTopic("I have the finger prints of the culprit.", 41, inInventory(player!!, Items.KILLERS_PRINT_1815), true)
)
33 -> playerl("I have proof that it wasn't any of the servants!").also { stage++ }
34 -> sendDialogue(player!!, "You show the guard the thread you found on the window.").also { stage ++ }
35 -> playerl("All the servants dress in black so it couldn't have been one of them.").also { stage++ }
36 -> npcl("That's some good work there. I guess it wasn't a servant. You still haven't proved who did do it though.").also { stage = END_DIALOGUE }
37 -> playerl("I have proof that $KILLER is lying about the poison.").also { stage++ }
38 -> npcl("Oh really? How did you get that?").also { stage++ }
39 -> sendDialogue(player!!, "You tell the guard about the " +
when (getAttribute(player!!, attributeRandomMurderer, 0)) {
4 -> "mosquitos at the fountain."
5 -> "tarnished family crest."
else -> "$POISONSPOT."
}).also { stage++ }
40 -> npcl("Hmm. That's some good detective work there, we need more evidence before we can close the case though. Keep up the good work.").also { stage = END_DIALOGUE }
41 -> playerl("I have the fingerprints of the culprit!").also { stage++ }
42 -> playerl("I have $KILLER's fingerprints here, you can see for yourself they match the fingerprints on the murder weapon exactly.").also { stage++ }
43 -> sendDialogue(player!!,"You show the guard the finger prints evidence.").also { stage++ }
44 -> npcl("... I'm impressed. How on earth did you think of something like that? I've never heard of such a technique for finding criminals before!").also { stage++ }
45 -> npcl("This will come in very handy in the future but we can't arrest someone on just this. I'm afraid you'll still need to find more evidence before we can close this case completely.").also { stage = END_DIALOGUE }
46 -> playerl(FacialExpression.HAPPY, "I have conclusive proof who the killer was.").also { stage++ }
47 -> npcl(FacialExpression.HAPPY, "You do? That's excellent work. Let's hear it then.").also { stage++ }
48 -> playerl("I don't think it was an intruder, and I don't think Lord Sinclair was killed by being stabbed.").also { stage++ }
49 -> npcl("Hmmm? Really? Why not?").also { stage++ }
50 -> playerl(FacialExpression.HAPPY, "Nobody heard the guard dog barking, which it would have if it had been an intruder who was responsible.").also { stage++ }
51 -> playerl("Nobody heard any signs of a struggle either. I think the knife was there to throw suspicion away from the real culprit.").also { stage++ }
52 -> npcl("Yes, that makes sense. But who did do it then?").also { stage++ }
53 -> sendDialogue(player!!, "You prove to the guard the thread matches $KILLER's clothes.").also { stage++ }
54 -> npcl("Yes, I'd have to agree with that... but we need more evidence!").also { stage++ }
55 -> sendDialogue(player!!, "You prove to the guard $KILLER did not use the poison on the $POISONSPOT.").also { stage++ }
56 -> npcl("Excellent work - have you considered a career as a detective? But I'm afraid it's still not quite enough...").also { stage++ }
57 -> sendDialogue(player!!, "You match $KILLER's finger prints with those on the dagger found in the body of Lord Sinclair.").also { stage++ }
58 -> npcl(FacialExpression.HAPPY, "Yes. There's no doubt about it. It must have been $KILLER who killed " + if (KILLERMALE) {"his"} else {"her"} + " father. All of the guards must congratulate you on your excellent work in helping us to solve this case.").also { stage++ }
59 -> npcl("We don't have many murders here in $SERVER_NAME and I'm afraid we wouldn't have been able to solve it by ourselves. We will hold " + if (KILLERMALE) {"him"} else {"her"} + " here under house arrest until such time as we bring " + if (KILLERMALE) {"him"} else {"her"} + " to trial.").also { stage++ }
60 -> npcl("You have our gratitude, and I'm sure the rest of the family's as well, in helping to apprehend the murderer. I'll just take the evidence from you now.").also { stage++ }
61 -> sendDialogue(player!!, "You hand over all the evidence.").also { stage++ }
62 -> npcl(FacialExpression.HAPPY, "Please accept this reward from the family!").also { stage++ }
63 -> finishQuest(player!!, Quests.MURDER_MYSTERY)
.also {
player!!.inventory.removeAll(EVIDENCE)
player!!.bank.removeAll(EVIDENCE)
player!!.equipment.removeAll(EVIDENCE)
}
.also { stage = END_DIALOGUE }
}
100 -> when (stage) {
0 -> npcl("Excellent work on solving the murder! All of the guards I know are very impressed, and don't worry, we have the murderer under guard until they can be taken to trial.").also { stage++ }
1 -> playerl("Is there anything else I can do? Seems awfully quiet up at the house, considering their sibling has just been arrested.").also { stage++ }
2 -> npcl("Nothing right now, we have it all under control.").also { stage = END_DIALOGUE }
}
}
}
}

View file

@ -0,0 +1,62 @@
package content.region.kandarin.quest.murdermystery
import content.data.Quests
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributeNoiseClue
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributePoisonClue
import core.api.*
import core.game.dialogue.*
import core.game.node.entity.player.Player
import core.plugin.Initializable
import core.tools.END_DIALOGUE
import org.rs09.consts.NPCs
@Initializable
class HobbesDialogue (player: Player? = null) : DialoguePlugin(player) {
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
openDialogue(player, HobbesDialogueFile(), npc)
return true
}
override fun newInstance(player: Player): DialoguePlugin {
return HobbesDialogue(player)
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.HOBBES_808)
}
}
class HobbesDialogueFile : DialogueFile() {
override fun handle(componentID: Int, buttonID: Int) {
when (getQuestStage(player!!, Quests.MURDER_MYSTERY)){
0 -> npcl("This is private property! Please leave!").also { stage = END_DIALOGUE }
1 -> when (stage) {
0 -> playerl(FacialExpression.NEUTRAL, "I'm here to help the guards with their investigation.").also { stage++ }
1 -> npcl(FacialExpression.ASKING, "How can I help?").also { stage++ }
2 -> showTopics(
Topic("Who do you think is responsible?", 3),
Topic( "Where were you at the time of the murder?", 6),
IfTopic("Did you hear any suspicious noises at all?", 7, getAttribute(player!!, attributeNoiseClue, false)),
IfTopic("Do you know why so much poison was bought recently?", 12, getAttribute(player!!, attributePoisonClue, 0) > 0)
)
3 -> npcl("Well, in my considered opinion it must be David. The man is nothing more than a bully And I happen to know that poor Lord Sinclair and David had a massive argument in the living").also { stage++ }
4 -> npcl("room about the way he treats the staff, the other day. I did not intend to overhear their conversation, but they were shouting so loudly I could not help but Overhear it. David definitely used the words").also { stage++ }
5 -> npcl("'I am going to kill you!' as well. I think he should be the prime suspect. He has a nasty temper that one.").also { stage = END_DIALOGUE }
6 -> npcl("I was assisting the cook with the evening meal. I gave Mary His Lordships' dinner, and sent her to take it to him, then heard the scream as she found the body.").also { stage = END_DIALOGUE }
7 -> npcl("How do you mean 'suspicious'?").also { stage++ }
8 -> playerl("Any sounds of a struggle with Lord Sinclair?").also { stage++ }
9 -> npcl("No, I definitely didn't hear anything like that.").also { stage++ }
10 -> playerl("How about the guard dog barking at all?").also { stage++ }
11 -> npcl("You know, now you come to mention it I don't believe I did. I suppose that is Proof enough that it could not have been an intruder who is responsible.").also { stage = END_DIALOGUE }
12 -> npcl("Well, I do know that Elizabeth was extremely annoyed by the mosquito nest under the fountain in the garden, and was going to do something about it. I suspect any poison she bought would have been").also { stage++ }
13 -> npcl ("enough to get rid of it. A Good job, too. I hate mosquitos.").also { stage++ }
14 -> playerl("Yeah, so do I.").also { stage++ }
15 -> npcl("You'd really have to ask her though.").also { stage = END_DIALOGUE }
}
100 -> npcl("Thank you for all your help in solving the murder.").also { stage = END_DIALOGUE }
}
}
}

View file

@ -0,0 +1,59 @@
package content.region.kandarin.quest.murdermystery
import content.data.Quests
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributeNoiseClue
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributePoisonClue
import core.api.*
import core.game.dialogue.*
import core.game.node.entity.player.Player
import core.plugin.Initializable
import core.tools.END_DIALOGUE
import org.rs09.consts.NPCs
@Initializable
class LouisaDialogue (player: Player? = null) : DialoguePlugin(player) {
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
openDialogue(player, LouisaDialogueFile(), npc)
return true
}
override fun newInstance(player: Player): DialoguePlugin {
return LouisaDialogue(player)
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.LOUISA_809)
}
}
class LouisaDialogueFile : DialogueFile() {
override fun handle(componentID: Int, buttonID: Int) {
when (getQuestStage(player!!, Quests.MURDER_MYSTERY)){
0 -> npcl("I'm far too upset to talk to random people right now.").also { stage = END_DIALOGUE }
1 -> when (stage) {
0 -> playerl(FacialExpression.NEUTRAL, "I'm here to help the guards with their investigation.").also { stage++ }
1 -> npcl(FacialExpression.ASKING, "How can I help?").also { stage++ }
2 -> showTopics(
Topic("Who do you think is responsible?", 3),
Topic( "Where were you at the time of the murder?", 6),
IfTopic("Did you hear any suspicious noises at all?", 7, getAttribute(player!!, attributeNoiseClue, false)),
IfTopic("Do you know why so much poison was bought recently?", 12, getAttribute(player!!, attributePoisonClue, 0) > 0)
)
3 -> npcl("Elizabeth.").also { stage ++ }
4 -> npcl("Her father confronted her about her constant petty thieving, and was devastated to find she had stolen a silver needle which had meant a lot to him.").also { stage++ }
5 -> npcl("You could hear their argument from Lumbridge!").also { stage = END_DIALOGUE }
6 -> npcl("I was right here with Hobbes and Mary. You can't suspect me surely!").also { stage = END_DIALOGUE }
7 -> npcl("Suspicious? What do you mean suspicious?").also { stage++ }
8 -> playerl("Any sounds of a struggle with an intruder for example?").also { stage++ }
9 -> npcl("No, I'm sure I don't recall any such thing.").also { stage++ }
10 -> playerl("How about the guard dog barking at an intruder?").also { stage++ }
11 -> npcl("No, I didn't. If you don't have anything else to ask can You go and leave me alone now? I have a lot of cooking to do for this evening.").also { stage = END_DIALOGUE }
12 -> npcl("I told Carol to buy some from that strange poison salesman and clean the drains before they began to smell any worse. She was the one who blocked them in the first place with a load").also { stage++ }
13 -> npcl("of beans that she bought for some reason. There were far too many to eat, and they were almost rotten when she bought them anyway! You'd really have to ask her though.").also { stage = END_DIALOGUE }
}
100 -> npcl("Thank you for all your help in solving the murder.").also { stage = END_DIALOGUE }
}
}
}

View file

@ -0,0 +1,59 @@
package content.region.kandarin.quest.murdermystery
import content.data.Quests
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributeNoiseClue
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributePoisonClue
import core.api.*
import core.game.dialogue.*
import core.game.node.entity.player.Player
import core.plugin.Initializable
import core.tools.END_DIALOGUE
import org.rs09.consts.NPCs
@Initializable
class MaryDialogue (player: Player? = null) : DialoguePlugin(player) {
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
openDialogue(player, MaryDialogueFile(), npc)
return true
}
override fun newInstance(player: Player): DialoguePlugin {
return MaryDialogue(player)
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.MARY_810)
}
}
class MaryDialogueFile : DialogueFile() {
override fun handle(componentID: Int, buttonID: Int) {
when (getQuestStage(player!!, Quests.MURDER_MYSTERY)){
0 -> sendDialogue(player!!, "They are ignoring you.").also { stage = END_DIALOGUE }
1 -> when (stage) {
0 -> playerl(FacialExpression.NEUTRAL, "I'm here to help the guards with their investigation.").also { stage++ }
1 -> npcl(FacialExpression.ASKING, "How can I help?").also { stage++ }
2 -> showTopics(
Topic("Who do you think is responsible?", 3),
Topic( "Where were you at the time of the murder?", 5),
IfTopic("Did you hear any suspicious noises at all?", 7, getAttribute(player!!, attributeNoiseClue, false)),
IfTopic("Do you know why so much poison was bought recently?", 12, getAttribute(player!!, attributePoisonClue, 0) > 0)
)
3 -> npcl("Oh I don't know... Frank was acting kind of funny... After that big argument him and the Lord had the other day by the beehive... so").also { stage ++ }
4 -> npcl("I guess maybe him... but it's really scary to think someone here might have been responsible. I actually hope it was a burglar...").also { stage = END_DIALOGUE }
5 -> npcl("I was with Hobbes and Louisa in the Kitchen helping to prepare Lord Sinclair's meal, and then when I took it to his study... I saw... oh, it was horrible... he was...").also { stage++ }
6 -> sendDialogue(player!!, "She seems to be on the verge of crying. You decide not to push her anymore for details.").also { stage = END_DIALOGUE}
7 -> npcl("I don't really remember hearing anything out of the ordinary.").also { stage++ }
8 -> playerl("No sounds of a struggle then?").also { stage++ }
9 -> npcl("No, I don't remember hearing anything like that.").also { stage++ }
10 -> playerl("How about the guard dog barking?").also { stage++ }
11 -> npcl("Oh that horrible dog is always barking at noting but I don't think I did...").also { stage = END_DIALOGUE }
12 -> npcl("I overheard Anna saying to Stanford that if he didn't do something about the state of his compost heap, she was going to.").also { stage++ }
13 -> npcl("She really doesn't get on well with Stanford, I really have no idea why. You'd really have to ask her though.").also { stage = END_DIALOGUE }
}
100 -> npcl("Thank you for all your help in solving the murder.").also { stage = END_DIALOGUE }
}
}
}

View file

@ -0,0 +1,156 @@
package content.region.kandarin.quest.murdermystery
import content.data.Quests
import core.api.*
import core.game.node.entity.player.link.quest.Quest
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.plugin.Initializable
import org.rs09.consts.Items
// https://www.youtube.com/watch?v=f1Eou5i5hBo at 2:29
// https://www.youtube.com/watch?v=BwO4JhZdQKo at 25:20
// https://www.youtube.com/watch?v=u5Osw_jas4A at 26:35
// https://www.youtube.com/watch?v=f1Eou5i5hBo
// https://www.youtube.com/watch?v=9Q2aLUg44SQ at 10:02
// https://www.youtube.com/watch?v=_lTUessdfOM 6:18
/**
* Murder Mystery Quest
*/
@Initializable
class MurderMystery : Quest(Quests.MURDER_MYSTERY, 93, 92, 3, 192, 0, 1, 2) {
companion object {
const val questName = "Murder Mystery"
const val attributeRandomMurderer = "/save:quest:murdermystery-randommurderer" //Alphabetical, 0 for Anna, 1 for Bob, 2 for Carol, 3 for David, 4 for Elizabeth, 5 for Frank
const val attributeTakenThread = "/save:quest:murdermystery-takenthread" //true after taking thread for the first time from window
const val attributeNoiseClue = "/save:quest:murdermystery-noiseclue" //true on learning of the barking dog for the first time
const val attributePoisonClue = "/save:quest:murdermystery-poisonclue" //1 after learning poison was bought, 2 after finding liar
const val attributeAskPoisonAnna = "/save:quest:murdermystery-askpoisonanna" //true after asking Anna about poison
const val attributeAskPoisonBob = "/save:quest:murdermystery-askpoisonbob" //true after asking Bob about poison
const val attributeAskPoisonCarol = "/save:quest:murdermystery-askpoisoncarol" //true after asking Carol about poison
const val attributeAskPoisonDavid = "/save:quest:murdermystery-askpoisondavid" //true after asking David about poison
const val attributeAskPoisonElizabeth = "/save:quest:murdermystery-askpoisonelizabeth" //true after asking Elizabeth about poison
const val attributeAskPoisonFrank = "/save:quest:murdermystery-askpoisonfrank" //true after asking Anna about poison
fun clueCount(player: Player) : Int {
var count = 0
if (inInventory(player, Items.CRIMINALS_THREAD_1808) || inInventory(player, Items.CRIMINALS_THREAD_1809) || inInventory(player, Items.CRIMINALS_THREAD_1810)) {
count++
}
if (inInventory(player, Items.KILLERS_PRINT_1815)) {
count ++
}
if (getAttribute(player, attributePoisonClue,0) == 2) {
count ++
}
return count
}
fun solvedMystery(player: Player) : Boolean {
return (
( inInventory(player, Items.CRIMINALS_THREAD_1808) || inInventory(player, Items.CRIMINALS_THREAD_1809) || inInventory(player, Items.CRIMINALS_THREAD_1810) )
&& inInventory(player, Items.KILLERS_PRINT_1815)
&& getAttribute(player, attributePoisonClue,0) == 2
&& getAttribute(player, attributeNoiseClue, false)
)
}
}
override fun drawJournal(player: Player, stage: Int) {
super.drawJournal(player, stage)
var line = 12
var stage = getStage(player)
var started = getQuestStage(player, Quests.MURDER_MYSTERY) > 0
if (!started) {
line(player, "I can start this quest by speaking to one of the !!Guards?? at", line++, false)
line(player, "the !!Sinclair Mansion??, North of the !!Seer's Village??.", line++, false)
} else if (stage < 100) {
line(player, "Lord Sinclair, a prominent nobleman, had been horribly", line++, true)
line(player, "murdered at his mansion. The guards had been sent to", line++, true)
line(player, "investigate his murder, but have been completely stuck.", line++, true)
if (solvedMystery(player)) {
line(player, "One of the guards asked me for my help in solving the", line++, true)
line(player, "murder. After careful examination of the crime scene and", line++, true)
line(player, "interrogating all suspects, I worked out who was guilty.", line++, true)
} else {
line(player, "One of the !!guards?? has asked me for my help in solving the", line++, false)
line(player, "murder. I should !!examine the crime scene?? very closely for", line++, false)
line(player, "evidence, and !!interrogate everybody?? in the area carefully.", line++, false)
}
// This may not be a stage but an attribute when all the evidence is collected.
if (solvedMystery(player)) {
line(player, "I have !!indisputable evidence?? of who the murderer must be.", line++, false)
line(player, "I should take it to one of the !!Guards?? immediately.", line++, false)
} else {
line++
if (inInventory(player, Items.CRIMINALS_THREAD_1808) || inInventory(player, Items.CRIMINALS_THREAD_1809) || inInventory(player, Items.CRIMINALS_THREAD_1810)) {
line(player, "I have found some !!coloured thread??. It might be useful.", line++, false)
}
if (inInventory(player, Items.CRIMINALS_DAGGER_1813) || inInventory(player, Items.CRIMINALS_DAGGER_1814)) {
line(player, "I have taken the !!murder weapon??. I think it might help me.", line++, false)
}
if (inInventory(player, Items.PUNGENT_POT_1812)) {
line(player, "I have a !!strange smelling pot??. It seems like a clue.", line++, false)
}
}
} else {
line(player, "One of the guards asked me for my help in solving the", line++, true)
line(player, "murder. After careful examination of the crime scene and", line++, true)
line(player, "interrogating all suspects, I worked out who was guilty.", line++, true)
line(player, "I took the evidence I had collected to the Guards and", line++, true)
line(player, "explained how it could identify the killer. Impressed", line++, true)
line(player, "with my deductions, the killer was arrested and I was", line++, true)
line(player, "given a fair reward for my help in solving the crime.", line++, true)
line++
line(player,"<col=FF0000>QUEST COMPLETE!</col>", line)
}
}
override fun reset(player: Player) {
removeAttribute(player, attributeRandomMurderer)
removeAttribute(player, attributeNoiseClue)
removeAttribute(player, attributePoisonClue)
removeAttribute(player, attributeTakenThread)
removeAttribute(player, attributeAskPoisonAnna)
removeAttribute(player, attributeAskPoisonBob)
removeAttribute(player, attributeAskPoisonCarol)
removeAttribute(player, attributeAskPoisonDavid)
removeAttribute(player, attributeAskPoisonElizabeth)
removeAttribute(player, attributeAskPoisonFrank)
}
override fun finish(player: Player) {
var ln = 10
super.finish(player)
player.packetDispatch.sendString("You have completed the Murder Mystery quest!", 277, 4)
player.packetDispatch.sendItemZoomOnInterface(Items.COINS_617, 230, 277, 5)
drawReward(player, "3 Quest Points", ln++)
drawReward(player, "2000 coins", ln++)
drawReward(player, "1406 Crafting XP", ln++)
addItem(player, Items.COINS_995, 2000)
rewardXP(player, Skills.CRAFTING, 1406.0)
removeAttribute(player, attributeNoiseClue)
removeAttribute(player, attributePoisonClue)
removeAttribute(player, attributeTakenThread)
removeAttribute(player, attributeAskPoisonAnna)
removeAttribute(player, attributeAskPoisonBob)
removeAttribute(player, attributeAskPoisonCarol)
removeAttribute(player, attributeAskPoisonDavid)
removeAttribute(player, attributeAskPoisonElizabeth)
removeAttribute(player, attributeAskPoisonFrank)
}
override fun newInstance(`object`: Any?): Quest {
return this
}
}

View file

@ -0,0 +1,442 @@
package content.region.kandarin.quest.murdermystery
import content.data.Quests
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributeAskPoisonAnna
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributeAskPoisonBob
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributeAskPoisonCarol
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributeAskPoisonDavid
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributeAskPoisonElizabeth
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributeAskPoisonFrank
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributeNoiseClue
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributePoisonClue
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributeRandomMurderer
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributeTakenThread
import core.api.*
import core.game.interaction.InteractionListener
import core.game.node.item.GroundItem
import core.game.node.item.Item
import org.rs09.consts.Items
import org.rs09.consts.Scenery
class MurderMysteryListeners : InteractionListener {
companion object {
val UNDUSTEDEVIDENCE = intArrayOf(
Items.CRIMINALS_DAGGER_1813,
Items.PUNGENT_POT_1812,
Items.SILVER_NECKLACE_1796,
Items.SILVER_CUP_1798,
Items.SILVER_BOTTLE_1800,
Items.SILVER_BOOK_1802,
Items.SILVER_NEEDLE_1804,
Items.SILVER_POT_1806
)
val DUSTEDEVIDENCE = intArrayOf(
Items.CRIMINALS_DAGGER_1814,
Items.SILVER_NECKLACE_1797,
Items.SILVER_CUP_1799,
Items.SILVER_BOTTLE_1801,
Items.SILVER_BOOK_1803,
Items.SILVER_NEEDLE_1805,
Items.SILVER_POT_1807
)
val SILVERBARRELS = intArrayOf(
Scenery.ANNA_S_BARREL_2656,
Scenery.BOB_S_BARREL_2657,
Scenery.CAROL_S_BARREL_2658,
Scenery.DAVID_S_BARREL_2659,
Scenery.ELIZABETH_S_BARREL_2660,
Scenery.FRANK_S_BARREL_2661
)
val POISONSPOTS = intArrayOf(
Scenery.SINCLAIR_FAMILY_COMPOST_HEAP_26120,
Scenery.SINCLAIR_FAMILY_BEEHIVE_26121,
Scenery.SINCLAIR_MANSION_DRAIN_2843,
Scenery.SPIDERS__NEST_26109,
Scenery.SINCLAIR_FAMILY_FOUNTAIN_2654,
Scenery.SINCLAIR_FAMILY_CREST_2655
)
val SUSPECTPRINTS = intArrayOf(
Items.ANNAS_PRINT_1816,
Items.BOBS_PRINT_1817,
Items.CAROLS_PRINT_1818,
Items.DAVIDS_PRINT_1819,
Items.ELIZABETHS_PRINT_1820,
Items.FRANKS_PRINT_1821
)
}
override fun defineListeners() {
on(Items.CRIMINALS_DAGGER_1813, GROUNDITEM, "take") { player, groundItem ->
when (getQuestStage(player, Quests.MURDER_MYSTERY)) {
1 -> {
if (inInventory(player, Items.CRIMINALS_DAGGER_1813) || inInventory(player, Items.CRIMINALS_DAGGER_1814)) {
sendDialogue(player, "I already have the murder weapon.")
}
else if (addItem(player, Items.CRIMINALS_DAGGER_1813)) {
removeGroundItem(groundItem as GroundItem)
sendDialogue(player, "This knife doesn't seem sturdy enough to have killed Lord Sinclair.")
}
return@on true
}
else -> {
sendDialogue(player, "You need the guards' permission to do that.")
return@on true
}
}
}
on(Items.PUNGENT_POT_1812, GROUNDITEM, "take") { player, groundItem ->
when (getQuestStage(player, Quests.MURDER_MYSTERY)) {
1 -> {
if (inInventory(player, Items.PUNGENT_POT_1812)) {
sendDialogue(player, "I already have the poisoned pot.")
} else if (addItem(player, Items.PUNGENT_POT_1812)) {
removeGroundItem(groundItem as GroundItem)
sendDialogue(player, "It seems like Lord Sinclair was drinking from this before he died.")
}
return@on true
}
else -> {
sendDialogue(player, "You need the guards' permission to do that.")
return@on true
}
}
}
on(intArrayOf(Scenery.STURDY_WOODEN_GATE_2664, Scenery.STURDY_WOODEN_GATE_2665), SCENERY, "investigate") { player, _ ->
when (getQuestStage(player, Quests.MURDER_MYSTERY)) {
1 -> {
sendDialogue(player, "As you approach the gate the guard dog starts barking loudly at you. There is no way an intruder could have committed the murder. It must have been someone the dog knew to get past it quietly.")
setAttribute(player, attributeNoiseClue, true)
return@on true
}
else -> {
sendDialogue(player, "You need the guards' permission to do that.")
return@on true
}
}
}
on(Scenery.SMASHED_WINDOW_26110, SCENERY, "investigate") { player, _ ->
when (getQuestStage(player, Quests.MURDER_MYSTERY)) {
1 -> {
sendDialogue(player, "Some thread seems to have been caught on a loose nail on the window.")
if (inInventory(player, Items.CRIMINALS_THREAD_1808) || inInventory(player, Items.CRIMINALS_THREAD_1809) || inInventory(player, Items.CRIMINALS_THREAD_1810)) {
sendMessage(player, "You have already taken the thread.")
}
else if (getAttribute(player, attributeTakenThread, false)) {
if (hasSpaceFor(player, Item(Items.CRIMINALS_THREAD_1808))) {
when (getAttribute(player, attributeRandomMurderer, 0)) {
1, 2 -> addItem(player, Items.CRIMINALS_THREAD_1808)
0, 3 -> addItem(player, Items.CRIMINALS_THREAD_1809)
else -> addItem(player, Items.CRIMINALS_THREAD_1810)
}
sendMessage(player, "Lucky for you there's some thread left. You should be less careless in the future.")
}
}
else {
if (hasSpaceFor(player, Item(Items.CRIMINALS_THREAD_1808))) {
when (getAttribute(player, attributeRandomMurderer, 0)) {
1, 2 -> addItem(player, Items.CRIMINALS_THREAD_1808)
0, 3 -> addItem(player, Items.CRIMINALS_THREAD_1809)
else -> addItem(player, Items.CRIMINALS_THREAD_1810)
}
sendMessage(player, "You take the thread.")
setAttribute(player, attributeTakenThread, true)
}
}
return@on true
}
else -> {
sendDialogue(player, "You need the guards' permission to do that.")
return@on true
}
}
}
on(Scenery.SMASHED_WINDOW_26110, SCENERY, "break") { player, _ ->
sendDialogue(player, "You don't want to damage evidence!")
return@on true
}
on(Scenery.SACKS_2663, SCENERY, "investigate") { player, _ ->
when (getQuestStage(player, Quests.MURDER_MYSTERY)) {
1 -> {
openDialogue(player, FlypaperDialogue())
return@on true
}
else -> {
sendDialogue(player, "You need the guards' permission to do that.")
return@on true
}
}
}
on(SILVERBARRELS, SCENERY, "search") { player, node ->
when (getQuestStage(player, Quests.MURDER_MYSTERY)) {
1 -> {
when (node.id) {
Scenery.ANNA_S_BARREL_2656 -> {
if (inInventory(player, Items.SILVER_NECKLACE_1796) || inInventory(player, Items.SILVER_NECKLACE_1797)) {
sendDialogue(player, "I already have Anna's Necklace.")
}
else if (addItem(player, Items.SILVER_NECKLACE_1796)){
sendDialogue(player, "There's something shiny hidden at the bottom. You take Anna's Silver Necklace.")
}
}
Scenery.BOB_S_BARREL_2657 -> {
if (inInventory(player, Items.SILVER_CUP_1798) || inInventory(player, Items.SILVER_CUP_1799)) {
sendDialogue(player, "I already have Bob's cup.")
}
else if (addItem(player, Items.SILVER_CUP_1798)){
sendDialogue(player, "There's something shiny hidden at the bottom. You take Bob's silver cup.")
}
}
Scenery.CAROL_S_BARREL_2658 -> {
if (inInventory(player, Items.SILVER_BOTTLE_1800) || inInventory(player, Items.SILVER_BOTTLE_1801)) {
sendDialogue(player, "I already have Carol's bottle.")
}
else if (addItem(player, Items.SILVER_BOTTLE_1800)){
sendDialogue(player, "There's something shiny hidden at the bottom. You take Carol's silver bottle.")
}
}
Scenery.DAVID_S_BARREL_2659 -> {
if (inInventory(player, Items.SILVER_BOOK_1802) || inInventory(player, Items.SILVER_BOOK_1803)) {
sendDialogue(player, "I already have David's book.")
}
else if (addItem(player, Items.SILVER_BOOK_1802)){
sendDialogue(player, "There's something shiny hidden at the bottom. You take David's silver book.")
}
}
Scenery.ELIZABETH_S_BARREL_2660 -> {
if (inInventory(player, Items.SILVER_NEEDLE_1804) || inInventory(player, Items.SILVER_NEEDLE_1805)) {
sendDialogue(player, "I already have Elizabeth's Needle.")
}
else if (addItem(player, Items.SILVER_NEEDLE_1804)){
sendDialogue(player, "There's something shiny hidden at the bottom. You take Elizabeth's silver needle.")
}
}
Scenery.FRANK_S_BARREL_2661 -> {
if (inInventory(player, Items.SILVER_POT_1806) || inInventory(player, Items.SILVER_POT_1807)) {
sendDialogue(player, "I already have Frank's pot.")
}
else if (addItem(player, Items.SILVER_POT_1806)){
sendDialogue(player, "There's something shiny hidden at the bottom. You take Frank's silver pot.")
}
}
}
return@on true
}
else -> {
sendDialogue(player, "You need the guards' permission to do that.")
return@on true
}
}
}
on(POISONSPOTS, SCENERY, "investigate") { player, node ->
when (node.id) {
Scenery.SINCLAIR_FAMILY_COMPOST_HEAP_26120 -> {
if (!getAttribute(player, attributeAskPoisonAnna, false)) {
sendDialogue(player, "It's a heap of compost.")
}
else if (getAttribute(player, attributeRandomMurderer, 0) == 0) {
sendDialogue(player, "The compost is teeming with maggots. Somebody should really do something about it. It's certainly clear nobody's used poison here.")
setAttribute(player, attributePoisonClue, 2)
}
else {
sendDialogue(player, "There is a faint smell of poison behind the smell of the compost.")
}
}
Scenery.SINCLAIR_FAMILY_BEEHIVE_26121 -> {
if (!getAttribute(player, attributeAskPoisonBob, false)) {
sendDialogue(player, "It's a very old beehive.")
}
else if (getAttribute(player, attributeRandomMurderer, 0) == 1) {
sendDialogue(player, "The beehive buzzes with activity. These bees definitely don't seem poisoned at all.")
setAttribute(player, attributePoisonClue, 2)
}
else {
sendDialogue(player, "The hive is empty. There are a few dead bees and a faint smell of poison.")
}
}
Scenery.SINCLAIR_MANSION_DRAIN_2843 -> {
if (!getAttribute(player, attributeAskPoisonCarol, false)) {
sendDialogue(player, "It's the drains from the kitchen.")
}
else if (getAttribute(player, attributeRandomMurderer, 0) == 2) {
sendDialogue(player, "The drain is totally blocked. It really stinks. No, it REALLY smells bad. It's certainly clear nobody's cleaned it recently.")
setAttribute(player, attributePoisonClue, 2)
}
else {
sendDialogue(player, "The drain seems to have been recently cleaned. You can still smell the faint aroma of poison.")
}
}
Scenery.SPIDERS__NEST_26109 -> {
if (!getAttribute(player, attributeAskPoisonDavid, false)) {
sendDialogue(player, "It looks like a spiders' nest of some kind...")
}
else if (getAttribute(player, attributeRandomMurderer, 0) == 3) {
sendDialogue(player, "There is a spiders' nest here. You estimate there must be at least a few hundred spiders ready to hatch. It's certainly clear nobody's used poison here.")
setAttribute(player, attributePoisonClue, 2)
}
else {
sendDialogue(player, "A faint smell of poison and a few dead spiders is all that remains of the spiders nest.")
}
}
Scenery.SINCLAIR_FAMILY_FOUNTAIN_2654 -> {
if (!getAttribute(player, attributeAskPoisonElizabeth, false)) {
sendDialogue(player, "A fountain with large numbers of insects around the base.")
}
else if (getAttribute(player, attributeRandomMurderer, 0) == 4) {
openDialogue(player, FountainDialogue())
setAttribute(player, attributePoisonClue, 2)
}
else {
sendDialogue(player, "There are a lot of dead mosquitos around the base of the fountain. A faint smell of poison is in the air, but the water seems clean.")
}
}
Scenery.SINCLAIR_FAMILY_CREST_2655 -> {
if (!getAttribute(player, attributeAskPoisonFrank, false)) {
sendDialogue(player, "The Sinclair Family Crest is hung up here.")
}
else if (getAttribute(player, attributeRandomMurderer, 0) == 5) {
sendDialogue(player, "It looks like the Sinclair family crest but it is very dirty. You can barely make it out under all of the grime. It's certainly clear nobody's cleaned it recently.")
setAttribute(player, attributePoisonClue, 2)
}
else {
sendDialogue(player, "The Sinclair family crest. It's shiny and freshly polished and has a slight smell of poison.")
}
}
}
return@on true
}
onUseWith(ITEM, UNDUSTEDEVIDENCE, Items.POT_OF_FLOUR_1933) { player, used, _ ->
when (used.id) {
Items.CRIMINALS_DAGGER_1813 -> {
removeItem(player, used)
addItem(player, Items.CRIMINALS_DAGGER_1814)
sendMessage(player, "You sprinkle a small amount of flour on the murder weapon.")
sendMessage(player, "The murder weapon is now coated with a thin layer of flour.")
}
Items.PUNGENT_POT_1812 -> {
sendMessage(player, "You sprinkle a small amount of flour on the strange smelling pot.")
sendMessage(player, "The surface isn't shiny enough to take a fingerprint from.")
}
Items.SILVER_NECKLACE_1796 -> {
removeItem(player, used)
addItem(player, Items.SILVER_NECKLACE_1797)
sendMessage(player, "You sprinkle the flour on Anna's necklace.")
sendMessage(player, "The necklace is now coated with a thin layer of flour.")
}
Items.SILVER_CUP_1798 -> {
removeItem(player, used)
addItem(player, Items.SILVER_CUP_1799)
sendMessage(player, "You sprinkle the flour on Bob's cup.")
sendMessage(player, "The cup is now coated with a thin layer of flour.")
}
Items.SILVER_BOTTLE_1800 -> {
removeItem(player, used)
addItem(player, Items.SILVER_BOTTLE_1801)
sendMessage(player, "You sprinkle the flour on Carol's bottle.")
sendMessage(player, "The bottle is now coated with a thin layer of flour.")
}
Items.SILVER_BOOK_1802 -> {
removeItem(player, used)
addItem(player, Items.SILVER_BOOK_1803)
sendMessage(player, "You sprinkle the flour on David's book.")
sendMessage(player, "The Book is now coated with a thin layer of flour.")
}
Items.SILVER_NEEDLE_1804 -> {
removeItem(player, used)
addItem(player, Items.SILVER_NEEDLE_1805)
sendMessage(player, "You sprinkle the flour on Elizabeth's needle.")
sendMessage(player, "The Needle is now coated with a thin layer of flour.")
}
Items.SILVER_POT_1806 -> {
removeItem(player, used)
addItem(player, Items.SILVER_POT_1807)
sendMessage(player, "You sprinkle the flour on Frank's pot")
sendMessage(player, "The Pot is now coated with a thin layer of flour.")
}
}
removeItem(player, Items.POT_OF_FLOUR_1933)
addItem(player, Items.EMPTY_POT_1931)
return@onUseWith true
}
onUseWith(ITEM, DUSTEDEVIDENCE, Items.FLYPAPER_1811) { player, used, _ ->
removeItem(player, Items.FLYPAPER_1811)
when (used.id) {
Items.CRIMINALS_DAGGER_1814 -> {
removeItem(player, used)
addItem(player, Items.CRIMINALS_DAGGER_1813)
addItem(player, Items.UNKNOWN_PRINT_1822)
sendMessage(player, "You use the flypaper on the floury dagger.")
sendMessage(player, "You have a clean impression of the murderer's finger prints.")
}
Items.SILVER_NECKLACE_1797 -> {
removeItem(player, used)
addItem(player, Items.SILVER_NECKLACE_1796)
addItem(player, Items.ANNAS_PRINT_1816)
sendMessage(player, "You use the flypaper on the flour covered necklace.")
sendMessage(player, "You have a clean impression of Anna's finger prints.")
}
Items.SILVER_CUP_1799 -> {
removeItem(player, used)
addItem(player, Items.SILVER_CUP_1798)
addItem(player, Items.BOBS_PRINT_1817)
sendMessage(player, "You use the flypaper on the flour covered cup.")
sendMessage(player, "You have a clean impression of Bob's finger prints.")
}
Items.SILVER_BOTTLE_1801 -> {
removeItem(player, used)
addItem(player, Items.SILVER_BOTTLE_1800)
addItem(player, Items.CAROLS_PRINT_1818)
sendMessage(player, "You use the flypaper on the flour covered bottle.")
sendMessage(player, "You have a clean impression of Carol's finger prints.")
}
Items.SILVER_BOOK_1803 -> {
removeItem(player, used)
addItem(player, Items.SILVER_BOOK_1802)
addItem(player, Items.DAVIDS_PRINT_1819)
sendMessage(player, "You use the flypaper on the flour covered book.")
sendMessage(player, "You have a clean impression of David's finger prints.")
}
Items.SILVER_NEEDLE_1805 -> {
removeItem(player, used)
addItem(player, Items.SILVER_NEEDLE_1804)
addItem(player, Items.ELIZABETHS_PRINT_1820)
sendMessage(player, "You use the flypaper on the flour covered needle.")
sendMessage(player, "You have a clean impression of Elizabeth's finger prints.")
}
Items.SILVER_POT_1807 -> {
removeItem(player, used)
addItem(player, Items.SILVER_POT_1806)
addItem(player, Items.FRANKS_PRINT_1821)
sendMessage(player, "You use the flypaper on the flour covered pot.")
sendMessage(player, "You have a clean impression of Frank's finger prints.")
}
}
return@onUseWith true
}
onUseWith(ITEM, SUSPECTPRINTS, Items.UNKNOWN_PRINT_1822) { player, used, with ->
val SUSPECT = when (used.id) {
Items.ANNAS_PRINT_1816 -> "Anna"
Items.BOBS_PRINT_1817 -> "Bob"
Items.CAROLS_PRINT_1818 -> "Carol"
Items.DAVIDS_PRINT_1819 -> "David"
Items.ELIZABETHS_PRINT_1820 -> "Elizabeth"
Items.FRANKS_PRINT_1821 -> "Frank"
else -> "Anna"
}
if (used.id == getAttribute(player, attributeRandomMurderer, 0) + Items.ANNAS_PRINT_1816) {
sendDialogue(player, "The fingerprints are an exact match to $SUSPECT's.")
removeItem(player, with.id)
addItem(player, Items.KILLERS_PRINT_1815)
}
else {
sendDialogue(player, "They don't seem to be the same. I guess that clears $SUSPECT of the crime. You destroy the useless fingerprint.")
removeItem(player, used.id)
}
return@onUseWith true
}
onUseWith(SCENERY, intArrayOf(Items.SILVER_POT_1806, Items.PUNGENT_POT_1812), Scenery.BARREL_OF_FLOUR_26122) { player, _, _ ->
sendDialogue(player, "You probably shouldn't use evidence from a crime scene to keep flour in.")
return@onUseWith true
}
}
}

View file

@ -0,0 +1,58 @@
package content.region.kandarin.quest.murdermystery
import content.data.Quests
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributeNoiseClue
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributePoisonClue
import core.api.*
import core.game.dialogue.*
import core.game.node.entity.player.Player
import core.plugin.Initializable
import core.tools.END_DIALOGUE
import org.rs09.consts.NPCs
@Initializable
class PierreDialogue (player: Player? = null) : DialoguePlugin(player) {
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
openDialogue(player, PierreDialogueFile(), npc)
return true
}
override fun newInstance(player: Player): DialoguePlugin {
return PierreDialogue(player)
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.PIERRE_807)
}
}
class PierreDialogueFile : DialogueFile() {
override fun handle(componentID: Int, buttonID: Int) {
when (getQuestStage(player!!, Quests.MURDER_MYSTERY)){
0 -> npcl("The Guards told me not to talk to anyone.").also { stage = END_DIALOGUE }
1 -> when (stage) {
0 -> playerl(FacialExpression.NEUTRAL, "I'm here to help the guards with their investigation.").also { stage++ }
1 -> npcl(FacialExpression.ASKING, "How can I help?").also { stage++ }
2 -> showTopics(
Topic("Who do you think is responsible?", 3),
Topic( "Where were you at the time of the murder?", 5),
IfTopic("Did you hear any suspicious noises at all?", 6, getAttribute(player!!, attributeNoiseClue, false)),
IfTopic("Do you know why so much poison was bought recently?", 11, getAttribute(player!!, attributePoisonClue, 0) > 0)
)
3 -> npcl("Honestly? I think it was Carol.").also { stage++ }
4 -> npcl("I saw her in a huge argument with Lord Sinclair in the library the other day. It was something to do with stolen books. She definitely seemed upset enough to have done it afterwards.").also { stage = END_DIALOGUE }
5 -> npcl("I was in town at the inn. When I got back the house was swarming with guards who told me what had happened. Sorry.").also { stage = END_DIALOGUE }
6 -> npcl("Well, like what?").also { stage++ }
7 -> playerl("Any sounds of a struggle with Lord Sinclair?").also { stage++ }
8 -> npcl("No, I don't remember hearing anything like that.").also { stage++ }
9 -> playerl("How about the guard dog barking at all?").also { stage++ }
10 -> npcl("I hear him bark all the time. It's one of his favourite things to do. I can't say I did the night of the murder though as I wasn't close enough to hear either way.").also { stage = END_DIALOGUE }
11 -> npcl("Well, I know David said that he was going to do something about the spiders' nest that's between the two servants' quarters upstairs.").also { stage++ }
12 -> npcl("He made a big deal about it to Mary the Maid, calling her useless and incompetent. I felt quite sorry for her actually. You'd really have to ask him though.").also { stage = END_DIALOGUE }
}
100 -> npcl("Thank you for all your help in solving the murder.").also { stage = END_DIALOGUE }
}
}
}

View file

@ -0,0 +1,58 @@
package content.region.kandarin.quest.murdermystery
import content.data.Quests
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributeNoiseClue
import content.region.kandarin.quest.murdermystery.MurderMystery.Companion.attributePoisonClue
import core.api.*
import core.game.dialogue.*
import core.game.node.entity.player.Player
import core.plugin.Initializable
import core.tools.END_DIALOGUE
import org.rs09.consts.NPCs
@Initializable
class StanfordDialogue (player: Player? = null) : DialoguePlugin(player) {
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
openDialogue(player, StanfordDialogueFile(), npc)
return true
}
override fun newInstance(player: Player): DialoguePlugin {
return StanfordDialogue(player)
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.STANFORD_811)
}
}
class StanfordDialogueFile : DialogueFile() {
override fun handle(componentID: Int, buttonID: Int) {
when (getQuestStage(player!!, Quests.MURDER_MYSTERY)){
0 -> npcl("Have you no shame? We are all grieving at the moment.").also { stage = END_DIALOGUE }
1 -> when (stage) {
0 -> playerl(FacialExpression.NEUTRAL, "I'm here to help the guards with their investigation.").also { stage++ }
1 -> npcl(FacialExpression.ASKING, "How can I help?").also { stage++ }
2 -> showTopics(
Topic("Who do you think is responsible?", 3),
Topic( "Where were you at the time of the murder?", 5),
IfTopic("Did you hear any suspicious noises at all?", 6, getAttribute(player!!, attributeNoiseClue, false)),
IfTopic("Do you know why so much poison was bought recently?", 11, getAttribute(player!!, attributePoisonClue, 0) > 0)
)
3 -> npcl("It was Anna. She is seriously unbalanced. She trashed the garden once then tried to blame it on me! I bet it was her. It's just the kind of thing she'd do!").also { stage++ }
4 -> npcl("She really hates me and was arguing with Lord Sinclair about trashing the garden a few days ago.").also { stage = END_DIALOGUE }
5 -> npcl("Right here, by my little shed. It's very cosy to sit and think in.").also { stage = END_DIALOGUE }
6 -> npcl("Not that I remember.").also { stage++ }
7 -> playerl("So no sounds of a struggle between Lord Sinclair and an intruder?").also { stage++ }
8 -> npcl("Not to the best of my recollection.").also { stage++ }
9 -> playerl("How about the guard dog barking?").also { stage++ }
10 -> npcl("Not that I can recall.").also { stage = END_DIALOGUE }
11 -> npcl("Well, Bob mentioned to me the other day he wanted to get rid of the bees in that hive over there. I think I saw him buying poison").also { stage++ }
12 -> npcl("from that poison salesman the other day. I assume it was to sort out those bees. You'd really have to ask him though.").also { stage = END_DIALOGUE }
}
100 -> npcl("Thank you for all your help in solving the murder.").also { stage = END_DIALOGUE }
}
}
}

View file

@ -52,6 +52,6 @@ public final class CamelotGuardDialogue extends DialoguePlugin {
@Override
public int[] getIds() {
return new int[] { 812 };
return new int[] { 6183, 6184 };
}
}

View file

@ -1,48 +0,0 @@
package content.region.karamja.handlers;
import core.game.node.entity.npc.AbstractNPC;
import core.game.world.map.Location;
import core.plugin.Initializable;
import core.game.system.config.NPCConfigParser;
/**
* Represents the tribesamn npc.
* @author 'Vexia
* @version 1.0
*/
@Initializable
public final class TribesmanNPC extends AbstractNPC {
/**
* Represents the npc ids.
*/
private static final int[] IDS = new int[] { 191, 2496, 2497 };
/**
* Constructs a new {@code TribesmanNPC} {@code Object}.
* @param id the id.
* @param location the location.
*/
public TribesmanNPC(int id, Location location) {
super(id, location, true);
getDefinition().getHandlers().put(NPCConfigParser.POISONOUS, true);
}
/**
* Constructs a new {@code TribesmanNPC} {@code Object}.
*/
public TribesmanNPC() {
super(0, null);
}
@Override
public AbstractNPC construct(int id, Location location, Object... objects) {
return new TribesmanNPC(id, location);
}
@Override
public int[] getIds() {
return IDS;
}
}

View file

@ -0,0 +1,49 @@
package content.region.karamja.tzhaar.handlers
import core.api.openNpcShop
import core.game.dialogue.DialoguePlugin
import core.game.dialogue.FacialExpression
import core.game.dialogue.Topic
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.plugin.Initializable
import core.tools.END_DIALOGUE
import org.rs09.consts.NPCs
@Initializable
class TzHaarDialogue(player: Player? = null) : DialoguePlugin(player) {
override fun open(vararg args: Any): Boolean {
npc = args[0] as NPC
npcl(FacialExpression.HALF_GUILTY, "Can I help you JalYt-Ket-${player.username}?").also { stage = 0 }
return true
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
when (stage) {
0 -> showTopics(
Topic(FacialExpression.HALF_GUILTY, "What do you have to trade?", 10, true),
Topic(FacialExpression.HALF_GUILTY, "What did you call me?", 20),
Topic(FacialExpression.HALF_GUILTY, "No I'm fine thanks.", END_DIALOGUE),
)
10 -> end().also { openNpcShop(player, npc.id) }
20 -> npcl(FacialExpression.HALF_GUILTY, "Are you not JalYt-Ket?").also { stage++ }
21 -> showTopics(
Topic(FacialExpression.HALF_GUILTY, "What's a 'JalYt-Ket'?", 22),
Topic(FacialExpression.HALF_GUILTY, "I guess so...", 25),
Topic(FacialExpression.HALF_GUILTY, "No I'm not!", END_DIALOGUE)
)
22 -> npcl(FacialExpression.HALF_GUILTY, "That what you are... you tough and strong no?").also { stage++ }
23 -> playerl(FacialExpression.HALF_GUILTY, "Well yes I suppose I am...").also { stage++ }
24 -> npcl(FacialExpression.HALF_GUILTY, "Then you JalYt-Ket!").also { stage = END_DIALOGUE }
25 -> npcl(FacialExpression.HALF_GUILTY, "Well then, no problems.").also { stage = END_DIALOGUE }
}
return true
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.TZHAAR_HUR_TEL_2620, NPCs.TZHAAR_HUR_LEK_2622, NPCs.TZHAAR_MEJ_ROH_2623)
}
}

View file

@ -1,313 +0,0 @@
package content.region.karamja.tzhaar.handlers;
import core.game.dialogue.DialogueInterpreter;
import core.game.dialogue.DialoguePlugin;
import core.game.dialogue.FacialExpression;
import core.game.node.entity.npc.NPC;
import core.game.node.item.Item;
import core.plugin.Initializable;
import core.game.node.entity.player.Player;
import core.game.world.GameWorld;
/**
* Handles the TzHaarMejJal dialogue.
* @author 'Vexia
* @author Empathy
* @author Logg
*/
@Initializable
public class TzHaarMejJah extends DialoguePlugin {
private static final Item APPEARANCE_FEE = new Item(6529, 8000); // 8000 tokkul, about the same as you get from failing jad
public TzHaarMejJah() {
}
public TzHaarMejJah(Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new TzHaarMejJah(player);
}
@Override
public boolean open(Object... args) {
npc = (NPC) args[0];
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "You want help JalYt-Ket-" + player.getUsername() + "?");
stage = 0;
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
switch (stage) {
case 0:
if (GameWorld.getSettings().getJad_practice_enabled()) {
if (player.getAttribute("fc_practice_jad", false)) {
interpreter.sendOptions("Select an Option", player.getInventory().containItems(6570) ? "I have a fire cape here." : "What is this place?", "What did you call me?", "About my challenge...", "No I'm fine thanks.");
} else {
interpreter.sendOptions("Select an Option", player.getInventory().containItems(6570) ? "I have a fire cape here." : "What is this place?", "What did you call me?", "I want to challenge Jad directly.", "No I'm fine thanks.");
}
} else {
interpreter.sendOptions("Select an Option", player.getInventory().containItems(6570) ? "I have a fire cape here." : "What is this place?", "What did you call me?", "No I'm fine thanks.");
}
stage = 1;
break;
case 1:
switch (buttonId) {
case 1:
if (player.getInventory().containItems(6570)) {
interpreter.open(DialogueInterpreter.getDialogueKey("firecape-exchange"), npc);
break;
}
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "What is this place?");
stage = 10;
break;
case 2:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "What did you call me?");
stage = 20;
break;
case 3:
if (GameWorld.getSettings().getJad_practice_enabled()) {
if (player.getAttribute("fc_practice_jad", false)) {
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "About my challenge...");
stage = 64;
} else {
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "The challenge is too long.", "I want to challenge Jad directly.");
stage = 50;
}
} else {
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "No I'm fine thanks.");
stage = 30;
}
break;
case 4:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "No I'm fine thanks.");
stage = 30;
break;
}
break;
case 10:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "This is the fight caves, TzHaar-Xil made it for practice,", "but many JalYt come here to fight too.", "Just enter the cave and make sure you're prepared.");
stage = 11;
break;
case 11:
interpreter.sendOptions("Select an Option", "Are there any rules?", "Ok thanks.");
stage = 12;
break;
case 12:
switch (buttonId) {
case 1:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Are there any rules?");
stage = 14;
break;
case 2:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Ok thanks.");
stage = 13;
break;
}
break;
case 13:
end();
break;
case 14:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Rules? Survival is the only rule in there.");
stage = 15;
break;
case 15:
interpreter.sendOptions("Select an Option", "Do I win anything?", "Sounds good.");
stage = 16;
break;
case 16:
switch (buttonId) {
case 1:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Do I win anything?");
stage = 17;
break;
case 2:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Sounds good.");
stage = 13;
break;
}
break;
case 17:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "You ask a lot of questions.", "Might give you TokKul if you last long enough.");
stage = 18;
break;
case 18:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "...");
stage = 19;
break;
case 19:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Before you ask, TokKul is like your Coins.");
stage = 500;
break;
case 500:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Gold is like you JalYt, soft and easily broken, we use", "hard rock forged in fire like TzHaar!");
stage = 501;
break;
case 501:
end();
break;
case 20:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Are you not JalYt-Ket?");
stage = 21;
break;
case 21:
interpreter.sendOptions("Select an Option", "What's a 'JalYt-Ket'?", "I guess so...", "No I'm not!");
stage = 22;
break;
case 22:
switch (buttonId) {
case 1:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "What's a 'JalYt-Ket'?");
stage = 100;
break;
case 2:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "I guess so...");
stage = 200;
break;
case 3:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "No I'm not!");
stage = 300;
break;
}
break;
case 100:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "That what you are... you tough and strong no?");
stage = 101;
break;
case 101:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Well yes I suppose I am...");
stage = 102;
break;
case 102:
end();
break;
case 200:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "I guess so....");
stage = 201;
break;
case 201:
end();
break;
case 300:
end();
break;
case 30:
end();
break;
case 50:
interpreter.sendDialogues(npc, FacialExpression.DISGUSTED_HEAD_SHAKE, "I thought you strong and tough", "but you want skip endurance training?");
stage = 57;
break;
case 57:
interpreter.sendDialogues(npc, FacialExpression.NEUTRAL, "Maybe you not JalYt-Ket afterall.");
stage = 58;
break;
case 58:
interpreter.sendOptions("Select an Option", "I don't have time for it, man.", "No, I'm JalYt-Ket!");
stage = 51;
break;
case 51:
switch (buttonId) {
case 1:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "I don't have time for it, man.");
stage = 52;
break;
case 2:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "No, I'm JalYt-Ket! I swear!", "I'll do the training properly.");
stage = 30;
break;
}
break;
case 52:
interpreter.sendDialogues(npc, FacialExpression.DISGUSTED_HEAD_SHAKE, "JalYt, you know you not get reward","if you not do training properly, ok?");
stage = 56;
break;
case 56:
interpreter.sendOptions("Select an Option", "That's okay, I don't need a reward.", "Oh, nevermind then.");
stage = 53;
break;
case 53:
switch (buttonId) {
case 1:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "That's okay, I don't need a reward.");
stage = 54;
break;
case 2:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Oh, nevermind then.");
stage = 30;
break;
}
break;
case 54:
interpreter.sendDialogues(player, FacialExpression.NEUTRAL, "I just wanna fight the big guy.");
stage = 55;
break;
case 55:
interpreter.sendDialogues(npc, FacialExpression.NEUTRAL, "Okay JalYt.","TzTok-Jad not show up for just anyone.");
stage = 59;
break;
case 59:
interpreter.sendDialogues(npc, FacialExpression.NEUTRAL, "You give 8000 TokKul, TzTok-Jad know you serious.", "You get it back if you victorious.");
stage = 60;
break;
case 60:
interpreter.sendOptions("Select an Option", "That's fair, here's 8000 TokKul.", "I don't have that much on me, but I'll go get it.", "TzTok-Jad must be old and tired to not just accept my challenge.");
stage = 61;
case 61:
switch (buttonId) {
case 1:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "That's fair, here's 8000 TokKul.");
if (!player.getInventory().containsItem(APPEARANCE_FEE)) {
stage = 62;
break;
}
if (player.getInventory().remove(APPEARANCE_FEE)) {
stage = 69;
} else {
stage = 62;
}
break;
case 2:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "I don't have that much on me, but I'll go get it.");
stage = 30;
break;
case 3:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "TzTok-Jad must be old and tired", "to not just accept my challenge.");
stage = 63;
break;
}
break;
case 62:
interpreter.sendDialogues(npc, FacialExpression.NEUTRAL, "JalYt, you not have the TokKul.", "You come back when you are serious.");
stage = 30;
break;
case 63:
interpreter.sendDialogues(npc, FacialExpression.ANGRY, "JalYt-Mor, you the old and tired one.", "You the one not want to do proper training.");
stage = 30;
break;
case 64:
interpreter.sendDialogues(npc, FacialExpression.NEUTRAL, "TzTok-Jad is waiting for you.", "Do not make TzTok-Jad wait long.");
stage = 30;
break;
case 69:
interpreter.sendDialogues(npc, FacialExpression.NEUTRAL, "Okay JalYt. Enter cave when you are prepared.", "You find TzTok-Jad waiting for JalYt challenger.");
player.setAttribute("fc_practice_jad", true);
stage = 30;
break;
}
return true;
}
@Override
public int[] getIds() {
return new int[] { DialogueInterpreter.getDialogueKey("tzhaar-mej"), 2617 };
}
}

View file

@ -0,0 +1,167 @@
package content.region.karamja.tzhaar.handlers
import core.api.*
import core.game.dialogue.*
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.game.node.item.Item
import core.game.world.GameWorld.settings
import core.plugin.Initializable
import core.tools.END_DIALOGUE
import org.rs09.consts.Items
import org.rs09.consts.NPCs
/**
* Handles the TzHaarMejJal dialogue.
* @author 'Vexia
* @author Empathy
* @author Logg
*/
@Initializable
class TzHaarMejJal(player: Player? = null) : DialoguePlugin(player){
override fun open(vararg args: Any): Boolean {
npc = args[0] as NPC
npcl(FacialExpression.HALF_GUILTY, "You want help JalYt-Ket-${player.username}?").also { stage = 0 }
return true
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
when (stage) {
0 -> showTopics(
if (inInventory(player, Items.FIRE_CAPE_6570)) {
Topic(FacialExpression.HALF_GUILTY, "I have a fire cape here.", 100)
} else {
Topic(FacialExpression.HALF_GUILTY, "What is this place?", 10)
},
Topic(FacialExpression.HALF_GUILTY, "What did you call me?", 20),
IfTopic(FacialExpression.HALF_GUILTY, "About my challenge...", 50, getAttribute(player, "fc_practice_jad", false) && settings!!.jad_practice_enabled),
IfTopic("I want to challenge Jad directly.", 30, !getAttribute(player, "fc_practice_jad", false) && settings!!.jad_practice_enabled, skipPlayer = true),
Topic(FacialExpression.HALF_GUILTY, "No I'm fine thanks.", END_DIALOGUE)
)
10 -> npc(FacialExpression.HALF_GUILTY,
"This is the fight caves, TzHaar-Xil made it for practice,",
"but many JalYt come here to fight too.",
"Just enter the cave and make sure you're prepared."
).also { stage++ }
11 -> showTopics(
Topic(FacialExpression.HALF_GUILTY, "Are there any rules?", 12),
Topic(FacialExpression.HALF_GUILTY, "Ok thanks.", END_DIALOGUE)
)
12 -> npcl(FacialExpression.HALF_GUILTY, "Rules? Survival is the only rule in there.").also { stage++ }
13 -> showTopics(
Topic(FacialExpression.HALF_GUILTY, "Do I win anything?", 14),
Topic(FacialExpression.HALF_GUILTY, "Sounds good.", END_DIALOGUE)
)
14 -> npc(FacialExpression.HALF_GUILTY,
"You ask a lot of questions.",
"Might give you TokKul if you last long enough."
).also { stage++ }
15 -> playerl(FacialExpression.HALF_GUILTY, "...").also { stage ++ }
16 -> npcl(FacialExpression.HALF_GUILTY, "Before you ask, TokKul is like your Coins.").also { stage++ }
17 -> npc(FacialExpression.HALF_GUILTY,
"Gold is like you JalYt, soft and easily broken, we use",
"hard rock forged in fire like TzHaar!"
).also{ stage = END_DIALOGUE }
20 -> npcl(FacialExpression.HALF_GUILTY, "Are you not JalYt-Ket?").also { stage++ }
21 -> showTopics(
Topic(FacialExpression.HALF_GUILTY, "What's a 'JalYt-Ket'?", 22),
Topic(FacialExpression.HALF_GUILTY, "I guess so...", END_DIALOGUE),
Topic(FacialExpression.HALF_GUILTY, "No I'm not!", END_DIALOGUE)
)
22 -> npcl(FacialExpression.HALF_GUILTY, "That what you are... you tough and strong no?").also { stage++ }
23 -> playerl(FacialExpression.HALF_GUILTY, "Well yes I suppose I am...").also { stage = END_DIALOGUE }
30 -> player(FacialExpression.HALF_GUILTY,
"The challenge is too long.",
"I want to challenge Jad directly."
).also { stage++ }
31 -> npc(FacialExpression.DISGUSTED_HEAD_SHAKE,
"I thought you strong and tough",
"but you want skip endurance training?"
).also { stage++ }
32 -> npcl(FacialExpression.NEUTRAL, "Maybe you not JalYt-Ket afterall.").also { stage++ }
33 -> showTopics(
Topic(FacialExpression.HALF_GUILTY, "I don't have time for it, man.", 35),
Topic("No, I'm JalYt-Ket!", 34, skipPlayer = true)
)
34 -> player(FacialExpression.HALF_GUILTY,
"No, I'm JalYt-Ket! I swear!",
"I'll do the training properly."
).also { stage = END_DIALOGUE }
35 -> npc(FacialExpression.DISGUSTED_HEAD_SHAKE,
"JalYt, you know you not get reward",
"if you not do training properly, ok?"
).also { stage++ }
36 -> showTopics(
Topic(FacialExpression.HALF_GUILTY, "That's okay, I don't need a reward.", 37),
Topic(FacialExpression.HALF_GUILTY, "Oh, nevermind then.", END_DIALOGUE)
)
37 -> playerl(FacialExpression.NEUTRAL, "I just wanna fight the big guy.").also { stage++ }
38 -> npc(FacialExpression.NEUTRAL,
"Okay JalYt.",
"TzTok-Jad not show up for just anyone."
).also { stage++ }
39 -> npc(FacialExpression.NEUTRAL,
"You give 8000 TokKul, TzTok-Jad know you serious.",
"You get it back if you victorious."
).also { stage++ }
40 -> showTopics(
Topic(FacialExpression.HALF_GUILTY, "That's fair, here's 8000 TokKul.", 41),
Topic(FacialExpression.HALF_GUILTY, "I don't have that much on me, but I'll go get it.", END_DIALOGUE),
Topic("TzTok-Jad must be old and tired to not just accept my challenge.", 42, skipPlayer = true)
)
41 -> if (removeItem(player, Item(Items.TOKKUL_6529, 8000))) {
npc(FacialExpression.NEUTRAL,
"Okay JalYt. Enter cave when you are prepared.",
"You find TzTok-Jad waiting for JalYt challenger."
)
.also { setAttribute(player, "fc_practice_jad", true) }
.also { stage = END_DIALOGUE }
} else npc(FacialExpression.NEUTRAL,
"JalYt, you not have the TokKul.",
"You come back when you are serious."
).also { stage = END_DIALOGUE }
42 -> player(FacialExpression.HALF_GUILTY,
"TzTok-Jad must be old and tired",
"to not just accept my challenge."
).also { stage++ }
43 -> npc(FacialExpression.ANGRY,
"JalYt-Mor, you the old and tired one.",
"You the one not want to do proper training."
).also { stage = END_DIALOGUE }
50 -> npc(FacialExpression.NEUTRAL,
"TzTok-Jad is waiting for you.",
"Do not make TzTok-Jad wait long."
).also { stage = END_DIALOGUE }
100 -> sendDialogueOptions(player, "Sell your fire cape?", "Yes, sell it for 8,000 TokKul.", "No, keep it.").also { stage++ }
101 -> when (buttonId) {
1 -> npcl(FacialExpression.OLD_NORMAL, "Hand your cape here, young JalYte.").also { stage++ }
2 -> end()
}
102 -> end().also { if (removeItem(player, Items.FIRE_CAPE_6570)) addItem(player, Items.TOKKUL_6529, 8000) }
}
return true
}
override fun newInstance(player: Player): DialoguePlugin {
return TzHaarMejJal(player)
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.TZHAAR_MEJ_JAL_2617)
}
}

View file

@ -1,263 +0,0 @@
package content.region.karamja.tzhaar.handlers;
import core.cache.def.impl.NPCDefinition;
import core.game.dialogue.DialogueInterpreter;
import core.game.dialogue.DialoguePlugin;
import core.game.dialogue.FacialExpression;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import core.game.world.repository.Repository;
import core.plugin.Plugin;
import core.plugin.ClassScanner;
import core.plugin.Initializable;
import core.tools.RandomFunction;
/**
* Handles everything in regards to jad pet.
* @author Empathy
*
*/
@Initializable
public class TzRekJadNPC extends OptionHandler {
/**
* The tzhaar mej id.
*/
private static final int TZHAAR_MEJ_ID = 2617;
/**
* The firecape item.
*/
private static final Item FIRECAPE = new Item(6570);
/**
* The tokkul item.
*/
private static final Item TOKKUL = new Item(6529);
/**
* The jad item.
*/
private static final Item JAD_PET = new Item(14828);
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
NPCDefinition.forId(TZHAAR_MEJ_ID).getHandlers().put("option:exchange fire cape", this);
ClassScanner.definePlugins(new TzhaarMejJalDialogue(), new TzRekJadDialogue());
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
switch (option) {
case "exchange fire cape":
player.getDialogueInterpreter().open(DialogueInterpreter.getDialogueKey(player.getInventory().containsItem(FIRECAPE) ? "firecape-exchange" : "tzhaar-mej"), node.asNpc());
break;
}
return true;
}
/**
* Handles the TzhaarMejJal Dialogue to gamble for jad pet.
* @author Empathy
*
*/
public final class TzhaarMejJalDialogue extends DialoguePlugin {
/**
* Constructs a new {@code TzhaarMejJalDialogue} {@code Object}.
*/
public TzhaarMejJalDialogue() {
/**
* empty.
*/
}
/**
* Constructs a new {@code TzhaarMejJalDialogue} {@code Object}.
*
* @param player the player.
*/
public TzhaarMejJalDialogue(Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new TzhaarMejJalDialogue(player);
}
@Override
public boolean open(Object... args) {
npc = (NPC) args[0];
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "I have a fire cape here.");
stage = 0;
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
switch (stage) {
case 0:
interpreter.sendOptions("Sell your fire cape?", "Yes, sell it for 8,000 TokKul.", "No, keep it.", "Bargain for TzRek-Jad.");
stage = 1;
break;
case 1:
switch(buttonId) {
case 1:
interpreter.sendDialogues(npc, FacialExpression.OLD_NORMAL, player.getInventory().containsItems(FIRECAPE) ? "Hand your cape here, young JalYte." : "You not have firecape, JalYt.");
stage = 10;
break;
case 2:
end();
break;
case 3:
interpreter.sendOptions("Sacrifice your firecape?", "Yes, I know I won't get my cape back.", "No, I like my cape!");
stage = 20;
break;
}
break;
case 10:
if (player.getInventory().containsItem(FIRECAPE)) {
if (player.getInventory().remove(FIRECAPE)) {
TOKKUL.setAmount(8000);
player.getInventory().add(TOKKUL);
TOKKUL.setAmount(1);
}
}
end();
break;
case 20:
switch (buttonId) {
case 1:
if (player.hasItem(JAD_PET)) {
interpreter.sendDialogues(npc, FacialExpression.OLD_NORMAL, "Best you train one TzRek-Jad only.");
stage = 21;
break;
}
if (player.getFamiliarManager().hasFamiliar()) {
if (player.getFamiliarManager().getFamiliar().getId() == 8650) {
interpreter.sendDialogues(npc, FacialExpression.OLD_NORMAL, "Best you train one TzRek-Jad only.");
stage = 21;
break;
}
}
if (player.getInventory().remove(FIRECAPE)) {
int r = RandomFunction.getRandom(200);
if (r == 1) {
interpreter.sendDialogues(npc, FacialExpression.OLD_NORMAL, "You lucky. Better train him good else TzTok-Jad find", "you, JalYt.");
if (!player.getFamiliarManager().hasFamiliar()) {
player.getFamiliarManager().summon(JAD_PET, true);
player.sendNotificationMessage("You have a funny feeling like you're being followed.");
} else if (player.getInventory().freeSlots() > 0) {
player.getInventory().add(JAD_PET);
player.sendNotificationMessage("You feel something weird sneaking into your backpack.");
}
Repository.sendNews(player.getUsername() + " now commands a miniature TzTok-Jad!");
} else {
interpreter.sendDialogues(npc, FacialExpression.OLD_NORMAL, "You not lucky. Maybe next time, JalYt.");
}
}
stage = 21;
break;
case 2:
end();
break;
}
break;
case 21:
end();
break;
}
return true;
}
@Override
public int[] getIds() {
return new int[] { DialogueInterpreter.getDialogueKey("firecape-exchange") };
}
}
/**
* Handles the TzRekJad dialogue.
* @author Empathy
*
*/
public final class TzRekJadDialogue extends DialoguePlugin {
/**
* Constructs a new {@code TzRekJadDialogue} {@code Object}.
*/
public TzRekJadDialogue() {
/**
* empty.
*/
}
/**
* Constructs a new {@code TzRekJadDialogue} {@code Object}.
*
* @param player the player.
*/
public TzRekJadDialogue(Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new TzRekJadDialogue(player);
}
@Override
public boolean open(Object... args) {
npc = (NPC) args[0];
int i = RandomFunction.getRandom(1);
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, i == 1 ? "Do you miss your people?" : "Are you hungry?");
stage = (i == 1 ? 0 : 5);
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
switch (stage) {
case 0:
interpreter.sendDialogues(npc, FacialExpression.OLD_NORMAL, "Mej-TzTok-Jad Kot-Kl!");
stage = 1;
break;
case 1:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "No.. I don't think so.");
stage = 2;
break;
case 2:
interpreter.sendDialogues(npc, FacialExpression.OLD_NORMAL, "Jal-Zek Kl?");
stage = 3;
break;
case 3:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "No, no, I wouldn't hurt you.");
stage = 4;
break;
case 4:
end();
break;
case 5:
interpreter.sendDialogues(npc, FacialExpression.OLD_NORMAL, "Kl-Kra!");
stage = 6;
break;
case 6:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Ooookay...");
stage = 4;
break;
}
return true;
}
@Override
public int[] getIds() {
return new int[] { 8650 };
}
}
}

View file

@ -1,203 +0,0 @@
package content.region.karamja.tzhaar.handlers;
import core.cache.def.impl.SceneryDefinition;
import core.game.activity.ActivityManager;
import core.game.dialogue.DialoguePlugin;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player;
import core.game.node.scenery.Scenery;
import core.game.world.map.Location;
import core.plugin.Initializable;
import core.plugin.Plugin;
/**
* Represents the plugin used for tzhaar city.
* @author 'Vexia
* @version 1.0
*/
@Initializable
public final class TzhaarCityPlugin extends OptionHandler {
/**
* Represents the locations to use.
*/
private static final Location[] LOCATIONS = new Location[] { Location.create(2480, 5175, 0), Location.create(2866, 9571, 0) };
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
SceneryDefinition.forId(31284).getHandlers().put("option:enter", this); //karamja cave.
SceneryDefinition.forId(9359).getHandlers().put("option:enter", this); //tzhaar exit
SceneryDefinition.forId(9356).getHandlers().put("option:enter", this);
SceneryDefinition.forId(9369).getHandlers().put("option:pass", this);
SceneryDefinition.forId(31292).getHandlers().put("option:go-through", this); //unimplemented door near fairy ring
new TzhaarDialogue().init();
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
int id = ((Scenery) node).getId();
switch (option) {
case "enter":
switch (id) {
case 31284:
player.getProperties().setTeleportLocation(LOCATIONS[0]);
break;
case 9359:
player.getProperties().setTeleportLocation(LOCATIONS[1]);
break;
case 9356:
if (player.getFamiliarManager().hasFamiliar()) {
player.getPacketDispatch().sendMessage("You can't enter this with a follower.");
break;
}
ActivityManager.start(player, "fight caves", false);
break;
}
break;
case "pass":
switch (id) {
case 9369:
ActivityManager.start(player, "fight pits", false);
break;
}
break;
case "go-through":
switch (id) {
case 31292:
return false;
}
break;
}
return true;
}
/**
* Represents the dialogue plugin used for the tzhaar npcs.
* @author 'Vexia
* @version 1.0
*/
public static final class TzhaarDialogue extends DialoguePlugin {
/**
* Constructs a new {@code TzhaarDialogue} {@code Object}.
*/
public TzhaarDialogue() {
/**
* empty.
*/
}
/**
* Constructs a new {@code TzhaarDialogue} {@code Object}.
* @param player the player.
*/
public TzhaarDialogue(Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new TzhaarDialogue(player);
}
@Override
public boolean open(Object... args) {
npc = (NPC) args[0];
npc("Can I help you JalYt-Ket-" + player.getUsername() + "?");
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
switch (stage) {
case 0:
options("What do you have to trade?", "What did you call me?", "No I'm fine thanks.");
stage = 1;
break;
case 1:
switch (buttonId) {
case 1:
end();
npc.openShop(player);
break;
case 2:
player("What did you call me?");
stage = 20;
break;
case 3:
player("No I'm fine thanks.");
stage = 30;
break;
}
break;
case 10:
break;
case 20:
npc("Are you not JalYt-Ket?");
stage = 21;
break;
case 21:
options("What's a 'JalYt-Ket'?", "I guess so...", "No I'm not!");
stage = 22;
break;
case 22:
switch (buttonId) {
case 1:
player("What's a 'JalYt-Ket'?");
stage = 100;
break;
case 2:
player("I guess so...");
stage = 120;
break;
case 3:
player("No I'm not!");
stage = 130;
break;
}
break;
case 100:
npc("That what you are... you tough and strong no?");
stage = 101;
break;
case 101:
player("Well yes I suppose I am...");
stage = 102;
break;
case 102:
npc("Then you JalYt-Ket!");
stage = 103;
break;
case 103:
end();
break;
case 120:
npc("Well then, no problems.");
stage = 121;
break;
case 121:
end();
break;
case 130:
end();
break;
case 23:
end();
break;
case 30:
end();
break;
}
return true;
}
@Override
public int[] getIds() {
return new int[] { 2620, 2622, 2623 };
}
}
}

View file

@ -62,7 +62,7 @@ public final class TzhaarFightCavesPlugin extends ActivityPlugin {
* @param player The player.
*/
public TzhaarFightCavesPlugin(Player player) {
super("fight caves", true, true, true, ZoneRestriction.CANNON, ZoneRestriction.RANDOM_EVENTS);
super("fight caves", true, true, true, ZoneRestriction.CANNON, ZoneRestriction.RANDOM_EVENTS, ZoneRestriction.FOLLOWERS);
super.player = player;
}

View file

@ -0,0 +1,36 @@
package content.region.karamja.tzhaar.handlers
import core.api.sendNPCDialogueLines
import core.api.teleport
import core.game.activity.ActivityManager
import core.game.dialogue.FacialExpression
import core.game.interaction.IntType
import core.game.interaction.InteractionListener
import core.game.world.map.Location
import org.rs09.consts.NPCs
class TzhaarListeners : InteractionListener {
override fun defineListeners() {
on(intArrayOf(31284, 9359, 9356), IntType.SCENERY, "enter") { player, node ->
when (node.id) {
31284 -> teleport(player, Location.create(2480, 5175, 0))
9359 -> teleport(player, Location.create(2866, 9571, 0))
9356 -> {
if (player.familiarManager.hasFamiliar()) {
sendNPCDialogueLines(player, NPCs.TZHAAR_MEJ_JAL_2617, FacialExpression.ANGRY, false, "No Kimit-Zil in the cave! This is a fight for YOU,", "not your friends!")
} else ActivityManager.start(player, "fight caves", false)
}
}
return@on true
}
on(9369, IntType.SCENERY, "pass") { player, _ ->
ActivityManager.start(player, "fight pits", false)
return@on true
}
on(31292, IntType.SCENERY, "go-through") { _, _ ->
return@on false
}
}
}

View file

@ -826,43 +826,53 @@ class TheDigSiteListeners : InteractionListener {
}
on(Items.UNIDENTIFIED_LIQUID_702, ITEM, "drop") { player, node ->
removeItem(player, node)
impact(player, 25)
sendChat(player, "Ow! The liquid exploded!")
sendMessage(player, "You were injured by the burning liquid.")
return@on true
if (removeItem(player, node)) {
impact(player, 25)
sendChat(player, "Ow! The liquid exploded!")
sendMessage(player, "You were injured by the burning liquid.")
return@on true
}
return@on false
}
on(Items.NITROGLYCERIN_703, ITEM, "drop") { player, node ->
removeItem(player, node)
impact(player, 35)
sendChat(player, "Ow! The nitroglycerin exploded!")
sendMessage(player, "You were injured by the burning liquid.")
return@on true
if (removeItem(player, node)) {
impact(player, 35)
sendChat(player, "Ow! The nitroglycerin exploded!")
sendMessage(player, "You were injured by the burning liquid.")
return@on true
}
return@on false
}
on(Items.MIXED_CHEMICALS_705, ITEM, "drop") { player, node ->
removeItem(player, node)
impact(player, 45)
sendChat(player, "Ow! The liquid exploded!")
sendMessage(player, "You were injured by the burning liquid.")
return@on true
if (removeItem(player, node)) {
impact(player, 45)
sendChat(player, "Ow! The liquid exploded!")
sendMessage(player, "You were injured by the burning liquid.")
return@on true
}
return@on false
}
on(Items.MIXED_CHEMICALS_706, ITEM, "drop") { player, node ->
removeItem(player, node)
impact(player, 55)
sendChat(player, "Ow! The liquid exploded!")
sendMessage(player, "You were injured by the burning liquid.")
return@on true
if (removeItem(player, node)) {
impact(player, 55)
sendChat(player, "Ow! The liquid exploded!")
sendMessage(player, "You were injured by the burning liquid.")
return@on true
}
return@on false
}
on(Items.CHEMICAL_COMPOUND_707, ITEM, "drop") { player, node ->
removeItem(player, node)
impact(player, 65)
sendChat(player, "Ow! The liquid exploded!")
sendMessage(player, "You were injured by the burning liquid.")
return@on true
if (removeItem(player, node)) {
impact(player, 65)
sendChat(player, "Ow! The liquid exploded!")
sendMessage(player, "You were injured by the burning liquid.")
return@on true
}
return@on false
}
// Scenery not tied to quest

View file

@ -0,0 +1,141 @@
package content.region.misthalin.draynor.handlers
import core.api.hasLineOfSight
import core.game.interaction.MovementPulse
import core.game.node.entity.Entity
import core.game.node.entity.impl.PulseType
import core.game.node.entity.npc.AbstractNPC
import core.game.node.entity.player.Player
import core.game.world.map.Location
import core.game.world.map.RegionManager
import core.game.world.map.path.Pathfinder
import core.plugin.Initializable
/**
* Represents the Draynor Manor Chair NPC, these are the chairs that follow the player
* around the manor.
*
* @author Broseki
*/
private const val DRAYNOR_MANOR_CHAIR_NPC_ID = 3293
private const val FOLLOWING_DISTANCE = 5
private const val STOP_FOLLOWING_DISTANCE = 30
@Initializable
class DraynorManorChairNPC(id: Int = DRAYNOR_MANOR_CHAIR_NPC_ID, location: Location? = null) :
AbstractNPC(id, location) {
// The player this NPC is currently following, null if nobody is being followed
private var following: Player? = null
override fun construct(id: Int, location: Location, vararg objects: Any): AbstractNPC {
return DraynorManorChairNPC(id, location)
}
override fun handleTickActions() {
super.handleTickActions()
val closestPlayer = findClosestPlayer()
// If there is a player nearby, follow them
if (closestPlayer != null && following != closestPlayer) {
stopFollowing()
following = closestPlayer
follow(closestPlayer)
following?.let { face(it) }
} else {
// If we didn't find a player within `FOLLOWING_DISTANCE`
// but we are following a player, check that they are still
// within `STOP_FOLLOWING_DISTANCE`, if they are gone, stop
// trying to follow them.
following?.let { player ->
if (findDistanceToPlayer(player) > STOP_FOLLOWING_DISTANCE
|| !player.isActive
|| player.isInvisible) {
stopFollowing()
} else {
if (!pulseManager.hasPulseRunning()) {
follow(player)
}
face(player)
}
}
}
}
/**
* Stops following `following`
*/
fun stopFollowing() {
following = null
resetWalk()
pulseManager.clear(PulseType.STANDARD)
}
/**
* Finds the closest player to the current entity within `FOLLOWING_DISTANCE`
* that is currently in the chair's line of sight.
*
* @return The Player object representing the closest player, or null if there are no players nearby.
*/
fun findClosestPlayer(): Player? {
val players = RegionManager.getLocalPlayers(this, FOLLOWING_DISTANCE)
if (players.isEmpty()) {
return null
}
var closestPlayer: Player? = null
var closestDistance = Double.MAX_VALUE
for (player in players) {
// Make sure the chair does not try to start
// following a player in another room
if (!hasLineOfSight(this, player)) {
continue
}
// If the player is invisible, don't follow them
if (player.isInvisible) {
continue
}
val distance = findDistanceToPlayer(player)
if (distance < closestDistance) {
closestDistance = distance
closestPlayer = player
}
}
return closestPlayer
}
/**
* Calculates the distance between the current entity and the specified player.
*
* @param player The player whose distance from the current entity is to be calculated.
* @return The distance between the current entity and the specified player as a Double value.
*/
fun findDistanceToPlayer(player: Player): Double {
return this.location.getDistance(player.location)
}
/**
* Triggers the current entity to follow the specified player using a movement pulse.
*
* @param player The player that the entity should follow.
*/
fun follow(player: Player) {
pulseManager.run((object : MovementPulse(this, player, Pathfinder.DUMB) {
override fun pulse(): Boolean {
return false
}
}), PulseType.STANDARD)
}
override fun getIds(): IntArray {
return intArrayOf(DRAYNOR_MANOR_CHAIR_NPC_ID)
}
override fun shouldPreventStacking(mover: Entity?): Boolean {
return mover is DraynorManorChairNPC
}
}

View file

@ -0,0 +1,57 @@
package content.region.misthalin.draynor.handlers
import core.game.node.entity.Entity
import core.game.world.map.Location
import core.game.world.map.RegionManager.getLocalNpcs
import core.game.world.map.path.Pathfinder
import core.game.world.map.zone.MapZone
import core.game.world.map.zone.ZoneBorders
import core.game.world.map.zone.ZoneBuilder
import core.plugin.Initializable
import core.plugin.Plugin
/**
* Represents the interior of Draynor Manor.
*
* @author Broseki
*/
@Initializable
class DraynorManorHouseZone : MapZone("Draynor Manor House", true), Plugin<Any?> {
override fun newInstance(arg: Any?): Plugin<Any?> {
ZoneBuilder.configure(this)
return this
}
override fun move(e: Entity, loc: Location?, destination: Location): Boolean {
for (n in getLocalNpcs(e, 5)) {
if (n.isInvisible() || n === e) {
continue
}
if (n.shouldPreventStacking(e)) {
val s1 = e.size()
val s2 = n.size()
val x = destination.getX()
val y = destination.getY()
val l = n.getLocation()
if (Pathfinder.isStandingIn(x, y, s1, s1, l.getX(), l.getY(), s2, s2)) {
return false
}
}
}
return true
}
override fun enter(entity: Entity?): Boolean {
return super.enter(entity)
}
override fun fireEvent(identifier: String?, vararg args: Any?): Any? {
return null
}
override fun configure() {
register(ZoneBorders(3097, 3373, 3119, 3364))
register(ZoneBorders(3090, 3363, 3126, 3354))
}
}

View file

@ -0,0 +1,145 @@
package content.region.misthalin.lumbridge.handlers
import core.api.*
import core.game.interaction.MovementPulse
import core.game.interaction.QueueStrength
import core.game.node.entity.Entity
import core.game.node.entity.combat.ImpactHandler.HitsplatType
import core.game.node.entity.npc.NPC
import core.game.node.entity.npc.NPCBehavior
import core.game.node.entity.player.Player
import core.game.world.map.Location
import core.game.world.map.zone.ZoneBorders
import core.game.world.repository.Repository
import org.rs09.consts.Items
import org.rs09.consts.NPCs
/**
* NPCs.WALL_BEAST_7823 starts out as NPCs.HOLE_IN_THE_WALL_2058 first.
* On death, it will respawn a new hole in the wall.
*
* h2QAZzGds9o
*
* npc anim 1807
* {3161,9547,0,0,3}-{3164,9556,0,0,4}-{3162,9574,0,0,3}-{3198,9554,0,0,7}-{3198,9572,0,0,1}-{3215,9560,0,0,1}-{3216,9588,0,0,1}-
*/
class WallBeastBehavior : NPCBehavior(NPCs.HOLE_IN_THE_WALL_2058, NPCs.WALL_BEAST_7823) {
override fun onCreation(self: NPC) {
// This NPC should never move.
self.walkRadius = 0
self.isNeverWalks = true
}
override fun onDeathFinished(self: NPC, entity: Entity) {
self.reTransform()
// I don't think this is needed since the respawn will be immediate.
}
}
class WallBeastNTrigger : MapArea {
companion object {
/** Finds the nearest NPC of npcId to location. */
fun findNearestNPC(location: Location, npcId: Int): NPC? {
// maybe replace contentAPI's version of this
return Repository.npcs
.filter { it.id == npcId }
.toMutableList()
.sortedWith { a, b ->
return@sortedWith (Location.getDistance(a.location, location) - Location.getDistance(b.location, location)).toInt()
}
.firstOrNull()
}
fun isHelmetInEquipment(entity: Player): Boolean {
return inEquipment(entity, Items.SPINY_HELMET_4551) ||
inEquipment(entity, Items.SLAYER_HELMET_13263) ||
inEquipment(entity, Items.SPIKED_HELMET_13105) ||
inEquipment(entity, Items.SLAYER_HELMET_E_14636) ||
inEquipment(entity, Items.SLAYER_HELMET_CHARGED_14637)
}
}
override fun defineAreaBorders(): Array<ZoneBorders> {
// The goals here are in order
return arrayOf(
ZoneBorders(3161,9546,3161,9546),
ZoneBorders(3164,9555,3164,9555),
ZoneBorders(3162,9573,3162,9573),
ZoneBorders(3198,9553,3198,9553),
ZoneBorders(3198,9571,3198,9571),
ZoneBorders(3215,9559,3215,9559),
ZoneBorders(3216,9587,3216,9587),
)
}
override fun areaEnter(entity: Entity) {
if (entity is Player) {
val nearbyWallbeast = findNearestNPC(entity.location, NPCs.HOLE_IN_THE_WALL_2058) // wallbeasts are always 1 square north.
// println(nearbyWallbeast)
if (nearbyWallbeast != null) {
lock(entity, 2)
stopWalk(entity)
// Stop walk doesn't stop the player from walking on.
// You have to clear the movement pulse that is continually feeding the walk location.
val movementPulse = entity.getPulseManager().current;
if (movementPulse is MovementPulse) {
movementPulse.stop();
}
face(entity, nearbyWallbeast.location)
queueScript(nearbyWallbeast, 2, QueueStrength.STRONG) { stage: Int ->
when (stage) {
0 -> {
if (isHelmetInEquipment(entity)) {
animate(nearbyWallbeast, 1805)
} else {
animate(nearbyWallbeast, 1806)
}
return@queueScript delayScript(nearbyWallbeast, 1)
}
1 -> {
if (isHelmetInEquipment(entity)) {
// You can only attack the wallbeast if you have a helmet
transformNpc(nearbyWallbeast, NPCs.WALL_BEAST_7823, 300)
return@queueScript stopExecuting(nearbyWallbeast)
} else {
animate(nearbyWallbeast, 1807)
return@queueScript delayScript(nearbyWallbeast, 4)
}
}
2 -> {
animate(nearbyWallbeast, 1808)
return@queueScript stopExecuting(nearbyWallbeast)
}
else -> return@queueScript stopExecuting(nearbyWallbeast)
}
}
queueScript(entity, 2, QueueStrength.STRONG) { stage: Int ->
when (stage) {
0 -> {
if (isHelmetInEquipment(entity)) {
return@queueScript stopExecuting(entity)
}
lock(entity, 5)
return@queueScript delayScript(entity, 1)
}
1 -> {
animate(entity, 1810) // 734
return@queueScript delayScript(entity, 4)
}
2 -> {
// I don't know how much they are supposed to hit... osrs says up to 18...
impact(entity, (13 .. 18).random() , HitsplatType.NORMAL)
animate(entity, 1811) // 734
return@queueScript stopExecuting(entity)
}
else -> return@queueScript stopExecuting(entity)
}
}
}
}
}
}

View file

@ -0,0 +1,14 @@
package content.region.wilderness.handlers
import core.api.*
import core.game.world.map.zone.ZoneBorders
import core.game.world.map.zone.ZoneRestriction
class KingBlackDragonArea : MapArea {
override fun defineAreaBorders() : Array<ZoneBorders> {
return arrayOf(ZoneBorders(2256, 4680, 2287, 4711, 0, true))
}
override fun getRestrictions() : Array<ZoneRestriction> {
return arrayOf(ZoneRestriction.RANDOM_EVENTS)
}
}

View file

@ -74,8 +74,10 @@ public class RevenantCombatHandler extends MultiSwingHandler {
}
}
}
if (!isPoisoned(victim) && (WildernessZone.getWilderness(entity) >= 50 || entity.getId() == 6998)) {
applyPoison(victim, entity, 6);
if (entity.getId() == 6998) {
applyPoison(victim, entity, 40);
} else if (WildernessZone.getWilderness(entity) >= 50) {
applyPoison(victim, entity, 30);
}
super.impact(entity, victim, state);
}

View file

@ -2193,6 +2193,10 @@ fun dumpContainer(player: Player, container: core.game.container.Container): Int
var dumpedCount = 0
run beginDepositing@{
if (hasIronmanRestriction(player, IronmanMode.ULTIMATE)) {
return@beginDepositing
}
container.toArray().filterNotNull().forEach { item ->
if (!bank.hasSpaceFor(item)) {
sendMessage(player, "You have no more space in your bank.")
@ -3046,11 +3050,18 @@ fun applyPoison (entity: Entity, source: Entity, severity: Int) {
if(hasTimerActive<PoisonImmunity>(entity)) {
return
}
if(entity.isPoisonImmune()) {
return
}
val existingTimer = getTimer<Poison>(entity)
if (existingTimer != null) {
existingTimer.severity = severity
existingTimer.damageSource = source
if (existingTimer.severity > severity) {
return
} else {
existingTimer.severity = severity
existingTimer.damageSource = source
}
} else {
registerTimer(entity, spawnTimer<Poison>(source, severity))
}

View file

@ -20,14 +20,11 @@ enum class God(vararg val validItems: Int) {
Items.BANDOS_TASSETS_11726,
),
SARADOMIN(
Items.ANCIENT_SYMBOL_11181,
Items.GILDED_KITESHIELD_3489,
Items.DAMAGED_BOOK_3839,
Items.HOLY_BOOK_3840,
Items.HOLY_SYMBOL_1718,
Items.HOLY_SYMBOL_4682,
Items.MONKS_ROBE_542,
Items.MONKS_ROBE_544,
Items.RUNE_HERALDIC_HELM_8488,
Items.SARADOMIN_BRACERS_10384,
Items.SARADOMIN_CAPE_2412,
Items.SARADOMIN_CHAPS_10388,
@ -43,26 +40,16 @@ enum class God(vararg val validItems: Int) {
Items.SARADOMIN_PLATEBODY_2661,
Items.SARADOMIN_PLATELEGS_2663,
Items.SARADOMIN_PLATESKIRT_3479,
Items.SARADOMIN_PLATESKIRT_3675,
Items.SARADOMIN_ROBE_LEGS_10464,
Items.SARADOMIN_ROBE_TOP_10458,
Items.SARADOMIN_STAFF_2415,
Items.SARADOMIN_STOLE_10470,
Items.SARADOMIN_SWORD_11730,
Items.SARADOMIN_SYMBOL_8055,
Items.STEEL_HERALDIC_HELM_8706,
),
ZAMORAK(
Items.DAGONHAI_HAT_14499,
Items.DAGONHAI_ROBE_TOP_14497,
Items.DAGONHAI_ROBE_BOTTOM_14501,
Items.DAMAGED_BOOK_3841,
Items.RUNE_HERALDIC_HELM_8494,
Items.STEEL_HERALDIC_HELM_8712,
Items.UNHOLY_BOOK_3842,
Items.UNHOLY_SYMBOL_1724,
Items.UNHOLY_SYMBOL_3852,
Items.UNHOLY_SYMBOL_4683,
Items.ZAMORAK_BRACERS_10368,
Items.ZAMORAK_CAPE_2414,
Items.ZAMORAK_CHAPS_10372,
@ -81,19 +68,17 @@ enum class God(vararg val validItems: Int) {
Items.ZAMORAK_PLATEBODY_2653,
Items.ZAMORAK_PLATELEGS_2655,
Items.ZAMORAK_PLATESKIRT_3478,
Items.ZAMORAK_PLATESKIRT_3674,
Items.ZAMORAK_ROBE_LEGS_10468,
Items.ZAMORAK_ROBE_TOP_10460,
Items.ZAMORAK_ROBE_TOP_10786,
Items.ZAMORAK_STAFF_2417,
Items.ZAMORAK_STOLE_10474,
Items.ZAMORAK_SYMBOL_8056,
Items.ZAMORAK_ROBE_1033,
Items.ZAMORAK_ROBE_1035,
),
GUTHIX(
Items.STEEL_HERALDIC_HELM_8692,
Items.RUNE_HERALDIC_HELM_8474,
Items.DAMAGED_BOOK_3843,
Items.BOOK_OF_BALANCE_3844,
Items.GUTHIX_BRACERS_10376,
Items.GUTHIX_CAPE_10720,
Items.GUTHIX_CHAPS_10380,
@ -102,24 +87,18 @@ enum class God(vararg val validItems: Int) {
Items.GUTHIX_CROZIER_10442,
Items.GUTHIX_DRAGONHIDE_10378,
Items.GUTHIX_DRAGONHIDE_10794,
Items.GUTHIX_FULL_HELM_13833,
Items.GUTHIX_FULL_HELM_2673,
Items.GUTHIX_KITESHIELD_13834,
Items.GUTHIX_KITESHIELD_2675,
Items.GUTHIX_MITRE_10454,
Items.GUTHIX_MJOLNIR_6760,
Items.GUTHIX_PLATEBODY_10780,
Items.GUTHIX_PLATEBODY_2669,
Items.GUTHIX_PLATEBODY_13830,
Items.GUTHIX_PLATELEGS_2671,
Items.GUTHIX_PLATELEGS_13831,
Items.GUTHIX_PLATESKIRT_13832,
Items.GUTHIX_PLATESKIRT_3676,
Items.GUTHIX_ROBE_LEGS_10466,
Items.GUTHIX_ROBE_TOP_10462,
Items.GUTHIX_ROBE_TOP_10788,
Items.GUTHIX_STAFF_2416,
Items.GUTHIX_STOLE_10472,
Items.GUTHIX_SYMBOL_8057,
)
}

View file

@ -42,27 +42,48 @@ open class WeightBasedTable : ArrayList<WeightedItem>() {
return roll(receiver, 1)
}
open fun roll(receiver: Entity? = null, times: Int = 1): ArrayList<Item>{
val items = ArrayList<WeightedItem>((guaranteedItems.size + 1) * times)
open fun roll(receiver: Entity?, times: Int = 1): ArrayList<Item> {
val weightedItemsToDrop = ArrayList<WeightedItem>()
for (i in 0 until times) {
items.addAll(guaranteedItems)
repeat(times) {
// Guaranteed items
for (item in guaranteedItems) {
if (isSpecialSlot(item.id)) {
val rolls = RandomFunction.random(item.minAmt, item.maxAmt)
repeat(rolls) {
weightedItemsToDrop.add(item)
}
} else {
// Add just one instance with amount set by getItem()
weightedItemsToDrop.add(item)
}
}
if (size == 1) {
items.add(get(0))
} else if (isNotEmpty()) {
// Weighted roll (one per table roll)
if (isNotEmpty()) {
var rngWeight = RandomFunction.randomDouble(totalWeight)
for (item in this) {
rngWeight -= item.weight
if (rngWeight <= 0) {
items.add(item)
if (isSpecialSlot(item.id)) {
val rolls = RandomFunction.random(item.minAmt, item.maxAmt)
repeat(rolls) {
weightedItemsToDrop.add(item)
}
} else {
weightedItemsToDrop.add(item)
}
break
}
}
}
}
return convertWeightedItems(items, receiver)
return convertWeightedItems(weightedItemsToDrop, receiver)
}
private fun isSpecialSlot(id: Int): Boolean {
return id == SLOT_HDT || id == SLOT_USDT // extend this if a drop table is not dropping multiple times
}
fun convertWeightedItems(weightedItems: ArrayList<WeightedItem>, receiver: Entity?): ArrayList<Item> {

View file

@ -161,7 +161,7 @@ abstract class DialogueFile {
return true
}
else if (validTopics.size == 1) {
val topic = topics[0]
val topic = topics.filter { it.text == validTopics[0] }[0]
if(topic.toStage is DialogueFile) {
val topicFile = topic.toStage as DialogueFile
interpreter!!.dialogue.loadFile(topicFile)

View file

@ -328,7 +328,6 @@ public final class DialogueInterpreter {
public Component sendItemMessage(int itemId, String... messages) {
// Select interface based on number of messages - 241 (1 line) to 244 (4 lines)
int interfaceId = 240 + messages.length;
player.getInterfaceManager().openChatbox(interfaceId);
player.getPacketDispatch().sendInterfaceConfig(interfaceId, 1, false);
player.getPacketDispatch().sendInterfaceConfig(interfaceId, 2, false);
// Hide or empty the title, since double item messages do not have them. (Child 3)
@ -344,6 +343,8 @@ public final class DialogueInterpreter {
player.getPacketDispatch().sendRepositionOnInterface(interfaceId, 2, 45, 46);
// Hide the second item which seems to be used for double items (child 1)
player.getPacketDispatch().sendInterfaceConfig(interfaceId, 1, true);
// Open the chatbox only after everything is set to avoid lag and flashing default strings (Line 1, Title)
player.getInterfaceManager().openChatbox(interfaceId);
// These are old interfaces which made no sense to use them.
// player.getPacketDispatch().sendString(message, 131, 1);
// player.getPacketDispatch().sendItemOnInterface(itemId, 1, 131, 2);
@ -385,7 +386,6 @@ public final class DialogueInterpreter {
public Component sendDoubleItemMessage(Item first, Item second, String... messages) {
// Select interface based on number of messages - 241 (1 line) to 244 (4 lines)
int interfaceId = 240 + messages.length;
player.getInterfaceManager().openChatbox(interfaceId);
player.getPacketDispatch().sendInterfaceConfig(interfaceId, 1, false);
player.getPacketDispatch().sendInterfaceConfig(interfaceId, 2, false);
// Hide or empty the title, since double item messages do not have them.
@ -404,7 +404,8 @@ public final class DialogueInterpreter {
player.getPacketDispatch().sendItemOnInterface(second.getId(), second.getAmount(), interfaceId, 2);
player.getPacketDispatch().sendAngleOnInterface(interfaceId, 2, (int)(itemDef2.getModelZoom() / 1.5), itemDef2.getModelRotationX(), itemDef2.getModelRotationY());
player.getPacketDispatch().sendRepositionOnInterface(interfaceId, 2, 60, 65);
// Open the chatbox only after everything is set to avoid lag and flashing default strings (Line 1, Title)
player.getInterfaceManager().openChatbox(interfaceId);
return player.getInterfaceManager().getChatbox();
}
@ -518,7 +519,6 @@ public final class DialogueInterpreter {
if (expression == -1) {
expression = FacialExpression.HALF_GUILTY.getAnimationId();
}
player.getInterfaceManager().openChatbox(interfaceId);
player.getPacketDispatch().sendInterfaceConfig(interfaceId, 1, true);
player.getPacketDispatch().sendInterfaceConfig(interfaceId, 2, false);
player.getPacketDispatch().sendAnimationInterface(expression, interfaceId, 2);
@ -537,6 +537,8 @@ public final class DialogueInterpreter {
player.getPacketDispatch().sendString(doSubstitutions(player, messages[i]), interfaceId, (i + 4));
}
player.getPacketDispatch().sendInterfaceConfig(player.getInterfaceManager().getChatbox().getId(), 3, false);
// Open the chatbox only after everything is set to avoid lag and flashing default strings (Line 1, Title)
player.getInterfaceManager().openChatbox(interfaceId);
return player.getInterfaceManager().getChatbox();
}
@ -556,6 +558,7 @@ public final class DialogueInterpreter {
for (int i = 0; i < options.length; i++) {
player.getPacketDispatch().sendString(options[i].toString(), interfaceId, i + 2);
}
// Open the chatbox only after everything is set to avoid lag and flashing default strings (Line 1, Title)
player.getInterfaceManager().openChatbox(interfaceId);
return player.getInterfaceManager().getChatbox();
}

View file

@ -101,13 +101,6 @@ class GrandExchange : StartupListener, Commands {
PriceIndex.allowItem(id)
notify(player, "Allowed ${getItemName(id)} for GE trade.")
}
define("geprivacy", Privilege.STANDARD) {player, _ ->
val current = getAttribute(player, "ge-exclude", false)
val new = !current
notify(player, "Your name is now ${if (new) colorize("%RHIDDEN") else colorize("%RSHOWN")}.")
setAttribute(player, "/save:ge-exclude", new)
}
}
companion object {
@ -131,15 +124,11 @@ class GrandExchange : StartupListener, Commands {
@JvmStatic
fun getRecommendedPrice(itemID: Int, from_bot: Boolean = false): Int {
var base = max(PriceIndex.getValue(itemID), getItemDefPrice(itemID))
var base = PriceIndex.getValue(itemID)
if (from_bot) base = (max(BotPrices.getPrice(itemID), base) * 1.10).toInt()
return base
}
private fun getItemDefPrice(itemID: Int): Int {
return max(itemDefinition(itemID).getConfiguration(ItemConfigParser.GE_PRICE) ?: 0, itemDefinition(itemID).value)
}
@JvmStatic
fun getOfferStats(itemID: Int, sale: Boolean) : String
{
@ -235,8 +224,7 @@ class GrandExchange : StartupListener, Commands {
//GrandExchangeRecords.getInstance(player).update(offer)
if (offer.sell && !player.isArtificial) {
val username = if (getAttribute(player, "ge-exclude", false)) "?????" else player.username
Repository.sendNews(username + " just offered " + offer.amount + " " + getItemName(offer.itemID) + " on the GE.")
sendNews(player.username + " just offered " + offer.amount + " " + getItemName(offer.itemID) + " on the GE.")
}
if (ServerConstants.I_AM_A_CHEATER) {

View file

@ -146,10 +146,7 @@ class GrandExchangeOffer() {
visualize(player)
stmt.close()
val username = if (getAttribute(player ?: return@run, "ge-exclude", false)) "?????"
else player?.username ?: "?????"
Discord.postNewOffer(sell, itemID, offeredValue, amount, username)
Discord.postNewOffer(sell, itemID, offeredValue, amount, player?.username ?: return@run)
}
}
}

View file

@ -3,6 +3,7 @@ package core.game.node.entity.combat
import content.global.skill.skillcapeperks.SkillcapePerks
import content.global.skill.slayer.SlayerEquipmentFlags
import content.global.skill.slayer.SlayerManager
import content.global.skill.slayer.Tasks
import core.api.*
import core.api.EquipmentSlot
import core.game.container.impl.EquipmentContainer
@ -114,16 +115,23 @@ open class MeleeSwingHandler (vararg flags: SwingHandlerFlag)
val name = entity.equipment.getNew(3).name
var damage = -1
if (name.contains("(p++") || name.contains("(s)") || name.contains("(kp)")) {
damage = 68
damage = 30
} else if (name.contains("(p+)")) {
damage = 58
damage = 25
} else if (name.contains("(p)")) {
damage = 48
damage = 20
}
if (damage > -1 && RandomFunction.random(10) < 4) {
applyPoison (victim, entity, damage)
}
}
} else if (entity is NPC) {
val poisonous = entity.isPoisonous
val damage = entity.poisonSeverity()
if (poisonous && damage > -1 && RandomFunction.random(10) < 4) {
applyPoison (victim, entity, damage)
}
}
super.adjustBattleState(entity, victim, state)
}
@ -156,7 +164,10 @@ open class MeleeSwingHandler (vararg flags: SwingHandlerFlag)
val amuletId = getItemFromEquipment(entity, EquipmentSlot.NECK)?.id ?: 0
if ((amuletId == Items.SALVE_AMULET_4081 || amuletId == Items.SALVE_AMULETE_10588) && checkUndead(victimName)) {
effectiveAttackLevel *= if (amuletId == Items.SALVE_AMULET_4081) 1.15 else 1.2
} else if (getSlayerTask(entity)?.ids?.contains((entity.properties.combatPulse?.getVictim()?.id ?: 0)) == true) {
} else if (getSlayerTask(entity)?.let { task ->
val victimId = entity.properties.combatPulse?.getVictim()?.id ?: 0
task.ids.contains(victimId) || (task == Tasks.KALPHITES && (victimId == 1158)) // Kalphite Queen phase 1
} == true) {
effectiveAttackLevel *= SlayerEquipmentFlags.getDamAccBonus(entity) //Slayer Helm/ Black Mask/ Slayer cape
if (getSlayerTask(entity)?.dragon == true && inEquipment(entity, Items.DRAGON_SLAYER_GLOVES_12862))
effectiveAttackLevel *= 1.1
@ -192,8 +203,12 @@ open class MeleeSwingHandler (vararg flags: SwingHandlerFlag)
if (!flags.contains(SwingHandlerFlag.IGNORE_STAT_BOOSTS_DAMAGE))
effectiveStrengthLevel *= styleStrengthBonus
else effectiveStrengthLevel *= 64
if (getSlayerTask(entity)?.ids?.contains((entity.properties.combatPulse?.getVictim()?.id ?: 0)) == true)
if (getSlayerTask(entity)?.let { task ->
val victimId = entity.properties.combatPulse?.getVictim()?.id ?: 0
task.ids.contains(victimId) || (task == Tasks.KALPHITES && (victimId == 1158)) // Kalphite Queen phase 1
} == true) {
effectiveStrengthLevel *= SlayerEquipmentFlags.getDamAccBonus(entity) //Slayer Helm/ Black Mask/ Slayer cape
}
return (floor((0.5 + (effectiveStrengthLevel / 640.0))) * modifier).toInt()
}

View file

@ -134,6 +134,13 @@ open class RangeSwingHandler (vararg flags: SwingHandlerFlag) : CombatSwingHandl
if (state.estimatedHit > 0 && damage > 8 && RandomFunction.random(10) < 4) {
applyPoison(victim, entity, damage)
}
} else if (entity is NPC) {
val poisonous = entity.isPoisonous
val damage = entity.poisonSeverity()
if (poisonous && damage > -1 && RandomFunction.random(10) < 4) {
applyPoison (victim, entity, damage)
}
}
super.adjustBattleState(entity, victim, state)
}

View file

@ -1,5 +1,6 @@
package core.game.node.entity.combat.spell;
import content.global.skill.summoning.familiar.Familiar;
import core.game.node.entity.combat.BattleState;
import core.game.node.entity.combat.CombatStyle;
import core.game.node.entity.combat.InteractionType;
@ -13,6 +14,7 @@ import core.game.node.entity.player.link.SpellBookManager;
import core.game.node.entity.player.link.audio.Audio;
import core.game.node.item.Item;
import core.game.world.map.RegionManager;
import core.game.world.map.zone.impl.WildernessZone;
import core.game.world.update.flag.context.Animation;
import core.game.world.update.flag.context.Graphics;
import org.rs09.consts.Sounds;
@ -106,27 +108,42 @@ public abstract class CombatSpell extends MagicSpell {
}
/**
* Gets a list of possible targets for a multihitting spell.
* @param entity The caster of the spell.
* @param target The victim.
* @param max The max amount of victims.
* @return The list of targets.
*/
public List<Entity> getMultihitTargets(Entity entity, Entity target, int max) {
List<Entity> list = new ArrayList<>(20);
list.add(target);
boolean npc = target instanceof NPC;
for (Entity e : npc ? RegionManager.getSurroundingNPCs(target) : RegionManager.getSurroundingPlayers(target)) {
if (e != target && e != entity && CombatStyle.MAGIC.getSwingHandler().canSwing(entity, e) != InteractionType.NO_INTERACT) {
list.add(e);
/**
* Gets a list of valid targets for a multihitting spell.
* @param entity The caster of the spell.
* @param target The primary victim.
* @param max The maximum number of extra victims that may be hit.
* @return The list of targets (the primary target is always at index 0).
*/
public List<Entity> getMultihitTargets(Entity entity, Entity target, int max) {
List<Entity> victims = new ArrayList<>(20);
victims.add(target);
List<Entity> surrounding = new ArrayList<>();
surrounding.addAll(RegionManager.getSurroundingPlayers(target));
surrounding.addAll(RegionManager.getSurroundingNPCs(target));
for (Entity e : surrounding) {
if (e == target || e == entity) {
continue;
}
if (CombatStyle.MAGIC.getSwingHandler().canSwing(entity, e) == InteractionType.NO_INTERACT) {
continue;
}
if (e instanceof Familiar) {
Player owner = ((Familiar) e).getOwner();
if (owner != entity && WildernessZone.getInstance().continueAttack(entity, owner, CombatStyle.MAGIC, true)) {
victims.add(e);
}
} else {
victims.add(e);
}
if (--max < 1) {
break;
}
}
return list;
}
return victims;
}
/**
* Visualizes the impact.
@ -235,4 +252,4 @@ public abstract class CombatSpell extends MagicSpell {
return SPLASH_GRAPHIC;
}
}
}

View file

@ -563,6 +563,14 @@ public class NPC extends Entity {
return definition.getConfiguration(NPCConfigParser.POISON_IMMUNE, false);
}
public boolean isPoisonous() {
return definition.getConfiguration(NPCConfigParser.POISONOUS, false);
}
public int poisonSeverity() {
return definition.getConfiguration(NPCConfigParser.POISON_AMOUNT, 0);
}
@Override
public void finalizeDeath(Entity killer) {
super.finalizeDeath(killer);

View file

@ -617,10 +617,13 @@ public class Player extends Entity {
if (this.isArtificial() && killer instanceof NPC) {
return;
}
if (killer instanceof Player && killer.getName() != getName() /* happens if you died via typeless damage from an external cause, e.g. bugs in a dark cave without a light source */ && getWorldTicks() - killer.getAttribute("/save:last-murder-news", 0) >= 500) {
Item wep = getItemFromEquipment((Player) killer, EquipmentSlot.WEAPON);
sendNews(killer.getUsername() + " has murdered " + getUsername() + " with " + (wep == null ? "their fists." : (StringUtils.isPlusN(wep.getName()) ? "an " : "a ") + wep.getName()));
killer.setAttribute("/save:last-murder-news", getWorldTicks());
if (killer instanceof Player && killer.getName() != getName()) { // the latter happens if you died via typeless damage from an external cause, e.g. bugs in a dark cave without a light source
long unixSeconds = System.currentTimeMillis() / 1000L;
if (unixSeconds - killer.getAttribute("/save:last-murder-news", 0L) >= 300) {
Item wep = getItemFromEquipment((Player) killer, EquipmentSlot.WEAPON);
sendNews(killer.getUsername() + " has murdered " + getUsername() + " with " + (wep == null ? "their fists." : (StringUtils.isPlusN(wep.getName()) ? "an " : "a ") + wep.getName()));
killer.setAttribute("/save:last-murder-news", unixSeconds);
}
}
getPacketDispatch().sendMessage("Oh dear, you are dead!");
incrementAttribute("/save:"+STATS_BASE+":"+STATS_DEATHS);

View file

@ -34,14 +34,14 @@ public enum DiaryType {
"Use Vigroy and Hajedy's cart service",
"Earn 100% favour in the village of Tai Bwo Wannai Cleanup", // todo tai bwo wannai cleanup
"Cook a spider on stick", // todo tai bwo wannai cleanup
"Charter the Lady of the Waves from Cairn Isle to Port Khazard", // todo verify
"Charter the Lady of the Waves from Cairn Isle to Port Khazard",
"Cut a log from a teak tree",
"Cut a log from a mahogany tree",
"Catch a karambwan", // todo need Tai Bwo Wannai Trio
"Exchange gems, a gout tuber, trading sticks for a machete", // todo
"Use the gnome glider to travel to Karamja",
"Grow a healthy fruit tree in the patch near Brimhaven", // todo verify
"Trap a Horned Graahk", // todo need to implement pitfall trapping
"Grow a healthy fruit tree in the patch near Brimhaven",
"Trap a Horned Graahk",
"Chop the vines to gain deeper access to Brimhaven Dungeon",
"Cross the lava using the stepping stones within Brimhaven<br><br>Dungeon",
"Climb the stairs within Brimhaven Dungeon",

View file

@ -239,6 +239,14 @@ class FunCommandSet : CommandSet(Privilege.ADMIN) {
}
}
/**
* Toggle instant woodcutting.
*/
define("instachop", Privilege.ADMIN, "", "Fells trees after a single log is gathered."){ player, _ ->
player.setAttribute("instachop", !player.getAttribute("instachop", false))
notify(player,"Instachop mode " + if (player.getAttribute("instachop", false)) "on." else "off.")
}
}
fun bury(player: Player){

View file

@ -19,6 +19,7 @@ import core.game.node.entity.player.info.Rights
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import core.game.node.scenery.Scenery
import core.game.system.command.Command
import core.game.system.command.CommandMapping
import core.game.system.command.Privilege
import core.game.system.communication.CommunicationInfo
@ -223,11 +224,8 @@ class MiscCommandSet : CommandSet(Privilege.ADMIN){
*/
define("commands", Privilege.STANDARD, "::commands <lt>page<gt>", "Lists all the commands (you are here.)"){player, args ->
val page = if (args.size > 1) (args[1].toIntOrNull() ?: 1) - 1 else 0
var lineid = 11
var pages = CommandMapping.getPageIndices(player.rights.ordinal)
var end = if (page < (pages.size - 1)) pages[page + 1] else CommandMapping.getCommands().size
player.interfaceManager.close()
val pages = CommandMapping.getPageIndices(player.rights.ordinal)
val end = if (page < (pages.size - 1)) pages[page + 1] else CommandMapping.getCommands().size
if (page < 0) {
reject(player, "Usage: ::commands <lt>page<gt>")
@ -237,44 +235,106 @@ class MiscCommandSet : CommandSet(Privilege.ADMIN){
reject(player, "That page number is too high, you don't have access to that many.")
}
for (i in 0..310) {
player.packetDispatch.sendString("", Components.QUESTJOURNAL_SCROLL_275, i)
}
val title = "Commands" + if (pages.size > 1) " (${page + 1}/${pages.size})" else ""
var lineId = setupScrollInterface(player, title)
player.packetDispatch.sendString(
"Commands" + if (pages.size > 1) " (${page + 1}/${pages.size})" else "",
Components.QUESTJOURNAL_SCROLL_275,
2
)
for(i in pages[page] until end) {
var command = CommandMapping.getCommands()[i]
var title = "${command.name}"
var rights = command.privilege.ordinal
var icon = rights - 1
val command = CommandMapping.getCommands()[i]
lineId = displayCommandInScroll(player, command, player.rights.ordinal, lineId)
if (rights > player.rights.ordinal) continue
if (rights > 0)
title = "(<img=$icon>) $title"
player.packetDispatch.sendString(title, Components.QUESTJOURNAL_SCROLL_275, lineid++)
if (command.usage.isNotEmpty())
player.packetDispatch.sendString("Usage: ${command.usage}", Components.QUESTJOURNAL_SCROLL_275, lineid++)
if (command.description.isNotEmpty())
player.packetDispatch.sendString(command.description, Components.QUESTJOURNAL_SCROLL_275, lineid++)
player.packetDispatch.sendString("<str>-------------------------------</str>", Components.QUESTJOURNAL_SCROLL_275, lineid++)
if (lineid > 306) {
player.packetDispatch.sendString("To view the next page, use ::commands ${page + 2}", Components.QUESTJOURNAL_SCROLL_275, lineid)
if (lineId > 306) {
player.packetDispatch.sendString("To view the next page, use ::commands ${page + 2}", Components.QUESTJOURNAL_SCROLL_275, lineId)
break
}
}
player.interfaceManager.open(Component(Components.QUESTJOURNAL_SCROLL_275))
}
/*
* Search for commands
*/
define("commandsearch", Privilege.STANDARD, "::commandsearch <lt>search term<gt> [--chat]", "Searches for commands containing the given term."){player, args ->
if (args.size < 2) {
reject(player, "Usage: ::commandsearch <search term> [--chat]")
return@define
}
val rawArguments = args.copyOfRange(1, args.size)
val chatMode = rawArguments.any { it.equals("--chat", ignoreCase = true) }
val searchRaw = rawArguments.filterNot { it.equals("--chat", ignoreCase = true) }
if (searchRaw.isEmpty()) {
reject(player, "Usage: ::commandsearch <search term> [--chat]")
return@define
}
val search = searchRaw.joinToString(" ").lowercase()
if (search.length < 2) {
reject(player, "Search term must be at least 2 characters long")
return@define
}
val playerRights = player.rights.ordinal
val allMatchingCommands = CommandMapping.getCommands()
.filter { command ->
command.name.lowercase().contains(search) ||
command.usage.lowercase().contains(search) ||
command.description.lowercase().contains(search)
}
if (allMatchingCommands.isEmpty()) {
notify(player, "No commands found matching '$search'")
return@define
}
val accessibleCommands = allMatchingCommands
.filter { it.privilege.ordinal <= playerRights }
.sortedBy { it.name }
val inaccessibleCount = allMatchingCommands.count { it.privilege.ordinal > playerRights }
if (chatMode) {
for (command in accessibleCommands) {
val cmdargs = if (command.usage.isNotEmpty()) {
val parts = command.usage.split(" ", limit = 2)
if (parts.size > 1) parts[1] else ""
} else {
""
}
val formattedMessage = if (cmdargs.isNotEmpty()) {
"CMD: ${command.name} ARGS: $cmdargs DESC: ${command.description}"
} else {
"CMD: ${command.name} DESC: ${command.description}"
}
val chunks = chunkText(formattedMessage, 70)
chunks.forEach { notify(player, it) }
}
if (accessibleCommands.isEmpty()) {
notify(player, "Found $inaccessibleCount command(s) matching '$search' but you don't have permission to use any of them")
} else {
val summary = "Found ${accessibleCommands.size} accessible command(s) for '$search'"
if (inaccessibleCount > 0) {
notify(player, summary)
notify(player, "($inaccessibleCount additional command(s) require higher privileges)")
} else {
notify(player, summary)
}
}
return@define
}
var lineId = setupScrollInterface(player, "Command Search: '$search'")
if (accessibleCommands.isEmpty()) {
player.packetDispatch.sendString("No accessible commands found.", Components.QUESTJOURNAL_SCROLL_275, lineId++)
}
for (command in accessibleCommands) {
lineId = displayCommandInScroll(player, command, playerRights, lineId)
if (lineId > 306) {
player.packetDispatch.sendString(
"Results truncated. Use ::commandsearch $search --chat",
Components.QUESTJOURNAL_SCROLL_275,
lineId
)
break
}
}
if (inaccessibleCount > 0 && lineId <= 306) {
player.packetDispatch.sendString(
"$inaccessibleCount more command(s) need higher privileges.",
Components.QUESTJOURNAL_SCROLL_275,
lineId
)
}
player.interfaceManager.open(Component(Components.QUESTJOURNAL_SCROLL_275))
}
@ -640,6 +700,63 @@ class MiscCommandSet : CommandSet(Privilege.ADMIN){
}
}
fun setupScrollInterface(player: Player, title: String): Int {
player.interfaceManager.close()
for (i in 0..310) {
player.packetDispatch.sendString("", Components.QUESTJOURNAL_SCROLL_275, i)
}
player.packetDispatch.sendString(title, Components.QUESTJOURNAL_SCROLL_275, 2)
return 11
}
fun displayCommandInScroll(player: Player, command: Command, playerRights: Int, lineId: Int): Int {
val privilegeLevel = command.privilege.ordinal
if (privilegeLevel > playerRights) return lineId
val titleIcon = privilegeLevel - 1
var title = command.name
if (privilegeLevel > 0) {
title = "(<img=$titleIcon>) $title"
}
var currentLineId = lineId
player.packetDispatch.sendString(title, Components.QUESTJOURNAL_SCROLL_275, currentLineId++)
if (command.usage.isNotEmpty()) {
val usageText = "Usage: ${command.usage}"
val usageChunks = chunkText(usageText, 70)
for (chunk in usageChunks) {
player.packetDispatch.sendString(chunk, Components.QUESTJOURNAL_SCROLL_275, currentLineId++)
}
}
if (command.description.isNotEmpty()) {
val descChunks = chunkText(command.description, 70)
for (chunk in descChunks) {
player.packetDispatch.sendString(chunk, Components.QUESTJOURNAL_SCROLL_275, currentLineId++)
}
}
player.packetDispatch.sendString("<str>-------------------------------</str>", Components.QUESTJOURNAL_SCROLL_275, currentLineId++)
return currentLineId
}
fun chunkText(text: String, maxLength: Int = 70): List<String> {
if (text.length <= maxLength) return listOf(text)
val chunks = mutableListOf<String>()
var remaining = text
while (remaining.length > maxLength) {
var breakPoint = maxLength
for (i in maxLength downTo 1) {
if (remaining[i - 1] == ' ') {
breakPoint = i
break
}
}
chunks.add(remaining.take(breakPoint).trim())
remaining = remaining.substring(breakPoint).trim()
}
if (remaining.isNotEmpty()) {
chunks.add(remaining)
}
return chunks
}
fun setPlaqueReadStatus(player: Player, status: Boolean){
// For some reason the loop has to be this way to have read write access
for (i in 0 until player.savedData.globalData.readPlaques.size){

View file

@ -20,14 +20,6 @@ class Poison : PersistTimer (30, "poison", flags = arrayOf(TimerFlag.ClearOnDeat
lateinit var damageSource: Entity
var severity = 0
set (value) {
if (value != field - 1 && value % 10 == 8) {//This was Arios's incorrect attempt at replicating severity, convert it to correct values.
(damageSource as? Player)?.debug ("[PoisonTimer] Warning: Converting suspect Arios severity into true severity. If numbers look wrong, this could be why.")
field = (value / 10) * 5
(damageSource as? Player)?.debug ("[PoisonTimer] Warning: New Severity: $field.")
} else field = value
}
override fun save (root: JSONObject, entity: Entity) {
root["source-uid"] = (damageSource as? Player)?.details?.uid ?: -1
root["severity"] = severity.toString()

View file

@ -31,11 +31,7 @@ class PoisonImmunity : PersistTimer (1, "poison:immunity", isSoft = true, flags
override fun run (entity: Entity) : Boolean {
ticksRemaining--
if (entity is Player && ticksRemaining == secondsToTicks(30)) {
sendMessage(entity, colorize("%RYou have 30 seconds remaining on your poison immunity."))
playAudio(entity, Sounds.CLOCK_TICK_1_3120, 0, 3)
}
else if (entity is Player && ticksRemaining == 0) {
if (entity is Player && ticksRemaining == 0) {
sendMessage(entity, colorize("%RYour poison immunity has expired."))
playAudio(entity, Sounds.DRAGON_POTION_FINISHED_2607)
}

View file

@ -19,6 +19,11 @@ class Skulled : PersistTimer (1, "skulled", flags = arrayOf(TimerFlag.ClearOnDea
return false
}
override fun onRemoval (entity: Entity) {
if (entity !is Player) return
entity.skullManager.reset()
}
override fun getTimer (vararg args: Any) : RSTimer {
val t = Skulled()
t.runInterval = args.getOrNull(0) as? Int ?: 500

View file

@ -7,6 +7,9 @@ import core.api.*
import core.game.system.timer.impl.AntiMacro
import core.game.world.map.Location
import core.game.world.map.zone.impl.WildernessZone
import content.region.wilderness.handlers.KingBlackDragonArea
import core.game.world.map.zone.MapZone
import core.game.world.map.zone.ZoneBuilder
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
import org.rs09.consts.Items
@ -132,6 +135,28 @@ class RandomEventTests {
}
}
@Test fun randomEventShouldNotSpawnInKingBlackDragonLair() {
TestUtils.getMockPlayer("antimacronospawninkbdlair").use { p ->
val timer = getTimer<AntiMacro>(p) ?: Assertions.fail("AntiMacro timer was null!")
TestUtils.advanceTicks(5, false)
// Manually configure KBD lair zone like ClassScanner does for MapArea instances
val kbdArea = KingBlackDragonArea()
val zone = object : MapZone(kbdArea.javaClass.simpleName + "MapArea", true, *kbdArea.getRestrictions()) {}
for(border in kbdArea.defineAreaBorders()) zone.register(border)
ZoneBuilder.configure(zone)
val kbdLocation = Location.create(2273, 4698, 0) // KBD spawn location
p.location = kbdLocation
Assertions.assertEquals(kbdLocation, p.location)
timer.nextExecution = getWorldTicks() + 5
TestUtils.advanceTicks(10, false)
Assertions.assertNull(AntiMacro.getEventNpc(p), "Random event should not spawn in KBD lair but one was found!")
}
}
//FIXME
//@Test fun randomEventShouldNotSpawnIfOneAlreadyActive() {
// TestUtils.getMockPlayer("antimacronospawnifalreadyhas").use { p ->

93
build
View file

@ -2,139 +2,90 @@
SCRIPT_DIR=$(cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P)
BUILD_MS=0
CLEAN=0
BUILD_GS=0
CLEAN_MS=0
CLEAN_GS=0
SKIPTEST=""
GS_SRC=$SCRIPT_DIR/Server
MS_SRC=$SCRIPT_DIR/Management-Server
CLEANOPT=""
_JAR_DIR="$SCRIPT_DIR/builddir"
help()
{
echo "Usage: $0 [-h] <-m | -g> [-c <m|g>] [-o <path>]";
echo "Usage: $0 [-h] [-q] <-g|-c> [-o <path>]";
echo " -h: Display this message.";
echo " -m: Build the management server.";
echo " -g: Build the game server.";
echo " -c: Clean: m: management, g: gameserver. "
echo " Can specify both. Need at least one if present.";
echo " -o: Specify jar-file directory."
echo " -c: Clean previous build.";
echo " -o: Specify jar-file directory.";
echo " -q: Quick build - will skip tests.";
}
error()
{
echo $1;
exit -1;
}
clean_ms()
{
cd $MS_SRC
if [[ "$CLEANOPT" == *"m"* ]]; then
echo "Cleaning the management server."
sh mvnw clean || error "Failed to clean the MS."
fi
echo "$1";
exit 1;
}
clean_gs()
{
cd $GS_SRC;
if [[ "$CLEANOPT" == *"g"* ]]; then
cd $GS_SRC || error "Could not change dir to game server directory."
echo "Cleaning the game server."
sh mvnw clean || error "Failed to clean the game server. Giving up."
fi
}
build_ms()
{
cd $MS_SRC
sh mvnw package $SKIPTEST || \
error "Failed to build the management server. Giving up";
sh mvnw clean || error "Failed to clean the game server. Giving up."
}
build_gs()
{
cd $GS_SRC;
cd "$GS_SRC" || error "ERROR: Could not chdir to server src. Abort."
sh mvnw package $SKIPTEST || \
error "Failed to build the game server. Giving up."
}
while getopts "hqmgc:o:d" arg; do
while getopts "hqgc:o:d" arg; do
case $arg in
h)
help
exit 0
;;
m)
BUILD_MS=1
;;
g)
BUILD_GS=1
;;
c)
CLEANOPT=${OPTARG}
CLEAN=1
;;
o)
_JAR_DIR=${OPTARG}
;;
d)
echo "BUILD_MS=$BUILD_MS"
echo "BUILD_GS=$BUILD_GS"
echo "CLEANOPT=$CLEANOPT"
echo "_JAR_DIR=$_JAR_DIR"
;;
q)
SKIPTEST="-DskipTests"
;;
*)
error "Argument -$arg is not a known or valid argument."
;;
esac
done
if [[ $CLEANOPT != "m" ]] \
&& [[ $CLEANOPT != "g" ]] \
&& [[ $CLEANOPT != "mg" ]] \
&& [[ $CLEANOPT != "" ]];
then
error "Invalid cleaning option '$CLEANOPT'. Valid options are 'm', 'g', 'mg' or none."
if [ $BUILD_GS -eq 0 ] && [ $CLEAN -eq 0 ]; then
error "Need to either build or clean at least. See -h for details."
fi
if [ $BUILD_MS -eq 0 ] && [ $BUILD_GS -eq 0 ] && [[ $CLEANOPT == "" ]]; then
error "Need to build or clean at least one of the modules. See -h for details."
fi
# Inside func is cd so mgmt prob fails if no condition
(( CLEAN )) && clean_gs
# Conditionals inside the functions.
clean_gs
clean_ms
# -----------
if [ -d $_JAR_DIR ]; then
rm -r $_JAR_DIR
if [ -d "$_JAR_DIR" ]; then
rm -r "$_JAR_DIR"
fi
if [ $BUILD_MS -ne 1 ] && [ $BUILD_GS -ne 1 ]; then
echo "No build options specified. Stop."
exit 0
fi
mkdir -p $_JAR_DIR || error "Failed to create build directory.";
if [ $BUILD_MS -eq 1 ]; then
build_ms
# Will never execute if build_ms fails because it quits upon failure.
mv -v $MS_SRC/target/*-with-dependencies.jar $_JAR_DIR/ms.jar
fi
mkdir -p "$_JAR_DIR" || error "Failed to create build directory.";
if [ $BUILD_GS -eq 1 ]; then
build_gs
# Will never execute if build_gs fails because it quits upon failure.
mv -v $GS_SRC/target/*-with-dependencies.jar $_JAR_DIR/server.jar
mv -v "$GS_SRC"/target/*-with-dependencies.jar "$_JAR_DIR"/server.jar
fi

View file

@ -1,29 +1,33 @@
version: '3.3'
services:
app:
server:
build: .
container_name: "2009scape_app"
depends_on:
- database
restart: unless-stopped
volumes:
- "2009scape_app:/app"
ports:
- "43595:43595"
database:
image: mysql:5.7
container_name: "2009scape_db"
- db
restart: always
ports:
- "3306:3306"
volumes:
- "2009scape_db:/var/lib/mysql"
- "bcache:/app/Server/target"
- "mcache:/root/.m2"
- "./Server/data:/app/Server/data"
- "./config:/app/Server/worldprops"
ports:
- "43594-43600:43594-43600"
db:
# current LTS (Long-Term Support) version
image: mariadb:11.4-noble
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
start_period: 30s
interval: 60s
timeout: 10s
retries: 3
restart: always
volumes:
- "./db:/var/lib/mysql"
- "./Server/db_exports/global.sql:/docker-entrypoint-initdb.d/global.sql"
environment:
MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
MYSQL_ROOT_PASSWORD: ""
MYSQL_ROOT_USER: "root"
env_file:
- mysql.env
volumes:
2009scape_app:
2009scape_db:
bcache:
mcache:

20
mysql.env.example Normal file
View file

@ -0,0 +1,20 @@
# Prefer no and generating a strong password for the root (+ special) user
MYSQL_ALLOW_EMPTY_PASSWORD="no"
# You can change the db name also for obscurity.
# Has to be changed in the default.conf and in the global.sql init file then also.
MYSQL_DATABASE="global"
# Beware: if not using root user, the database 'global' requires granting permissions for that user
# Root user is created automatically so dont provide it here.
#MYSQL_USER="dbuser"
#MYSQL_PASSWORD="CHANGEMEIFNOTUSINGROOTANDINGLOBALCONF"
# Comment this out if you are using random root pw (below).
MYSQL_ROOT_PASSWORD="ALWAYSCHANGEMEHEREANDINGLOBALCONFIFUSINGROOT"
# Or you can use a special non-root db user and generate a random pw for the root user instead.
# To improve security
# However, either initial root user access
# or editing Server/db_exports/global.sql to add grants for 'global' to the special user above.
MYSQL_RANDOM_ROOT_PASSWORD="no"

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