mirror of
https://gitlab.com/2009scape/2009scape.git
synced 2026-08-20 18:05:13 -06:00
Merge branch 2009scape:master into master
This commit is contained in:
commit
aff4b7bfae
113 changed files with 2116 additions and 1334 deletions
35
README.md
35
README.md
|
|
@ -29,6 +29,7 @@
|
|||
* [Prerequisites](#prerequisites)
|
||||
* [Project Setup](#project-setup)
|
||||
* [Running the project](#running-the-project)
|
||||
* [Browser WebSocket Transport](#browser-websocket-transport)
|
||||
* [License](#license)
|
||||
* [Contact](#contact)
|
||||
|
||||
|
|
@ -125,6 +126,40 @@ Start the game server with the included run script. Use `./run -h` for more info
|
|||
|
||||
Start the game server with `run-server.bat`
|
||||
|
||||
#### Browser WebSocket Transport
|
||||
|
||||
Enable the listener in `Server/worldprops/default.conf`:
|
||||
|
||||
```properties
|
||||
websocket_enabled = true
|
||||
websocket_port = 0
|
||||
```
|
||||
|
||||
When `websocket_port = 0`, the listener uses `53594 + world_id`. For world `1`, that is `53595`.
|
||||
|
||||
Both plain WebSocket (`ws://`) and secure WebSocket (`wss://`) are supported. Use `ws://` for local HTTP testing. PWA requires HTTPS/WSS.
|
||||
|
||||
Enable WSS with a Java keystore:
|
||||
|
||||
```properties
|
||||
websocket_tls_enabled = true
|
||||
websocket_tls_keystore_path = "certs/dev-wss.p12"
|
||||
websocket_tls_keystore_password = "<keystore-password>"
|
||||
```
|
||||
|
||||
The keystore password is optional. Leave `websocket_tls_keystore_password` blank when using a PKCS12 file exported with an empty password:
|
||||
|
||||
```bash
|
||||
openssl pkcs12 -export \
|
||||
-in fullchain.pem \
|
||||
-inkey privkey.pem \
|
||||
-out certs/dev-wss.p12 \
|
||||
-name websocket \
|
||||
-passout pass:
|
||||
```
|
||||
|
||||
For local WSS development, create a certificate for your hostname or LAN IP that the browser will use, then point the server at a PKCS12 keystore. For production, use a normal certificate from certbot. Plain WS does not require a certificate.
|
||||
|
||||
#### Docker
|
||||
|
||||
Make sure [Docker Engine](https://docs.docker.com/engine/install/) & [Docker Compose](https://docs.docker.com/compose/install/) plugin are installed first:
|
||||
|
|
|
|||
|
|
@ -8353,6 +8353,20 @@
|
|||
"description": "",
|
||||
"main": []
|
||||
},
|
||||
{
|
||||
"default": [
|
||||
{
|
||||
"minAmount": "1",
|
||||
"weight": "100.0",
|
||||
"id": "526",
|
||||
"maxAmount": "1"
|
||||
}
|
||||
],
|
||||
"charm": [],
|
||||
"ids": "1329",
|
||||
"description": "",
|
||||
"main": []
|
||||
},
|
||||
{
|
||||
"default": [
|
||||
{
|
||||
|
|
@ -19684,7 +19698,14 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"default": [],
|
||||
"default": [
|
||||
{
|
||||
"minAmount": "1",
|
||||
"weight": "100.0",
|
||||
"id": "526",
|
||||
"maxAmount": "1"
|
||||
}
|
||||
],
|
||||
"charm": [],
|
||||
"ids": "1307",
|
||||
"description": "",
|
||||
|
|
@ -29810,10 +29831,10 @@
|
|||
"maxAmount": "1"
|
||||
},
|
||||
{
|
||||
"minAmount": "1",
|
||||
"minAmount": "2",
|
||||
"weight": "100.0",
|
||||
"id": "12161",
|
||||
"maxAmount": "1"
|
||||
"maxAmount": "2"
|
||||
},
|
||||
{
|
||||
"minAmount": "1",
|
||||
|
|
@ -41175,7 +41196,7 @@
|
|||
{
|
||||
"minAmount": "1",
|
||||
"weight": "5.0",
|
||||
"id": "1",
|
||||
"id": "12070",
|
||||
"maxAmount": "1"
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -415,6 +415,10 @@
|
|||
"item_id": "1755",
|
||||
"loc_data": "{1,2935,3286,0,90}-"
|
||||
},
|
||||
{
|
||||
"item_id": "1773",
|
||||
"loc_data": "{1,2563,3261,0,100}-"
|
||||
},
|
||||
{
|
||||
"item_id": "1785",
|
||||
"loc_data": "{1,2822,3355,0,150}-"
|
||||
|
|
|
|||
|
|
@ -539,6 +539,12 @@
|
|||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "375",
|
||||
"interfaceType": "3",
|
||||
"walkable": "false",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "377",
|
||||
"interfaceType": "8",
|
||||
|
|
|
|||
|
|
@ -35942,6 +35942,7 @@
|
|||
"id": "4158",
|
||||
"name": "Leaf-bladed spear",
|
||||
"examine": "A spear with a leaf-shaped point.",
|
||||
"alchemizable": "true",
|
||||
"archery_ticket_price": "0",
|
||||
"attack_anims": "2080,2081,2082,2080",
|
||||
"attack_speed": "5",
|
||||
|
|
@ -77818,6 +77819,16 @@
|
|||
"durability": null,
|
||||
"weight": "1"
|
||||
},
|
||||
{
|
||||
"id": "9721",
|
||||
"name": "Scroll",
|
||||
"examine": "A scroll with some writing on it."
|
||||
},
|
||||
{
|
||||
"id": "9722",
|
||||
"name": "Key",
|
||||
"examine": "Quite a small key."
|
||||
},
|
||||
{
|
||||
"id": "9723",
|
||||
"name": "Pipe",
|
||||
|
|
@ -99252,7 +99263,7 @@
|
|||
{
|
||||
"id": "12184",
|
||||
"name": "Gecko",
|
||||
"examine": "(Baby) It's so adorably tiny! (Adult) How cute!",
|
||||
"examine": "How cute!",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
|
|
@ -100617,42 +100628,42 @@
|
|||
{
|
||||
"id": "12486",
|
||||
"name": "Baby raccoon",
|
||||
"examine": "(Baby) A stripy little baby raccoon.(Adult) He can run with us.",
|
||||
"examine": "A stripy little baby raccoon.",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12487",
|
||||
"name": "Raccoon",
|
||||
"examine": "(Baby) A stripy little baby raccoon.(Adult) He can run with us.",
|
||||
"examine": "He can run with us.",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12488",
|
||||
"name": "Baby gecko",
|
||||
"examine": "(Baby) It's so adorably tiny! (Adult) How cute!",
|
||||
"examine": "It's so adorably tiny!",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12489",
|
||||
"name": "Gecko",
|
||||
"examine": "(Baby) It's so adorably tiny! (Adult) How cute!",
|
||||
"examine": "How cute!",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12490",
|
||||
"name": "Baby squirrel",
|
||||
"examine": "Adult: An experienced nut-thief.Baby: A tiny nut-thief.",
|
||||
"examine": "A tiny nut-thief.",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12491",
|
||||
"name": "Squirrel",
|
||||
"examine": "Adult: An experienced nut-thief.Baby: A tiny nut-thief.",
|
||||
"examine": "An experienced nut-thief.",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
|
|
@ -100689,10 +100700,15 @@
|
|||
{
|
||||
"id": "12496",
|
||||
"name": "Baby monkey",
|
||||
"examine": "(Baby) It's a tiny, cheeky monkey. (Adult) Hide the bananas!",
|
||||
"examine": "It's a tiny, cheeky monkey.",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12497",
|
||||
"name": "Monkey",
|
||||
"examine": "Hide the bananas!"
|
||||
},
|
||||
{
|
||||
"id": "12498",
|
||||
"name": "Vulture chick",
|
||||
|
|
@ -102382,66 +102398,111 @@
|
|||
{
|
||||
"id": "12682",
|
||||
"name": "Baby monkey",
|
||||
"examine": "(Baby) It's a tiny, cheeky monkey. (Adult) Hide the bananas!",
|
||||
"examine": "It's a tiny, cheeky monkey.",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12683",
|
||||
"name": "Monkey",
|
||||
"examine": "Hide the bananas!"
|
||||
},
|
||||
{
|
||||
"id": "12684",
|
||||
"name": "Baby monkey",
|
||||
"examine": "(Baby) It's a tiny, cheeky monkey. (Adult) Hide the bananas!",
|
||||
"examine": "It's a tiny, cheeky monkey.",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12685",
|
||||
"name": "Monkey",
|
||||
"examine": "Hide the bananas!"
|
||||
},
|
||||
{
|
||||
"id": "12686",
|
||||
"name": "Baby monkey",
|
||||
"examine": "(Baby) It's a tiny, cheeky monkey. (Adult) Hide the bananas!",
|
||||
"examine": "It's a tiny, cheeky monkey.",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12687",
|
||||
"name": "Monkey",
|
||||
"examine": "Hide the bananas!"
|
||||
},
|
||||
{
|
||||
"id": "12688",
|
||||
"name": "Baby monkey",
|
||||
"examine": "(Baby) It's a tiny, cheeky monkey. (Adult) Hide the bananas!",
|
||||
"examine": "It's a tiny, cheeky monkey.",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12689",
|
||||
"name": "Monkey",
|
||||
"examine": "Hide the bananas!"
|
||||
},
|
||||
{
|
||||
"id": "12690",
|
||||
"name": "Baby monkey",
|
||||
"examine": "(Baby) It's a tiny, cheeky monkey. (Adult) Hide the bananas!",
|
||||
"examine": "It's a tiny, cheeky monkey.",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12691",
|
||||
"name": "Monkey",
|
||||
"examine": "Hide the bananas!"
|
||||
},
|
||||
{
|
||||
"id": "12692",
|
||||
"name": "Baby monkey",
|
||||
"examine": "(Baby) It's a tiny, cheeky monkey. (Adult) Hide the bananas!",
|
||||
"examine": "It's a tiny, cheeky monkey.",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12693",
|
||||
"name": "Monkey",
|
||||
"examine": "Hide the bananas!"
|
||||
},
|
||||
{
|
||||
"id": "12694",
|
||||
"name": "Baby monkey",
|
||||
"examine": "(Baby) It's a tiny, cheeky monkey. (Adult) Hide the bananas!",
|
||||
"examine": "It's a tiny, cheeky monkey.",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12695",
|
||||
"name": "Monkey",
|
||||
"examine": "Hide the bananas!"
|
||||
},
|
||||
{
|
||||
"id": "12696",
|
||||
"name": "Baby monkey",
|
||||
"examine": "(Baby) It's a tiny, cheeky monkey. (Adult) Hide the bananas!",
|
||||
"examine": "It's a tiny, cheeky monkey.",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12697",
|
||||
"name": "Monkey",
|
||||
"examine": "Hide the bananas!"
|
||||
},
|
||||
{
|
||||
"id": "12698",
|
||||
"name": "Baby monkey",
|
||||
"examine": "(Baby) It's a tiny, cheeky monkey. (Adult) Hide the bananas!",
|
||||
"examine": "It's a tiny, cheeky monkey.",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12699",
|
||||
"name": "Monkey",
|
||||
"examine": "Hide the bananas!"
|
||||
},
|
||||
{
|
||||
"id": "12700",
|
||||
"name": "Terrier puppy",
|
||||
|
|
@ -102707,84 +102768,84 @@
|
|||
{
|
||||
"id": "12734",
|
||||
"name": "Baby raccoon",
|
||||
"examine": "(Baby) A stripy little baby raccoon.(Adult) He can run with us.",
|
||||
"examine": "A stripy little baby raccoon.",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12735",
|
||||
"name": "Raccoon",
|
||||
"examine": "(Baby) A stripy little baby raccoon.(Adult) He can run with us.",
|
||||
"examine": "He can run with us.",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12736",
|
||||
"name": "Baby raccoon",
|
||||
"examine": "(Baby) A stripy little baby raccoon.(Adult) He can run with us.",
|
||||
"examine": "A stripy little baby raccoon.",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12737",
|
||||
"name": "Raccoon",
|
||||
"examine": "(Baby) A stripy little baby raccoon.(Adult) He can run with us.",
|
||||
"examine": "He can run with us.",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12738",
|
||||
"name": "Baby gecko",
|
||||
"examine": "(Baby) It's so adorably tiny! (Adult) How cute!",
|
||||
"examine": "It's so adorably tiny!",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12739",
|
||||
"name": "Baby gecko",
|
||||
"examine": "(Baby) It's so adorably tiny! (Adult) How cute!",
|
||||
"examine": "It's so adorably tiny!",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12740",
|
||||
"name": "Baby gecko",
|
||||
"examine": "(Baby) It's so adorably tiny! (Adult) How cute!",
|
||||
"examine": "It's so adorably tiny!",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12741",
|
||||
"name": "Baby gecko",
|
||||
"examine": "(Baby) It's so adorably tiny! (Adult) How cute!",
|
||||
"examine": "It's so adorably tiny!",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12742",
|
||||
"name": "Gecko",
|
||||
"examine": "(Baby) It's so adorably tiny! (Adult) How cute!",
|
||||
"examine": "How cute!",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12743",
|
||||
"name": "Gecko",
|
||||
"examine": "(Baby) It's so adorably tiny! (Adult) How cute!",
|
||||
"examine": "How cute!",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12744",
|
||||
"name": "Gecko",
|
||||
"examine": "(Baby) It's so adorably tiny! (Adult) How cute!",
|
||||
"examine": "How cute!",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12745",
|
||||
"name": "Gecko",
|
||||
"examine": "(Baby) It's so adorably tiny! (Adult) How cute!",
|
||||
"examine": "How cute!",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
|
|
@ -102855,56 +102916,56 @@
|
|||
{
|
||||
"id": "12754",
|
||||
"name": "Baby squirrel",
|
||||
"examine": "Adult: An experienced nut-thief.Baby: A tiny nut-thief.",
|
||||
"examine": "A tiny nut-thief.",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12755",
|
||||
"name": "Squirrel",
|
||||
"examine": "Adult: An experienced nut-thief.Baby: A tiny nut-thief.",
|
||||
"examine": "An experienced nut-thief.",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12756",
|
||||
"name": "Baby squirrel",
|
||||
"examine": "Adult: An experienced nut-thief.Baby: A tiny nut-thief.",
|
||||
"examine": "A tiny nut-thief.",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12757",
|
||||
"name": "Squirrel",
|
||||
"examine": "Adult: An experienced nut-thief.Baby: A tiny nut-thief.",
|
||||
"examine": "An experienced nut-thief.",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12758",
|
||||
"name": "Baby squirrel",
|
||||
"examine": "Adult: An experienced nut-thief.Baby: A tiny nut-thief.",
|
||||
"examine": "A tiny nut-thief.",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12759",
|
||||
"name": "Squirrel",
|
||||
"examine": "Adult: An experienced nut-thief.Baby: A tiny nut-thief.",
|
||||
"examine": "An experienced nut-thief.",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12760",
|
||||
"name": "Baby squirrel",
|
||||
"examine": "Adult: An experienced nut-thief.Baby: A tiny nut-thief.",
|
||||
"examine": "A tiny nut-thief.",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
{
|
||||
"id": "12761",
|
||||
"name": "Squirrel",
|
||||
"examine": "Adult: An experienced nut-thief.Baby: A tiny nut-thief.",
|
||||
"examine": "An experienced nut-thief.",
|
||||
"archery_ticket_price": "0",
|
||||
"durability": null
|
||||
},
|
||||
|
|
|
|||
|
|
@ -25592,7 +25592,7 @@
|
|||
"death_animation": "6003",
|
||||
"defence_animation": "6008",
|
||||
"defence_level": "5",
|
||||
"lifepoints": "7",
|
||||
"lifepoints": "10",
|
||||
"magic_animation": "0",
|
||||
"melee_animation": "6007",
|
||||
"range_animation": "0",
|
||||
|
|
@ -25610,7 +25610,7 @@
|
|||
"death_animation": "6003",
|
||||
"defence_animation": "6008",
|
||||
"defence_level": "5",
|
||||
"lifepoints": "7",
|
||||
"lifepoints": "10",
|
||||
"magic_animation": "0",
|
||||
"melee_animation": "6007",
|
||||
"range_animation": "0",
|
||||
|
|
@ -25628,7 +25628,7 @@
|
|||
"death_animation": "6003",
|
||||
"defence_animation": "6008",
|
||||
"defence_level": "5",
|
||||
"lifepoints": "7",
|
||||
"lifepoints": "10",
|
||||
"magic_animation": "0",
|
||||
"melee_animation": "6007",
|
||||
"range_animation": "0",
|
||||
|
|
@ -25646,7 +25646,7 @@
|
|||
"death_animation": "6003",
|
||||
"defence_animation": "6008",
|
||||
"defence_level": "5",
|
||||
"lifepoints": "7",
|
||||
"lifepoints": "10",
|
||||
"magic_animation": "0",
|
||||
"melee_animation": "6007",
|
||||
"range_animation": "0",
|
||||
|
|
@ -25697,61 +25697,61 @@
|
|||
"id": "2075",
|
||||
"name": "Cave goblin miner",
|
||||
"examine": "He's working hard!",
|
||||
"attack_level": "1",
|
||||
"attack_level": "5",
|
||||
"combat_audio": "469,472,471",
|
||||
"death_animation": "6003",
|
||||
"defence_animation": "6008",
|
||||
"defence_level": "1",
|
||||
"defence_level": "5",
|
||||
"lifepoints": "10",
|
||||
"melee_animation": "6007",
|
||||
"range_level": "1",
|
||||
"safespot": null,
|
||||
"strength_level": "1"
|
||||
"strength_level": "5"
|
||||
},
|
||||
{
|
||||
"id": "2076",
|
||||
"name": "Cave goblin miner",
|
||||
"examine": "He's working hard!",
|
||||
"attack_level": "1",
|
||||
"attack_level": "5",
|
||||
"combat_audio": "469,472,471",
|
||||
"death_animation": "6003",
|
||||
"defence_animation": "6008",
|
||||
"defence_level": "1",
|
||||
"defence_level": "5",
|
||||
"lifepoints": "10",
|
||||
"melee_animation": "6007",
|
||||
"range_level": "1",
|
||||
"safespot": null,
|
||||
"strength_level": "1"
|
||||
"strength_level": "5"
|
||||
},
|
||||
{
|
||||
"id": "2077",
|
||||
"name": "Cave goblin miner",
|
||||
"examine": "He's working hard!",
|
||||
"attack_level": "1",
|
||||
"attack_level": "5",
|
||||
"combat_audio": "469,472,471",
|
||||
"death_animation": "6003",
|
||||
"defence_animation": "6008",
|
||||
"defence_level": "1",
|
||||
"defence_level": "5",
|
||||
"lifepoints": "10",
|
||||
"melee_animation": "6007",
|
||||
"range_level": "1",
|
||||
"safespot": null,
|
||||
"strength_level": "1"
|
||||
"strength_level": "5"
|
||||
},
|
||||
{
|
||||
"id": "2078",
|
||||
"name": "Cave goblin miner",
|
||||
"examine": "He's working hard!",
|
||||
"attack_level": "1",
|
||||
"attack_level": "5",
|
||||
"combat_audio": "469,472,471",
|
||||
"death_animation": "6003",
|
||||
"defence_animation": "6008",
|
||||
"defence_level": "1",
|
||||
"defence_level": "5",
|
||||
"lifepoints": "10",
|
||||
"melee_animation": "6007",
|
||||
"range_level": "1",
|
||||
"safespot": null,
|
||||
"strength_level": "1"
|
||||
"strength_level": "5"
|
||||
},
|
||||
{
|
||||
"id": "2079",
|
||||
|
|
@ -38057,11 +38057,13 @@
|
|||
},
|
||||
{
|
||||
"id": "3284",
|
||||
"name": "Squirrel"
|
||||
"name": "Squirrel",
|
||||
"examine": "Bushy tail!"
|
||||
},
|
||||
{
|
||||
"id": "3285",
|
||||
"name": "Squirrel"
|
||||
"name": "Squirrel",
|
||||
"examine": "Bushy tail!"
|
||||
},
|
||||
{
|
||||
"id": "3286",
|
||||
|
|
@ -38081,7 +38083,8 @@
|
|||
},
|
||||
{
|
||||
"id": "3287",
|
||||
"name": "Raccoon"
|
||||
"name": "Raccoon",
|
||||
"examine": "A raccoon."
|
||||
},
|
||||
{
|
||||
"id": "3288",
|
||||
|
|
@ -77156,20 +77159,23 @@
|
|||
},
|
||||
{
|
||||
"id": "6913",
|
||||
"name": "Baby raccoon"
|
||||
"name": "Baby raccoon",
|
||||
"examine": "A stripy little baby raccoon."
|
||||
},
|
||||
{
|
||||
"id": "6914",
|
||||
"name": "Raccoon"
|
||||
"name": "Raccoon",
|
||||
"examine": "He can run with us."
|
||||
},
|
||||
{
|
||||
"id": "6915",
|
||||
"name": "Baby gecko"
|
||||
"name": "Baby gecko",
|
||||
"examine": "It's so adorably tiny!"
|
||||
},
|
||||
{
|
||||
"id": "6916",
|
||||
"name": "Gecko",
|
||||
"examine": ""
|
||||
"examine": "How cute!"
|
||||
},
|
||||
{
|
||||
"id": "6917",
|
||||
|
|
@ -77194,11 +77200,13 @@
|
|||
},
|
||||
{
|
||||
"id": "6919",
|
||||
"name": "Baby squirrel"
|
||||
"name": "Baby squirrel",
|
||||
"examine": "A tiny nut-thief."
|
||||
},
|
||||
{
|
||||
"id": "6920",
|
||||
"name": "Squirrel"
|
||||
"name": "Squirrel",
|
||||
"examine": "An experienced nut-thief."
|
||||
},
|
||||
{
|
||||
"id": "6921",
|
||||
|
|
@ -77299,6 +77307,7 @@
|
|||
{
|
||||
"id": "6942",
|
||||
"name": "Baby monkey",
|
||||
"examine": "It's a tiny, cheeky monkey.",
|
||||
"attack_level": "1",
|
||||
"combat_audio": "629,631,630",
|
||||
"defence_level": "1",
|
||||
|
|
@ -77310,6 +77319,7 @@
|
|||
{
|
||||
"id": "6943",
|
||||
"name": "Monkey",
|
||||
"examine": "Hide the bananas!",
|
||||
"attack_level": "1",
|
||||
"combat_audio": "629,631,630",
|
||||
"defence_level": "1",
|
||||
|
|
@ -77461,7 +77471,8 @@
|
|||
},
|
||||
{
|
||||
"id": "6970",
|
||||
"name": "Pikkupstix"
|
||||
"name": "Pikkupstix",
|
||||
"examine": "He's a very important druid."
|
||||
},
|
||||
{
|
||||
"id": "6971",
|
||||
|
|
@ -77805,6 +77816,16 @@
|
|||
},
|
||||
{
|
||||
"id": "6988",
|
||||
"name": "Pikkupstix",
|
||||
"examine": "He's a very important druid."
|
||||
},
|
||||
{
|
||||
"id": "6989",
|
||||
"name": "Pikkupstix",
|
||||
"examine": "He's a very important druid."
|
||||
},
|
||||
{
|
||||
"id": "6990",
|
||||
"name": "Giant wolpertinger"
|
||||
},
|
||||
{
|
||||
|
|
@ -79666,6 +79687,7 @@
|
|||
{
|
||||
"id": "7210",
|
||||
"name": "Baby monkey",
|
||||
"examine": "It's a tiny, cheeky monkey.",
|
||||
"attack_level": "1",
|
||||
"combat_audio": "629,631,630",
|
||||
"defence_level": "1",
|
||||
|
|
@ -79677,6 +79699,7 @@
|
|||
{
|
||||
"id": "7211",
|
||||
"name": "Monkey",
|
||||
"examine": "Hide the bananas!",
|
||||
"attack_level": "1",
|
||||
"combat_audio": "629,631,630",
|
||||
"defence_level": "1",
|
||||
|
|
@ -79688,6 +79711,7 @@
|
|||
{
|
||||
"id": "7212",
|
||||
"name": "Baby monkey",
|
||||
"examine": "It's a tiny, cheeky monkey.",
|
||||
"attack_level": "1",
|
||||
"combat_audio": "629,631,630",
|
||||
"defence_level": "1",
|
||||
|
|
@ -79699,6 +79723,7 @@
|
|||
{
|
||||
"id": "7213",
|
||||
"name": "Monkey",
|
||||
"examine": "Hide the bananas!",
|
||||
"attack_level": "1",
|
||||
"combat_audio": "629,631,630",
|
||||
"defence_level": "1",
|
||||
|
|
@ -79710,6 +79735,7 @@
|
|||
{
|
||||
"id": "7214",
|
||||
"name": "Baby monkey",
|
||||
"examine": "It's a tiny, cheeky monkey.",
|
||||
"attack_level": "1",
|
||||
"combat_audio": "629,631,630",
|
||||
"defence_level": "1",
|
||||
|
|
@ -79721,6 +79747,7 @@
|
|||
{
|
||||
"id": "7215",
|
||||
"name": "Monkey",
|
||||
"examine": "Hide the bananas!",
|
||||
"attack_level": "1",
|
||||
"combat_audio": "629,631,630",
|
||||
"defence_level": "1",
|
||||
|
|
@ -79732,6 +79759,7 @@
|
|||
{
|
||||
"id": "7216",
|
||||
"name": "Baby monkey",
|
||||
"examine": "It's a tiny, cheeky monkey.",
|
||||
"attack_level": "1",
|
||||
"combat_audio": "629,631,630",
|
||||
"defence_level": "1",
|
||||
|
|
@ -79743,6 +79771,7 @@
|
|||
{
|
||||
"id": "7217",
|
||||
"name": "Monkey",
|
||||
"examine": "Hide the bananas!",
|
||||
"attack_level": "1",
|
||||
"combat_audio": "629,631,630",
|
||||
"defence_level": "1",
|
||||
|
|
@ -79754,6 +79783,7 @@
|
|||
{
|
||||
"id": "7218",
|
||||
"name": "Baby monkey",
|
||||
"examine": "It's a tiny, cheeky monkey.",
|
||||
"attack_level": "1",
|
||||
"combat_audio": "629,631,630",
|
||||
"defence_level": "1",
|
||||
|
|
@ -79765,6 +79795,7 @@
|
|||
{
|
||||
"id": "7219",
|
||||
"name": "Monkey",
|
||||
"examine": "Hide the bananas!",
|
||||
"attack_level": "1",
|
||||
"combat_audio": "629,631,630",
|
||||
"defence_level": "1",
|
||||
|
|
@ -79776,6 +79807,7 @@
|
|||
{
|
||||
"id": "7220",
|
||||
"name": "Baby monkey",
|
||||
"examine": "It's a tiny, cheeky monkey.",
|
||||
"attack_level": "1",
|
||||
"combat_audio": "629,631,630",
|
||||
"defence_level": "1",
|
||||
|
|
@ -79787,6 +79819,7 @@
|
|||
{
|
||||
"id": "7221",
|
||||
"name": "Monkey",
|
||||
"examine": "Hide the bananas!",
|
||||
"attack_level": "1",
|
||||
"combat_audio": "629,631,630",
|
||||
"defence_level": "1",
|
||||
|
|
@ -79798,6 +79831,7 @@
|
|||
{
|
||||
"id": "7222",
|
||||
"name": "Baby monkey",
|
||||
"examine": "It's a tiny, cheeky monkey.",
|
||||
"attack_level": "1",
|
||||
"combat_audio": "629,631,630",
|
||||
"defence_level": "1",
|
||||
|
|
@ -79809,6 +79843,7 @@
|
|||
{
|
||||
"id": "7223",
|
||||
"name": "Monkey",
|
||||
"examine": "Hide the bananas!",
|
||||
"attack_level": "1",
|
||||
"combat_audio": "629,631,630",
|
||||
"defence_level": "1",
|
||||
|
|
@ -79820,6 +79855,7 @@
|
|||
{
|
||||
"id": "7224",
|
||||
"name": "Baby monkey",
|
||||
"examine": "It's a tiny, cheeky monkey.",
|
||||
"attack_level": "1",
|
||||
"combat_audio": "629,631,630",
|
||||
"defence_level": "1",
|
||||
|
|
@ -79831,6 +79867,7 @@
|
|||
{
|
||||
"id": "7225",
|
||||
"name": "Monkey",
|
||||
"examine": "Hide the bananas!",
|
||||
"attack_level": "1",
|
||||
"combat_audio": "629,631,630",
|
||||
"defence_level": "1",
|
||||
|
|
@ -79842,6 +79879,7 @@
|
|||
{
|
||||
"id": "7226",
|
||||
"name": "Baby monkey",
|
||||
"examine": "It's a tiny, cheeky monkey.",
|
||||
"attack_level": "1",
|
||||
"combat_audio": "629,631,630",
|
||||
"defence_level": "1",
|
||||
|
|
@ -79853,6 +79891,7 @@
|
|||
{
|
||||
"id": "7227",
|
||||
"name": "Monkey",
|
||||
"examine": "Hide the bananas!",
|
||||
"attack_level": "1",
|
||||
"combat_audio": "629,631,630",
|
||||
"defence_level": "1",
|
||||
|
|
@ -80161,19 +80200,23 @@
|
|||
},
|
||||
{
|
||||
"id": "7271",
|
||||
"name": "Baby raccoon"
|
||||
"name": "Baby raccoon",
|
||||
"examine": "A stripy little baby raccoon."
|
||||
},
|
||||
{
|
||||
"id": "7272",
|
||||
"name": "Raccoon"
|
||||
"name": "Raccoon",
|
||||
"examine": "He can run with us."
|
||||
},
|
||||
{
|
||||
"id": "7273",
|
||||
"name": "Baby raccoon"
|
||||
"name": "Baby raccoon",
|
||||
"examine": "A stripy little baby raccoon."
|
||||
},
|
||||
{
|
||||
"id": "7274",
|
||||
"name": "Raccoon"
|
||||
"name": "Raccoon",
|
||||
"examine": "He can run with us."
|
||||
},
|
||||
{
|
||||
"id": "7275",
|
||||
|
|
@ -80193,40 +80236,48 @@
|
|||
},
|
||||
{
|
||||
"id": "7276",
|
||||
"name": "Baby raccoon"
|
||||
"name": "Baby raccoon",
|
||||
"examine": "A stripy little baby raccoon."
|
||||
},
|
||||
{
|
||||
"id": "7277",
|
||||
"name": "Baby gecko"
|
||||
"name": "Baby gecko",
|
||||
"examine": "It's so adorably tiny!"
|
||||
},
|
||||
{
|
||||
"id": "7278",
|
||||
"name": "Baby gecko"
|
||||
"name": "Baby gecko",
|
||||
"examine": "It's so adorably tiny!"
|
||||
},
|
||||
{
|
||||
"id": "7279",
|
||||
"name": "Baby gecko"
|
||||
"name": "Baby gecko",
|
||||
"examine": "It's so adorably tiny!"
|
||||
},
|
||||
{
|
||||
"id": "7280",
|
||||
"name": "Baby gecko"
|
||||
"name": "Baby gecko",
|
||||
"examine": "It's so adorably tiny!"
|
||||
},
|
||||
{
|
||||
"id": "7281",
|
||||
"name": "Gecko",
|
||||
"examine": ""
|
||||
"examine": "How cute!"
|
||||
},
|
||||
{
|
||||
"id": "7282",
|
||||
"name": "Gecko"
|
||||
"name": "Gecko",
|
||||
"examine": "How cute!"
|
||||
},
|
||||
{
|
||||
"id": "7283",
|
||||
"name": "Gecko"
|
||||
"name": "Gecko",
|
||||
"examine": "How cute!"
|
||||
},
|
||||
{
|
||||
"id": "7284",
|
||||
"name": "Gecko"
|
||||
"name": "Gecko",
|
||||
"examine": "How cute!"
|
||||
},
|
||||
{
|
||||
"id": "7285",
|
||||
|
|
@ -80252,7 +80303,7 @@
|
|||
{
|
||||
"id": "7287",
|
||||
"name": "Baby gecko",
|
||||
"examine": ""
|
||||
"examine": "It's so adorably tiny!"
|
||||
},
|
||||
{
|
||||
"id": "7288",
|
||||
|
|
@ -80261,7 +80312,8 @@
|
|||
},
|
||||
{
|
||||
"id": "7289",
|
||||
"name": "Gecko"
|
||||
"name": "Gecko",
|
||||
"examine": "How cute!"
|
||||
},
|
||||
{
|
||||
"id": "7290",
|
||||
|
|
@ -80270,7 +80322,8 @@
|
|||
},
|
||||
{
|
||||
"id": "7291",
|
||||
"name": "Gecko"
|
||||
"name": "Gecko",
|
||||
"examine": "How cute!"
|
||||
},
|
||||
{
|
||||
"id": "7292",
|
||||
|
|
@ -80311,51 +80364,63 @@
|
|||
},
|
||||
{
|
||||
"id": "7301",
|
||||
"name": "Baby squirrel"
|
||||
"name": "Baby squirrel",
|
||||
"examine": "A tiny nut-thief."
|
||||
},
|
||||
{
|
||||
"id": "7302",
|
||||
"name": "Squirrel"
|
||||
"name": "Squirrel",
|
||||
"examine": "An experienced nut-thief."
|
||||
},
|
||||
{
|
||||
"id": "7303",
|
||||
"name": "Baby squirrel"
|
||||
"name": "Baby squirrel",
|
||||
"examine": "A tiny nut-thief."
|
||||
},
|
||||
{
|
||||
"id": "7304",
|
||||
"name": "Squirrel"
|
||||
"name": "Squirrel",
|
||||
"examine": "An experienced nut-thief."
|
||||
},
|
||||
{
|
||||
"id": "7305",
|
||||
"name": "Baby squirrel"
|
||||
"name": "Baby squirrel",
|
||||
"examine": "A tiny nut-thief."
|
||||
},
|
||||
{
|
||||
"id": "7306",
|
||||
"name": "Squirrel"
|
||||
"name": "Squirrel",
|
||||
"examine": "An experienced nut-thief."
|
||||
},
|
||||
{
|
||||
"id": "7307",
|
||||
"name": "Baby squirrel"
|
||||
"name": "Baby squirrel",
|
||||
"examine": "A tiny nut-thief."
|
||||
},
|
||||
{
|
||||
"id": "7308",
|
||||
"name": "Squirrel"
|
||||
"name": "Squirrel",
|
||||
"examine": "An experienced nut-thief."
|
||||
},
|
||||
{
|
||||
"id": "7309",
|
||||
"name": "Baby squirrel"
|
||||
"name": "Baby squirrel",
|
||||
"examine": "A tiny nut-thief."
|
||||
},
|
||||
{
|
||||
"id": "7310",
|
||||
"name": "Baby squirrel"
|
||||
"name": "Baby squirrel",
|
||||
"examine": "A tiny nut-thief."
|
||||
},
|
||||
{
|
||||
"id": "7311",
|
||||
"name": "Baby squirrel"
|
||||
"name": "Baby squirrel",
|
||||
"examine": "A tiny nut-thief."
|
||||
},
|
||||
{
|
||||
"id": "7312",
|
||||
"name": "Baby squirrel"
|
||||
"name": "Baby squirrel",
|
||||
"examine": "A tiny nut-thief."
|
||||
},
|
||||
{
|
||||
"id": "7313",
|
||||
|
|
|
|||
|
|
@ -91,6 +91,11 @@
|
|||
<version>2.9.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.java-websocket</groupId>
|
||||
<artifactId>Java-WebSocket</artifactId>
|
||||
<version>1.5.7</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
|||
|
|
@ -1,172 +0,0 @@
|
|||
package content.data;
|
||||
|
||||
import core.game.node.entity.player.Player;
|
||||
|
||||
/**
|
||||
* The BossKillcounter keeps track of the amount of bosses the player has slain.
|
||||
* addtoKillcount(player, npcId) should be added in the finalizeDeath() method of the combat handler for the boss.
|
||||
* @author Splinter
|
||||
*/
|
||||
public enum BossKillCounter {
|
||||
|
||||
|
||||
/* ORDINAL BOUND */
|
||||
KING_BLACK_DRAGON(new int[] { 50 }, "King Black Dragon", 14649),
|
||||
BORK(new int[] { 7133, 7134 }, "Bork", -1),
|
||||
DAGANNOTH_SUPREME(new int[] { 2881 }, "Dagannoth Supreme", 14639),
|
||||
DAGANNOTH_PRIME(new int[] { 2882 }, "Dagannoth Prime", 14640),
|
||||
DAGANNOTH_REX(new int[] { 2883 }, "Dagannoth Rex", 14641),
|
||||
CHAOS_ELEMENTAL(new int[] { 3200 }, "Chaos Elemental", 14638),
|
||||
GIANT_MOLE(new int[] { 3340 }, "Giant Mole", 14642),
|
||||
SARADOMIN(new int[] { 6247 }, "Commander Zilyana", 14647),
|
||||
ZAMORAK(new int[] { 6203 }, "K'ril Tsutsaroth", 14648),
|
||||
BANDOS(new int[] { 6260 }, "General Graardor", 14646),
|
||||
ARMADYL(new int[] { 6222 }, "Kree'arra", 14645),
|
||||
JAD(new int[] { 2745 }, "Tz-Tok Jad", 14828),
|
||||
KALPHITE_QUEEN(new int[] { 1160 }, "Kalphite Queen", 14650),
|
||||
CORPOREAL_BEAST(new int[] { 8133 }, "Corporeal Beast", 14653),
|
||||
TORMENTED_DEMONS(new int[] {
|
||||
8349, 8350, 8351, 8352, 8353, 8354,
|
||||
8355, 8356, 8357, 8358, 8359, 8360,
|
||||
8361, 8362, 8363, 8364, 8365, 8366,
|
||||
}, "Tormented demon", -1),
|
||||
|
||||
|
||||
;
|
||||
|
||||
/**
|
||||
* The npcs that can increase the killcounter
|
||||
*/
|
||||
private final int[] npc;
|
||||
|
||||
/**
|
||||
* The name of the NPC, to be displayed as a sendMessage
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* The item ID of the pet relating to the boss.
|
||||
*/
|
||||
private final int petId;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code BossKillCounter} {@code Object}.
|
||||
* @param npc the npc.
|
||||
* @param name the npc's string name
|
||||
*/
|
||||
BossKillCounter(final int[] npc, final String name, final int petId) {
|
||||
this.npc = npc;
|
||||
this.name = name;
|
||||
this.petId = petId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the npc.
|
||||
* @return The npc.
|
||||
*/
|
||||
public int[] getNpc() {
|
||||
return npc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the NPC's name
|
||||
* @return their name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the petId
|
||||
* @return The petId
|
||||
*/
|
||||
public int getPetId() {
|
||||
return petId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type for the npc.
|
||||
* @param npc the npc.
|
||||
* @return the BossKillcounter
|
||||
*/
|
||||
public static BossKillCounter forNPC(final int npc) {
|
||||
for (BossKillCounter kc : BossKillCounter.values()) {
|
||||
for (int i : kc.getNpc()) {
|
||||
if (npc == i) {
|
||||
return kc;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds to the player's killcount for that particular boss.
|
||||
* @param killer The player who killed the npc
|
||||
* @param npcid the ID of the npc that just died
|
||||
*/
|
||||
public static void addtoKillcount(Player killer, int npcid) {
|
||||
if (killer == null) {
|
||||
return;
|
||||
}
|
||||
BossKillCounter boss = BossKillCounter.forNPC(npcid);
|
||||
if (boss == null) {
|
||||
return;
|
||||
}
|
||||
killer.getSavedData().getGlobalData().getBossCounters()[boss.ordinal()]++;
|
||||
killer.getPacketDispatch().sendMessage("Your " + boss.getName() + " killcount is now: <col=ff0000>" + killer.getSavedData().getGlobalData().getBossCounters()[boss.ordinal()] + "</col>.");
|
||||
// addBossPet(killer, npcid, boss);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Gives the player the pet if they killed a certain boss.
|
||||
// * The chance by default is 1/5000. This rate lowers to 1/2200 if the <GlobalEvents> for Boss Pets is active.
|
||||
// * Note: Not all bosses have pet versions of themselves.
|
||||
// */
|
||||
// private static void addBossPet(Player killer, int npcid, BossKillCounter boss){
|
||||
// if(boss.getPetId() == -1){ //The boss does not have a pet version.
|
||||
// return;
|
||||
// }
|
||||
// int number = 5000;
|
||||
// if (npcid == 2745) {
|
||||
// number = 200;
|
||||
// if (killer.getSlayer().getTask() == Tasks.JAD) {
|
||||
// number = 100;
|
||||
// }
|
||||
// } else if (npcid == 3200) {
|
||||
// number = 300;
|
||||
// }
|
||||
// int rand = number;
|
||||
// if(rand == 10){
|
||||
// for (int i = 0; i < killer.getFamiliarManager().getInsuredPets().size(); i++) {
|
||||
// if (killer.getFamiliarManager().getInsuredPets().get(i).getBabyItemId() == boss.getPetId()) {
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// if(killer.getFamiliarManager().hasFamiliar() && killer.getInventory().freeSlots() < 1){
|
||||
// return;
|
||||
// }
|
||||
// if(!killer.getFamiliarManager().hasFamiliar()){
|
||||
// killer.getFamiliarManager().summon(new Item(boss.getPetId()), true);
|
||||
// killer.sendNotificationMessage("You have a funny feeling like you're being followed.");
|
||||
// } else if (killer.getInventory().freeSlots() > 0){
|
||||
// killer.getInventory().add(new Item(boss.getPetId(), 1));
|
||||
// killer.sendNotificationMessage("You feel something weird sneaking into your backpack.");
|
||||
// }
|
||||
// Repository.sendNews(killer.getUsername()+" now commands a miniature "+(boss.equals(CORPOREAL_BEAST) ? "Dark core" : boss.getName())+"!");
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* Increments the player's Barrows chest counter.
|
||||
* @param player the player
|
||||
*/
|
||||
public static void addtoBarrowsCount(Player player) {
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
player.getSavedData().getGlobalData().setBarrowsLoots(player.getSavedData().getGlobalData().getBarrowsLoots() + 1);
|
||||
player.getPacketDispatch().sendMessage("Your Barrows chest count is: <col=ff0000>" + player.getSavedData().getGlobalData().getBarrowsLoots() + "</col>.");
|
||||
}
|
||||
|
||||
}
|
||||
72
Server/src/main/content/data/BossKillCounter.kt
Normal file
72
Server/src/main/content/data/BossKillCounter.kt
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
package content.data
|
||||
|
||||
import core.api.sendMessage
|
||||
import core.game.node.entity.player.Player
|
||||
import org.rs09.consts.NPCs
|
||||
|
||||
/**
|
||||
* Enumerates the bosses that have their kill counts tracked in a player's statistics (::stats).
|
||||
* addToBossKillCount(player, npcId) should be added in the finalizeDeath() method of the combat handler for the boss.
|
||||
* ORDINAL BOUND
|
||||
* @author Bishop
|
||||
*/
|
||||
|
||||
enum class BossKillCounter(val bossId: IntArray, val bossName: String) {
|
||||
|
||||
KING_BLACK_DRAGON(intArrayOf(NPCs.KING_BLACK_DRAGON_50), "King Black Dragon"),
|
||||
BORK(intArrayOf(NPCs.BORK_7133, NPCs.BORK_7134), "Bork"),
|
||||
DAGANNOTH_SUPREME(intArrayOf(NPCs.DAGANNOTH_SUPREME_2881), "Dagannoth Supreme"),
|
||||
DAGANNOTH_PRIME(intArrayOf(NPCs.DAGANNOTH_PRIME_2882), "Dagannoth Prime"),
|
||||
DAGANNOTH_REX(intArrayOf(NPCs.DAGANNOTH_REX_2883), "Dagannoth Rex"),
|
||||
CHAOS_ELEMENTAL(intArrayOf(NPCs.CHAOS_ELEMENTAL_3200), "Chaos Elemental"),
|
||||
GIANT_MOLE(intArrayOf(NPCs.GIANT_MOLE_3340), "Giant Mole"),
|
||||
SARADOMIN(intArrayOf(NPCs.COMMANDER_ZILYANA_6247), "Commander Zilyana"),
|
||||
ZAMORAK(intArrayOf(NPCs.KRIL_TSUTSAROTH_6203), "K'ril Tsutsaroth"),
|
||||
BANDOS(intArrayOf(NPCs.GENERAL_GRAARDOR_6260), "General Graardor"),
|
||||
ARMADYL(intArrayOf(NPCs.KREEARRA_6222), "Kree'arra"),
|
||||
JAD(intArrayOf(NPCs.TZTOK_JAD_2745), "Tz-Tok Jad"),
|
||||
KALPHITE_QUEEN(intArrayOf(NPCs.KALPHITE_QUEEN_1160), "Kalphite Queen"),
|
||||
CORPOREAL_BEAST(intArrayOf(NPCs.CORPOREAL_BEAST_8133), "Corporeal Beast"),
|
||||
TORMENTED_DEMONS(
|
||||
intArrayOf(
|
||||
NPCs.TORMENTED_DEMON_8349, NPCs.TORMENTED_DEMON_8350, NPCs.TORMENTED_DEMON_8351,
|
||||
NPCs.TORMENTED_DEMON_8352, NPCs.TORMENTED_DEMON_8353, NPCs.TORMENTED_DEMON_8354,
|
||||
NPCs.TORMENTED_DEMON_8355, NPCs.TORMENTED_DEMON_8356, NPCs.TORMENTED_DEMON_8357,
|
||||
NPCs.TORMENTED_DEMON_8358, NPCs.TORMENTED_DEMON_8359, NPCs.TORMENTED_DEMON_8360,
|
||||
NPCs.TORMENTED_DEMON_8361, NPCs.TORMENTED_DEMON_8362, NPCs.TORMENTED_DEMON_8363,
|
||||
NPCs.TORMENTED_DEMON_8364, NPCs.TORMENTED_DEMON_8365, NPCs.TORMENTED_DEMON_8366),
|
||||
"Tormented demon"
|
||||
),
|
||||
PENANCE_QUEEN(intArrayOf(NPCs.PENANCE_QUEEN_5247), "Penance Queen");
|
||||
|
||||
companion object {
|
||||
private fun forBossId(npc: Int): BossKillCounter? {
|
||||
for (kc in values()) {
|
||||
for (i in kc.bossId) {
|
||||
if (npc == i) {
|
||||
return kc
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun addToBossKillCount(killer: Player?, bossId: Int) {
|
||||
if (killer == null) {
|
||||
return
|
||||
}
|
||||
val boss: BossKillCounter = forBossId(bossId) ?: return
|
||||
killer.getSavedData().globalData.bossCounters[boss.ordinal]++
|
||||
sendMessage(killer, "Your ${boss.bossName} killcount is now: <col=ff0000>${killer.getSavedData().globalData.bossCounters[boss.ordinal]}</col>.")
|
||||
}
|
||||
|
||||
fun addToBarrowsChestCount(player: Player?) {
|
||||
if (player == null) {
|
||||
return
|
||||
}
|
||||
player.getSavedData().globalData.barrowsLoots++
|
||||
sendMessage(player, "Your Barrows chest count is: <col=ff0000>${player.getSavedData().globalData.barrowsLoots}</col>.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -193,7 +193,7 @@ enum class EnchantedJewellery(
|
|||
),
|
||||
RING_OF_LIFE(arrayOf<String>(),
|
||||
arrayOf(
|
||||
Location.create(ServerConstants.HOME_LOCATION)
|
||||
Location.create(ServerConstants.HOME_LOCATION!!)
|
||||
),
|
||||
true,
|
||||
Items.RING_OF_LIFE_2570
|
||||
|
|
@ -246,7 +246,13 @@ enum class EnchantedJewellery(
|
|||
when (stage) {
|
||||
0 -> {
|
||||
lock(player, 4)
|
||||
visualize(player, ANIMATION, GRAPHICS)
|
||||
// This is an intentional teleport animation & graphics difference as these two jewellery
|
||||
// animations are authentic to 2009 while others are currently unknown.
|
||||
if (this == RING_OF_DUELING || this == GAMES_NECKLACE) {
|
||||
visualize(player, JEWELLERY_ANIMATION, JEWELLERY_GRAPHICS)
|
||||
} else {
|
||||
visualize(player, ANIMATION, GRAPHICS)
|
||||
}
|
||||
playGlobalAudio(player.location, Sounds.TELEPORT_ALL_200)
|
||||
player.impactHandler.disabledTicks = 4
|
||||
closeInterface(player)
|
||||
|
|
@ -255,6 +261,9 @@ enum class EnchantedJewellery(
|
|||
1 -> {
|
||||
teleport(player, location)
|
||||
resetAnimator(player)
|
||||
if (this == RING_OF_DUELING || this == GAMES_NECKLACE) {
|
||||
player.graphics(JEWELLERY_GRAPHICS)
|
||||
}
|
||||
unlock(player)
|
||||
player.dispatch(TeleportEvent(TeleportManager.TeleportType.NORMAL, TeleportMethod.JEWELRY, item, location))
|
||||
|
||||
|
|
@ -370,6 +379,8 @@ enum class EnchantedJewellery(
|
|||
companion object {
|
||||
private val ANIMATION = Animation(714)
|
||||
private val GRAPHICS = Graphics(308, 100, 50)
|
||||
private val JEWELLERY_ANIMATION = Animation(9603)
|
||||
private val JEWELLERY_GRAPHICS = Graphics(1684)
|
||||
val idMap = HashMap<Int, EnchantedJewellery>()
|
||||
|
||||
init {
|
||||
|
|
|
|||
|
|
@ -353,7 +353,7 @@ public enum Consumables {
|
|||
FISHING(new Potion(new int[] {2438, 151, 153, 155}, new SkillEffect(Skills.FISHING, 3, 0))),
|
||||
PRAYER(new Potion(new int[] {2434, 139, 141, 143}, new PrayerEffect(7, 0.25))),
|
||||
SUPER_RESTO(new Potion(new int[] {3024, 3026, 3028, 3030}, new RestoreEffect(8, 0.25, true))),
|
||||
ZAMMY_BREW(new Potion(new int[] {2450, 189, 191, 193}, new MultiEffect(new DamageEffect(10, true), new SkillEffect(Skills.ATTACK, 0, 0.25), new SkillEffect(Skills.STRENGTH, 0, 0.15), new SkillEffect(Skills.DEFENCE, 0, -0.1)))),
|
||||
ZAMMY_BREW(new Potion(new int[] {2450, 189, 191, 193}, new MultiEffect(new DamageEffect(10, true, 2), new SkillEffect(Skills.ATTACK, 2, 0.20), new SkillEffect(Skills.STRENGTH, 2, 0.12), new SkillEffect(Skills.DEFENCE, -2, -0.10), new PrayerEffect(0.0, 0.10, true)))),
|
||||
ANTIFIRE(new Potion(new int[] {2452, 2454, 2456, 2458}, new AddTimerEffect("dragonfire:immunity", 600, true))),
|
||||
GUTH_REST(new Potion(new int[] {4417, 4419, 4421, 4423}, new MultiEffect(new RemoveTimerEffect("poison"), new EnergyEffect(5), new HealingEffect(5)))),
|
||||
MAGIC_ESS(new Potion(new int[] {9021, 9022, 9023, 9024}, new SkillEffect(Skills.MAGIC,3,0))),
|
||||
|
|
@ -363,7 +363,7 @@ public enum Consumables {
|
|||
|
||||
/** Barbarian Mixes */
|
||||
PRAYERMIX(new BarbarianMix(new int[] {11465, 11467}, new MultiEffect(new PrayerEffect(7, 0.25), new HealingEffect(6)))),
|
||||
ZAMMY_MIX(new BarbarianMix(new int[] {11521, 11523}, new MultiEffect(new DamageEffect(10, true), new SkillEffect(Skills.ATTACK, 0, 0.15), new SkillEffect(Skills.STRENGTH, 0, 0.25), new SkillEffect(Skills.DEFENCE, 0, -0.1)))),
|
||||
ZAMMY_MIX(new BarbarianMix(new int[]{11521, 11523}, new MultiEffect(new ZamorakMixEffect(), new SkillEffect(Skills.ATTACK, 2, 0.20), new SkillEffect(Skills.STRENGTH, 2, 0.12), new SkillEffect(Skills.DEFENCE, -2, -0.10)))),
|
||||
ATT_MIX(new BarbarianMix(new int[] {11429, 11431}, new MultiEffect(new SkillEffect(Skills.ATTACK, 3, 0.1), new HealingEffect(3)))),
|
||||
ANTIP_MIX(new BarbarianMix(new int[] {11433, 11435}, new MultiEffect(new AddTimerEffect("poison:immunity", secondsToTicks(90)), new HealingEffect(3)))),
|
||||
RELIC_MIX(new BarbarianMix(new int[] {11437, 11439}, new MultiEffect(new CureDiseaseEffect(), new HealingEffect(3)))),
|
||||
|
|
|
|||
|
|
@ -7,15 +7,21 @@ import core.game.node.entity.player.Player;
|
|||
public class DamageEffect extends ConsumableEffect {
|
||||
final double amt;
|
||||
final boolean isPercent;
|
||||
final int baseAmount;
|
||||
|
||||
public DamageEffect(double amt,boolean isPercent){
|
||||
public DamageEffect(double amt, boolean isPercent) {
|
||||
this(amt, isPercent, 0);
|
||||
}
|
||||
|
||||
public DamageEffect(double amt, boolean isPercent, int baseAmount) {
|
||||
this.amt = amt;
|
||||
this.isPercent = isPercent;
|
||||
this.baseAmount = baseAmount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activate(Player p) {
|
||||
p.getImpactHandler().manualHit(p,-getHealthEffectValue(p), ImpactHandler.HitsplatType.NORMAL);
|
||||
p.getImpactHandler().manualHit(p, -getHealthEffectValue(p), ImpactHandler.HitsplatType.NORMAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -23,8 +29,8 @@ public class DamageEffect extends ConsumableEffect {
|
|||
double amount = amt;
|
||||
if (isPercent) {
|
||||
amount /= 100;
|
||||
return (int) -(amount * player.getSkills().getLifepoints());
|
||||
return (int) -(amount * player.getSkills().getLifepoints() + baseAmount);
|
||||
}
|
||||
return (int) -amt;
|
||||
return (int) -(amt + baseAmount);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,16 +5,18 @@ import core.game.consumable.ConsumableEffect
|
|||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.skill.Skills
|
||||
import org.rs09.consts.Items
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.floor
|
||||
|
||||
class PrayerEffect(var base: Double, var bonus: Double) : ConsumableEffect() {
|
||||
class PrayerEffect @JvmOverloads constructor(var base: Double, var bonus: Double, private val roundUp: Boolean = false) : ConsumableEffect() {
|
||||
override fun activate(player: Player?) {
|
||||
if(player == null) return
|
||||
val level = getStatLevel(player, Skills.PRAYER)
|
||||
var b = bonus
|
||||
if(inInventory(player, Items.HOLY_WRENCH_6714))
|
||||
b += 0.02 // Leaving this in for futureproofing. Current update is for properly rounding down.
|
||||
val amount = floor(base + (level * b))
|
||||
val rawAmount = base + (level * b)
|
||||
val amount = if (roundUp) ceil(rawAmount) else floor(rawAmount)
|
||||
modPrayerPoints(player, amount)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package content.data.consumables.effects;
|
||||
|
||||
import core.game.consumable.ConsumableEffect;
|
||||
import core.game.node.entity.combat.ImpactHandler;
|
||||
import core.game.node.entity.player.Player;
|
||||
|
||||
/**
|
||||
* The Zamorak mix shows the regular Zamorak brew hitsplat (10% of pre-drink lifepoints + 2, rounded down)
|
||||
* but also heals 6 lifepoints. The heal must be applied before the hit so the net change can never kill
|
||||
* the player, while the hitsplat still reflects the pre-heal lifepoints.
|
||||
*/
|
||||
public class ZamorakMixEffect extends ConsumableEffect {
|
||||
|
||||
@Override
|
||||
public void activate(Player p) {
|
||||
int damage = (int) (p.getSkills().getLifepoints() * 0.10 + 2);
|
||||
p.getSkills().heal(6);
|
||||
p.getImpactHandler().manualHit(p, damage, ImpactHandler.HitsplatType.NORMAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHealthEffectValue(Player player) {
|
||||
return 6 - (int) (player.getSkills().getLifepoints() * 0.10 + 2);
|
||||
}
|
||||
}
|
||||
|
|
@ -39,6 +39,7 @@ abstract class RandomEventNPC(id: Int) : NPC(id) {
|
|||
var finalized = false
|
||||
var timerPaused = false
|
||||
var ticksLeft = secondsToTicks(180)
|
||||
private val combatBracket = intArrayOf(10, 20, 40, 60, 90)
|
||||
|
||||
open fun create(player: Player, loot: WeightBasedTable? = null, type: String = ""): RandomEventNPC {
|
||||
val event = this::class.createInstance()
|
||||
|
|
@ -144,7 +145,7 @@ abstract class RandomEventNPC(id: Int) : NPC(id) {
|
|||
}
|
||||
|
||||
fun idForCombatLevel(ids: List<Int>, player: Player): Int {
|
||||
val index = min(ids.size, ceil(player.properties.currentCombatLevel / 20.0).toInt()) - 1
|
||||
val index = combatBracket.indexOfFirst { player.properties.currentCombatLevel <= it }.takeIf { it != -1 }?: ids.lastIndex
|
||||
return ids[index]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ class QuizMasterNPC(var type: String = "", override var loot: WeightBasedTable?
|
|||
super.init()
|
||||
sendChat("Hey ${player.username}! It's your lucky day!")
|
||||
face(player)
|
||||
kidnapPlayer(this, player, Location(1952, 4764, 0)) { player, _ ->
|
||||
kidnapPlayer(this, player, Location(1952, 4764, 1)) { player, _ ->
|
||||
setAttribute(player, QuizMasterDialogueFile.QUIZMASTER_ATTRIBUTE_QUESTIONS_CORRECT, 0)
|
||||
sendMessage(player, "Answer four questions correctly in a row to be teleported back where you came from.")
|
||||
sendMessage(player, "You will need to relog in if you lose the quiz dialog.") // Inauthentic, but there to notify the player in case.
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import core.game.bots.SkillingBotAssembler
|
|||
import core.game.bots.Script
|
||||
import core.game.interaction.IntType
|
||||
import core.game.interaction.InteractionListeners
|
||||
import core.game.node.entity.skill.Skills
|
||||
import java.util.*
|
||||
|
||||
class ManThiever : Script() {
|
||||
|
|
@ -22,6 +23,6 @@ class ManThiever : Script() {
|
|||
}
|
||||
|
||||
init {
|
||||
equipment.addAll(Arrays.asList(Item(1103), Item(1139), Item(1265)))
|
||||
skills[Skills.THIEVING] = 20
|
||||
}
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
package content.global.handlers.iface;
|
||||
|
||||
import static core.api.ContentAPIKt.*;
|
||||
import core.game.component.Component;
|
||||
import core.game.component.ComponentDefinition;
|
||||
import core.game.component.ComponentPlugin;
|
||||
import content.global.travel.glider.GliderPulse;
|
||||
import content.global.travel.glider.Gliders;
|
||||
import core.game.node.entity.player.Player;
|
||||
import core.plugin.Initializable;
|
||||
import core.plugin.Plugin;
|
||||
|
||||
/**
|
||||
* Represents the glider interface component.
|
||||
* @author Emperor
|
||||
* @author 'Vexia
|
||||
* @version 1.0
|
||||
*/
|
||||
@Initializable
|
||||
public final class GliderInterface extends ComponentPlugin {
|
||||
|
||||
@Override
|
||||
public Plugin<Object> newInstance(Object arg) throws Throwable {
|
||||
ComponentDefinition.put(138, this);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(final Player player, Component component, int opcode, int button, int slot, int itemId) {
|
||||
final Gliders glider = Gliders.forId(button);
|
||||
if (glider == null) {
|
||||
return true;
|
||||
}
|
||||
submitWorldPulse(new GliderPulse(1, player, glider));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package content.global.handlers.iface
|
||||
|
||||
import core.api.submitWorldPulse
|
||||
import content.global.travel.glider.GliderPulse
|
||||
import content.global.travel.glider.Gliders
|
||||
import core.game.interaction.InterfaceListener
|
||||
import org.rs09.consts.Components
|
||||
|
||||
class GliderInterface : InterfaceListener {
|
||||
override fun defineInterfaceListeners() {
|
||||
on(Components.GLIDERMAP_138) { player, _, _, button, _, _ ->
|
||||
val glider = Gliders.forId(button) ?: return@on true
|
||||
submitWorldPulse(GliderPulse(1, player, glider))
|
||||
return@on true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
package content.global.handlers.iface;
|
||||
|
||||
import core.game.component.Component;
|
||||
import core.game.component.ComponentDefinition;
|
||||
import core.game.component.ComponentPlugin;
|
||||
import core.game.node.entity.player.Player;
|
||||
import core.plugin.Initializable;
|
||||
import core.plugin.Plugin;
|
||||
|
||||
/**
|
||||
* Handles the world map interface.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
@Initializable
|
||||
public final class WorldMapInterface extends ComponentPlugin {
|
||||
|
||||
@Override
|
||||
public Plugin<Object> newInstance(Object arg) throws Throwable {
|
||||
ComponentDefinition.forId(755).setPlugin(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
//Thanks snicker!
|
||||
@Override
|
||||
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
|
||||
switch (button) {
|
||||
case 3:
|
||||
player.getInterfaceManager().openWindowsPane(new Component(player.getInterfaceManager().isResizable() ? 746 : 548), 2);
|
||||
player.getPacketDispatch().sendRunScript(1187, "ii", 0, 0);
|
||||
player.updateSceneGraph(true);
|
||||
return true;
|
||||
default:
|
||||
//log(this.getClass(), Log.ERR, "World map: buttonid: " + button + ", opcode: " + opcode + ", slot: " + slot);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package content.global.handlers.iface
|
||||
|
||||
import core.game.component.Component
|
||||
import core.game.interaction.InterfaceListener
|
||||
import org.rs09.consts.Components
|
||||
|
||||
class WorldMapInterface : InterfaceListener {
|
||||
override fun defineInterfaceListeners() {
|
||||
on(Components.WORLDMAP_755) { player, _, _, button, _, _ ->
|
||||
if (button == 3) {
|
||||
val paneId = if (player.interfaceManager.isResizable) {
|
||||
Components.TOPLEVEL_FULLSCREEN_746
|
||||
} else {
|
||||
Components.TOPLEVEL_548
|
||||
}
|
||||
player.interfaceManager.openWindowsPane(Component(paneId), 2)
|
||||
player.packetDispatch.sendRunScript(1187, "ii", 0, 0)
|
||||
player.updateSceneGraph(true)
|
||||
}
|
||||
return@on true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,6 @@ package content.global.handlers.item
|
|||
|
||||
import content.global.skill.slayer.SlayerUtils
|
||||
import core.api.*
|
||||
import content.global.skill.slayer.Tasks
|
||||
import org.rs09.consts.Items
|
||||
import core.game.dialogue.DialogueFile
|
||||
import core.game.dialogue.IfTopic
|
||||
|
|
@ -39,12 +38,7 @@ class EnchantedGemDialogue() : DialogueFile() {
|
|||
if(!hasSlayerTask(player!!)) {
|
||||
npcl(core.game.dialogue.FacialExpression.HALF_THINKING, "You need something new to hunt. Come and see me when you can and I'll give you a new task.").also { stage = 1 }
|
||||
} else {
|
||||
if(getSlayerTask(player!!) == Tasks.JAD) {
|
||||
npcl(core.game.dialogue.FacialExpression.FRIENDLY, "You're currently assigned to kill TzTok-Jad!")
|
||||
} else {
|
||||
npcl(core.game.dialogue.FacialExpression.FRIENDLY, "You're currently assigned to kill ${SlayerUtils.pluralise(
|
||||
getSlayerTaskName(player!!))}; only ${getSlayerTaskKillsRemaining(player!!)} more to go.")
|
||||
}
|
||||
npcl(core.game.dialogue.FacialExpression.FRIENDLY, "You're currently assigned to kill ${SlayerUtils.pluralise(getSlayerTaskName(player!!))}; only ${getSlayerTaskKillsRemaining(player!!)} more to go.")
|
||||
setVarp(player!!, 2502, getSlayerTaskFlags(player!!) shr 4)
|
||||
stage = 1
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
package content.global.handlers.item
|
||||
|
||||
import core.api.*
|
||||
import core.game.interaction.InteractionListener
|
||||
import core.game.interaction.InterfaceListener
|
||||
import core.game.node.entity.player.Player
|
||||
import org.rs09.consts.Items
|
||||
import org.rs09.consts.NPCs
|
||||
import org.rs09.consts.Sounds
|
||||
|
||||
/**
|
||||
* Handles morphing with the Ring of Stone and Easter Ring.
|
||||
*/
|
||||
|
||||
class MorphItemListener : InteractionListener, InterfaceListener {
|
||||
|
||||
// the morphing items
|
||||
private val morphItems = intArrayOf(Items.RING_OF_STONE_6583, Items.EASTER_RING_7927)
|
||||
|
||||
// the NPCs to morph into
|
||||
private val easterEggs = intArrayOf(
|
||||
NPCs.EGG_3689,
|
||||
NPCs.EGG_3690,
|
||||
NPCs.EGG_3691,
|
||||
NPCs.EGG_3692,
|
||||
NPCs.EGG_3693,
|
||||
NPCs.EGG_3694
|
||||
)
|
||||
private val stone = intArrayOf(NPCs.ROCKS_2626)
|
||||
|
||||
// the "unmorph" interface
|
||||
private val morphIface = 375
|
||||
|
||||
// equipping the morph items
|
||||
override fun defineListeners() {
|
||||
onEquip(morphItems) { player, item ->
|
||||
morph(player, item.id)
|
||||
return@onEquip false
|
||||
}
|
||||
}
|
||||
|
||||
// the interface that appears when you morph
|
||||
override fun defineInterfaceListeners() {
|
||||
|
||||
// hitting the 'unmorph' button
|
||||
on(morphIface){ player, _, _, buttonID, _, _ ->
|
||||
when(buttonID) {
|
||||
3 -> closeAllInterfaces(player)
|
||||
}
|
||||
return@on true
|
||||
}
|
||||
|
||||
// after the interface closes
|
||||
onClose(morphIface) { player, _ ->
|
||||
unmorph(player)
|
||||
return@onClose true
|
||||
}
|
||||
}
|
||||
|
||||
// morphs the player
|
||||
private fun morph(player: Player, item: Int) {
|
||||
val morphId = when (item) {
|
||||
Items.RING_OF_STONE_6583 -> stone.random()
|
||||
else -> easterEggs.random()
|
||||
}
|
||||
playAudio(player, Sounds.EASTER06_HUMAN_INTO_EGG_1520)
|
||||
stopWalk(player)
|
||||
closeAllInterfaces(player)
|
||||
player.appearance.transformNPC(morphId)
|
||||
openInterface(player, morphIface)
|
||||
}
|
||||
|
||||
// unmorphs the player
|
||||
private fun unmorph(player: Player) {
|
||||
player.appearance.transformNPC(-1)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
package content.global.handlers.item;
|
||||
|
||||
import core.cache.def.impl.ItemDefinition;
|
||||
import core.game.component.CloseEvent;
|
||||
import core.game.component.Component;
|
||||
import core.game.component.ComponentDefinition;
|
||||
import core.game.component.ComponentPlugin;
|
||||
import core.game.node.entity.player.Player;
|
||||
import core.game.node.item.Item;
|
||||
import core.game.world.GameWorld;
|
||||
import core.plugin.Initializable;
|
||||
import core.plugin.Plugin;
|
||||
import core.plugin.ClassScanner;
|
||||
import core.tools.RandomFunction;
|
||||
import org.rs09.consts.Sounds;
|
||||
|
||||
import static core.api.ContentAPIKt.playAudio;
|
||||
|
||||
/**
|
||||
* Handles a morph item.
|
||||
* @author Vexia
|
||||
*/
|
||||
@Initializable
|
||||
public class MorphItemPlugin implements Plugin<Object> {
|
||||
|
||||
/**
|
||||
* The easter egg ids.
|
||||
*/
|
||||
protected static final int[] EASTER_EGG_IDS = new int[] { 3689, 3690, 3691, 3692, 3693, 3694 };
|
||||
|
||||
/**
|
||||
* The morph component.
|
||||
*/
|
||||
private static final Component COMPONENT = new Component(375).setCloseEvent(new CloseEvent() {
|
||||
|
||||
@Override
|
||||
public boolean close(Player player, Component c) {
|
||||
unmorph(player);
|
||||
return true;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@Override
|
||||
public Plugin<Object> newInstance(Object arg) throws Throwable {
|
||||
ItemDefinition.forId(7927).getHandlers().put("equipment", this);
|
||||
ItemDefinition.forId(6583).getHandlers().put("equipment", this);
|
||||
ClassScanner.definePlugin(new MorphInterfacePlugin());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fireEvent(String identifier, Object... args) {
|
||||
final Player player = (Player) args[0];
|
||||
final Item item = (Item) args[1];
|
||||
switch (identifier) {
|
||||
case "equip":
|
||||
morph(player, item);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Morphs the player.
|
||||
* @param player the player.
|
||||
* @param item the item.
|
||||
*/
|
||||
private void morph(Player player, Item item) {
|
||||
int morphId = item.getId() == 6583 ? 2626 : EASTER_EGG_IDS[RandomFunction.random(EASTER_EGG_IDS.length)];
|
||||
playAudio(player, 1520);
|
||||
player.getInterfaceManager().close();
|
||||
player.getAppearance().transformNPC(morphId);
|
||||
player.getInterfaceManager().removeTabs(0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14);
|
||||
player.getLocks().lockMovement(GameWorld.getTicks() + 900000000);
|
||||
player.getLocks().lockInteractions(GameWorld.getTicks() + 90000000);
|
||||
player.getLocks().lockTeleport(GameWorld.getTicks() + 900000000);
|
||||
player.getInterfaceManager().openSingleTab(COMPONENT);
|
||||
player.getAppearance().sync();
|
||||
player.getWalkingQueue().reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmorphs the player.
|
||||
* @param player the player.
|
||||
*/
|
||||
private static void unmorph(Player player) {
|
||||
player.getAppearance().transformNPC(-1);
|
||||
player.unlock();
|
||||
player.getInterfaceManager().restoreTabs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the morph interface plugin.
|
||||
* @author Vexia
|
||||
*/
|
||||
public class MorphInterfacePlugin extends ComponentPlugin {
|
||||
|
||||
@Override
|
||||
public Plugin<Object> newInstance(Object arg) throws Throwable {
|
||||
ComponentDefinition.forId(375).setPlugin(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
|
||||
player.getInterfaceManager().closeSingleTab();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -129,9 +129,9 @@ class SheepBehavior : NPCBehavior(*sheepIds), InteractionListener {
|
|||
val sheepDirection = Direction.getDirection(sheepLocation, playerLocation) // Get direction sheep is facing, from the player's location
|
||||
val sheepOppositeDirection = sheepDirection.getOpposite() // Switch to opposite direction
|
||||
|
||||
val xWalkLocation = sheepLocation.getX() + (sheepOppositeDirection.getStepX() * 3) // Gets x location, if set, 3 steps away from player
|
||||
val yWalkLocation = sheepLocation.getY() + (sheepOppositeDirection.getStepY() * 3) // Gets y location, if set, 3 steps away from player
|
||||
val sheepWalkToLocation = Location(xWalkLocation, yWalkLocation, sheepLocation.getZ()); // New location for pathfinding
|
||||
val xWalkLocation = sheepLocation.x + (sheepOppositeDirection.getStepX() * 3) // Gets x location, if set, 3 steps away from player
|
||||
val yWalkLocation = sheepLocation.y + (sheepOppositeDirection.getStepY() * 3) // Gets y location, if set, 3 steps away from player
|
||||
val sheepWalkToLocation = Location(xWalkLocation, yWalkLocation, sheepLocation.z); // New location for pathfinding
|
||||
|
||||
sendMessage(player, messagePlayer)
|
||||
|
||||
|
|
|
|||
|
|
@ -139,6 +139,13 @@ public final class AgilityHandler {
|
|||
* @return The force movement instance, if force movement is used.
|
||||
*/
|
||||
public static ForceMovement forceWalk(final Player player, final int courseIndex, Location start, Location end, Animation animation, int speed, final double experience, final String message) {
|
||||
return forceWalk(player, courseIndex, start, end, animation, speed, experience, message, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks across an obstacle while using an explicit force-movement facing direction.
|
||||
*/
|
||||
public static ForceMovement forceWalk(final Player player, final int courseIndex, Location start, Location end, Animation animation, int speed, final double experience, final String message, Direction direction) {
|
||||
player.logoutListeners.put("forcewalk", p -> {
|
||||
p.setLocation(player.getLocation().transform(0,0,0));
|
||||
return Unit.INSTANCE;
|
||||
|
|
@ -158,6 +165,9 @@ public final class AgilityHandler {
|
|||
player.logoutListeners.remove("forcewalk");
|
||||
}
|
||||
};
|
||||
if (direction != null) {
|
||||
movement.setDirection(direction);
|
||||
}
|
||||
movement.start();
|
||||
GameWorld.getPulser().submit(movement);
|
||||
return movement;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@ import core.game.node.entity.Entity;
|
|||
import core.game.node.entity.player.Player;
|
||||
import core.game.system.task.MovementHook;
|
||||
import core.game.system.task.Pulse;
|
||||
import core.net.packet.PacketRepository;
|
||||
import core.net.packet.context.PlayerContext;
|
||||
import core.net.packet.out.ClearMinimapFlag;
|
||||
import kotlin.Unit;
|
||||
import core.game.world.GameWorld;
|
||||
import core.game.world.map.Direction;
|
||||
|
|
@ -24,6 +27,10 @@ public final class BladeTrap implements MovementHook {
|
|||
final Direction dir = e.getDirection();
|
||||
final Player player = (Player) e;
|
||||
final Location start = l.transform(-dir.getStepX(), -dir.getStepY(), 0);
|
||||
player.getPulseManager().clear();
|
||||
player.getWalkingQueue().reset();
|
||||
PacketRepository.send(ClearMinimapFlag.class, new PlayerContext(player));
|
||||
|
||||
e.lock(5);
|
||||
if(e.isPlayer())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -119,6 +119,8 @@ public final class BrimhavenCourse extends OptionHandler {
|
|||
final Direction dir = direction;
|
||||
final Direction faceDirection = Direction.get(object.getDirection().toInteger() - 1 & 3);
|
||||
final Location start = player.getLocation();
|
||||
player.setDirection(faceDirection);
|
||||
player.faceLocation(start.transform(faceDirection));
|
||||
player.getAppearance().setAnimations(Animation.create(1118 + m));
|
||||
player.getAppearance().sync();
|
||||
AgilityHandler.climb(player, -1, new Animation(1117 + m), start.transform(dir), 0.0, null);
|
||||
|
|
@ -143,12 +145,12 @@ public final class BrimhavenCourse extends OptionHandler {
|
|||
} else if (count == 6) {
|
||||
player.getAppearance().setAnimations();
|
||||
player.getAppearance().sync();
|
||||
AgilityHandler.forceWalk(player, -1, last, last.transform(dir), Animation.create(1120 + m), 5, getExp(player, 22.0), null).setDirection(faceDirection);
|
||||
AgilityHandler.forceWalk(player, -1, last, last.transform(dir), Animation.create(1120 + m), 5, getExp(player, 22.0), null, faceDirection);
|
||||
player.logoutListeners.remove("brimcourse");
|
||||
return true;
|
||||
}
|
||||
player.logoutListeners.remove("brimcourse");
|
||||
AgilityHandler.forceWalk(player, -1, last, last = last.transform(dir), Animation.create(1118 + m), 5, 0.0, null).setDirection(faceDirection);
|
||||
AgilityHandler.forceWalk(player, -1, last, last = last.transform(dir), Animation.create(1118 + m), 5, 0.0, null, faceDirection);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
|
@ -272,7 +274,7 @@ public final class BrimhavenCourse extends OptionHandler {
|
|||
public boolean pulse() {
|
||||
if (!finish) {
|
||||
setDelay(2);
|
||||
AgilityHandler.fail(player, 1, player.getLocation().transform(0, 0, -3), Animation.create(189), getHitAmount(player), "You stepped on a broken piece of plank!");
|
||||
AgilityHandler.fail(player, 1, player.getLocation().transform(0, 0, -3), Animation.create(768), getHitAmount(player), "You stepped on a broken piece of plank!");
|
||||
finish = true;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -282,7 +284,7 @@ public final class BrimhavenCourse extends OptionHandler {
|
|||
});
|
||||
return;
|
||||
}
|
||||
AgilityHandler.walk(player, -1, start, end, ForceMovement.WALK_ANIMATION, getExp(player, 6.0), null);
|
||||
AgilityHandler.walk(player, -1, start, end, Animation.create(1426), getExp(player, 6.0), null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -389,6 +391,7 @@ public final class BrimhavenCourse extends OptionHandler {
|
|||
}
|
||||
break;
|
||||
case 3551:
|
||||
case 3583:
|
||||
return n.getLocation();
|
||||
}
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import core.game.node.entity.impl.Projectile;
|
|||
import core.game.node.entity.player.Player;
|
||||
import core.game.system.task.MovementHook;
|
||||
import core.game.system.task.Pulse;
|
||||
import core.net.packet.context.PlayerContext;
|
||||
import core.net.packet.out.ClearMinimapFlag;
|
||||
import kotlin.Unit;
|
||||
import core.game.world.GameWorld;
|
||||
import core.game.world.map.Direction;
|
||||
|
|
@ -29,6 +31,9 @@ public final class DartTrap implements MovementHook {
|
|||
final Direction dir = e.getDirection();
|
||||
final Player player = (Player) e;
|
||||
final Location start = l.transform(-dir.getStepX(), -dir.getStepY(), 0);
|
||||
player.getPulseManager().clear();
|
||||
player.getWalkingQueue().reset();
|
||||
PacketRepository.send(ClearMinimapFlag.class, new PlayerContext(player));
|
||||
e.lock(6);
|
||||
if(e.isPlayer())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ import core.game.node.entity.Entity;
|
|||
import core.game.node.entity.player.Player;
|
||||
import core.game.system.task.MovementHook;
|
||||
import core.game.system.task.Pulse;
|
||||
import core.net.packet.PacketRepository;
|
||||
import core.net.packet.context.PlayerContext;
|
||||
import core.net.packet.out.ClearMinimapFlag;
|
||||
import kotlin.Unit;
|
||||
import core.game.world.GameWorld;
|
||||
import core.game.world.map.Direction;
|
||||
|
|
@ -24,6 +27,9 @@ public final class FloorSpikes implements MovementHook {
|
|||
final Direction dir = e.getDirection();
|
||||
final Player player = (Player) e;
|
||||
final Location start = l.transform(-dir.getStepX(), -dir.getStepY(), 0);
|
||||
player.getPulseManager().clear();
|
||||
player.getWalkingQueue().reset();
|
||||
PacketRepository.send(ClearMinimapFlag.class, new PlayerContext(player));
|
||||
e.lock(5);
|
||||
if(e.isPlayer())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ import core.game.node.entity.Entity;
|
|||
import core.game.node.entity.player.Player;
|
||||
import core.game.system.task.MovementHook;
|
||||
import core.game.system.task.Pulse;
|
||||
import core.net.packet.PacketRepository;
|
||||
import core.net.packet.context.PlayerContext;
|
||||
import core.net.packet.out.ClearMinimapFlag;
|
||||
import kotlin.Unit;
|
||||
import core.game.world.GameWorld;
|
||||
import core.game.world.map.Direction;
|
||||
|
|
@ -24,6 +27,10 @@ public final class PressurePad implements MovementHook {
|
|||
final Direction dir = e.getDirection();
|
||||
final Player player = (Player) e;
|
||||
final Location start = dest.transform(-dir.getStepX(), -dir.getStepY(), 0);
|
||||
player.getPulseManager().clear();
|
||||
player.getWalkingQueue().reset();
|
||||
PacketRepository.send(ClearMinimapFlag.class, new PlayerContext(player));
|
||||
|
||||
e.lock(5);
|
||||
if(e.isPlayer())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ import core.game.node.entity.Entity;
|
|||
import core.game.node.entity.player.Player;
|
||||
import core.game.system.task.MovementHook;
|
||||
import core.game.system.task.Pulse;
|
||||
import core.net.packet.PacketRepository;
|
||||
import core.net.packet.context.PlayerContext;
|
||||
import core.net.packet.out.ClearMinimapFlag;
|
||||
import kotlin.Unit;
|
||||
import core.game.world.GameWorld;
|
||||
import core.game.world.map.Direction;
|
||||
|
|
@ -24,6 +27,9 @@ public final class SpinningBlades implements MovementHook {
|
|||
final Direction dir = e.getDirection();
|
||||
final Player player = (Player) e;
|
||||
final Location start = l.transform(-dir.getStepX(), -dir.getStepY(), 0);
|
||||
player.getPulseManager().clear();
|
||||
player.getWalkingQueue().reset();
|
||||
PacketRepository.send(ClearMinimapFlag.class, new PlayerContext(player));
|
||||
e.lock(5);
|
||||
if(e.isPlayer())
|
||||
{
|
||||
|
|
@ -70,4 +76,4 @@ public final class SpinningBlades implements MovementHook {
|
|||
}
|
||||
player.getPacketDispatch().sendSceneryAnimation(RegionManager.getObject(l), Animation.create(1107));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
package content.global.skill.construction.decoration.skillhall
|
||||
|
||||
import content.global.skill.construction.HouseManager
|
||||
import core.api.openDialogue
|
||||
import core.game.dialogue.DialogueFile
|
||||
import core.game.dialogue.FacialExpression
|
||||
import core.game.interaction.IntType
|
||||
import core.game.interaction.InteractionListener
|
||||
import core.game.world.repository.Repository
|
||||
import core.tools.END_DIALOGUE
|
||||
import org.rs09.consts.NPCs
|
||||
import org.rs09.consts.Scenery as Sceneries
|
||||
|
||||
class MountedCockatriceHead : InteractionListener {
|
||||
override fun defineListeners() {
|
||||
on(Sceneries.COCKATRICE_HEAD_13482, IntType.SCENERY, "talk-to") { player, _ ->
|
||||
val house = player.getAttribute<HouseManager>("poh_entry", player.houseManager)
|
||||
if (house == player.houseManager) {
|
||||
openDialogue(player, MountedCockatriceHeadOwnerDialogue())
|
||||
} else {
|
||||
val ownerName = Repository.players.first { it.houseManager == house }.username.capitalize()
|
||||
openDialogue(player, MountedCockatriceHeadGuestDialogue(ownerName))
|
||||
}
|
||||
return@on true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MountedCockatriceHeadOwnerDialogue : DialogueFile() {
|
||||
override fun handle(componentID: Int, buttonID: Int) {
|
||||
when (stage) {
|
||||
0 -> npcl(NPCs.COCKATRICE_4227, FacialExpression.CHILD_NORMAL, "You deaded me!").also { stage++ }
|
||||
1 -> playerl(FacialExpression.NEUTRAL, "Well, yes.").also { stage++ }
|
||||
2 -> npcl(NPCs.COCKATRICE_4227, FacialExpression.CHILD_NORMAL, "What did you do that for?").also { stage++ }
|
||||
3 -> options("A Slayer Master told me to.", "So I could mount your head on my wall.", "I just wanted to.").also { stage++ }
|
||||
4 -> when (buttonID) {
|
||||
1 -> playerl(FacialExpression.NEUTRAL, "A Slayer Master told me to.").also { stage = 10 }
|
||||
2 -> playerl(FacialExpression.NEUTRAL, "So I could mount your head on my wall.").also { stage = 20 }
|
||||
3 -> playerl(FacialExpression.NEUTRAL, "I just wanted to.").also { stage = 30 }
|
||||
}
|
||||
10 -> npcl(NPCs.COCKATRICE_4227, FacialExpression.CHILD_SAD, "Why do the Slayer Masters all pick on poor cockatrice?").also { stage++ }
|
||||
11 -> playerl(FacialExpression.NEUTRAL, "They pick on lots of other creatures too.").also { stage++ }
|
||||
12 -> npcl(NPCs.COCKATRICE_4227, FacialExpression.CHILD_SAD, "Then mount one of them on your wall and let poor cockatrice rest in peace!").also { stage = END_DIALOGUE }
|
||||
20 -> npcl(NPCs.COCKATRICE_4227, FacialExpression.CHILD_SAD, "Another cockatrice falls victim to the dreaded mirror shield!").also { stage++ }
|
||||
21 -> playerl(FacialExpression.NEUTRAL, "Don't take it personally. You look good on my wall.").also { stage++ }
|
||||
22 -> npcl(NPCs.COCKATRICE_4227, FacialExpression.CHILD_SAD, "I don't care! I think I looked better with a body!").also { stage = END_DIALOGUE }
|
||||
30 -> npcl(NPCs.COCKATRICE_4227, FacialExpression.CHILD_ANGRY, "You dirty rotten swine, you!").also { stage++ }
|
||||
31 -> playerl(FacialExpression.AMAZED, "Steady on.").also { stage++ }
|
||||
32 -> npcl(NPCs.COCKATRICE_4227, FacialExpression.CHILD_ANGRY, "I will kill you with my paralyzing-type magic eyes look!").also { stage++ }
|
||||
33 -> npcl(NPCs.COCKATRICE_4227, FacialExpression.CHILD_ANGRY, "Dots appear in air between eyes and victim. Dot! Dot! Dotty!").also { stage++ }
|
||||
34 -> playerl(FacialExpression.NEUTRAL, "Er, nothing's happening...").also { stage++ }
|
||||
35 -> npcl(NPCs.COCKATRICE_4227, FacialExpression.CHILD_ANGRY, "Concentrates mental power. Eyes narrow beak clenches veins on head stand out.").also { stage++ }
|
||||
36 -> npcl(NPCs.COCKATRICE_4227, FacialExpression.CHILD_ANGRY, "Strain!").also { stage++ }
|
||||
37 -> playerl(FacialExpression.ASKING, "You're dead, cockatrice. Your eyes are glass beads. It won't work.").also { stage++ }
|
||||
38 -> npcl(NPCs.COCKATRICE_4227, FacialExpression.CHILD_ANGRY, "STRA-A-AIN!").also { stage++ }
|
||||
39 -> playerl(FacialExpression.ASKING, "I think I'll leave you to it.").also { stage = END_DIALOGUE }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MountedCockatriceHeadGuestDialogue(private val ownerName: String) : DialogueFile() {
|
||||
override fun handle(componentID: Int, buttonID: Int) {
|
||||
when (stage) {
|
||||
0 -> playerl(FacialExpression.HAPPY, "Hey, a cockatrice!").also { stage++ }
|
||||
1 -> npcl(NPCs.COCKATRICE_4227, FacialExpression.CHILD_SAD, "$ownerName deaded me! That wasn't very nice!").also { stage = END_DIALOGUE }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import content.global.skill.crafting.jewellery.JewelleryCrafting;
|
|||
import core.game.interaction.NodeUsageEvent;
|
||||
import core.game.interaction.UseWithHandler;
|
||||
import core.plugin.Plugin;
|
||||
import org.rs09.consts.Scenery;
|
||||
|
||||
/**
|
||||
* Represents the plugin used to craft jewellery.
|
||||
|
|
@ -17,7 +18,12 @@ public final class JewelleryCraftPlugin extends UseWithHandler {
|
|||
/**
|
||||
* Represents the ids to use for this plugin.
|
||||
*/
|
||||
private static final int[] IDS = new int[] { 4304, 6189, 11010, 11666, 12100, 12809, 18497, 26814, 30021, 30510, 36956, 37651 };
|
||||
private static final int[] IDS = new int[]{
|
||||
Scenery.FURNACE_4304, Scenery.FURNACE_6189, Scenery.FURNACE_11010, Scenery.FURNACE_11666,
|
||||
Scenery.FURNACE_12100, Scenery.FURNACE_12809, Scenery.FURNACE_18497, Scenery.CLAY_FORGE_21303,
|
||||
Scenery.FURNACE_26814, Scenery.FURNACE_30021, Scenery.FURNACE_30510, Scenery.FURNACE_36956,
|
||||
Scenery.FURNACE_37651
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructs a new {@code JewelleryCraftPlugin} {@code Object}.
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ class LightSourceLighter : UseWithHandler(590,36,38){
|
|||
// For Temple of Ikov - if you are in the dark basement and light a light source, switch to the light basement.
|
||||
// For the listener that covers the firemaking cape perk, see content.global.skill.skillcapeperks.SkillcapePerks.kt
|
||||
if(event.player.location.isInRegion(10648) && event.player.location.withinDistance(Location(2639,9738,0), 8)) {
|
||||
teleport(event.player, Location.create(event.player.getLocation().getX(), event.player.getLocation().getY() + 23, event.player.getLocation().getZ()))
|
||||
teleport(event.player, Location.create(event.player.getLocation().x, event.player.getLocation().y + 23, event.player.getLocation().z))
|
||||
closeDialogue(event.player)
|
||||
// Dark basement is region 10648, min 2639 9738 0, max 2643 9744 0. Add 23 to the Y loc to tele to light basement
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ class SilverCraftingListener : InterfaceListener, InteractionListener {
|
|||
Scenery.FURNACE_12100, Scenery.FURNACE_12809, Scenery.FURNACE_18497, Scenery.FURNACE_18525,
|
||||
Scenery.FURNACE_18526, Scenery.FURNACE_21879, Scenery.FURNACE_22721, Scenery.FURNACE_26814,
|
||||
Scenery.FURNACE_28433, Scenery.FURNACE_28434, Scenery.FURNACE_30021, Scenery.FURNACE_30510,
|
||||
Scenery.FURNACE_36956, Scenery.FURNACE_37651
|
||||
Scenery.FURNACE_36956, Scenery.FURNACE_37651, Scenery.CLAY_FORGE_21303
|
||||
)
|
||||
|
||||
private const val ATTRIBUTE_FURNACE_ID = "crafting:silver:furnace_id"
|
||||
|
|
|
|||
|
|
@ -270,7 +270,7 @@ class WoodcuttingListener : InteractionListener {
|
|||
var amount = amount
|
||||
var experience: Double = resource.getExperience()
|
||||
val reward = resource.reward
|
||||
if (player.getLocation().getRegionId() == 10300) {
|
||||
if (player.getLocation().regionId == 10300) {
|
||||
return 1.0
|
||||
}
|
||||
|
||||
|
|
|
|||
25
Server/src/main/content/global/skill/hunter/NetTrapNode.kt
Normal file
25
Server/src/main/content/global/skill/hunter/NetTrapNode.kt
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
package content.global.skill.hunter
|
||||
|
||||
import core.api.getStatLevel
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.skill.Skills
|
||||
import core.game.node.item.Item
|
||||
|
||||
/**
|
||||
* Handles the net trap node.
|
||||
*/
|
||||
class NetTrapNode(
|
||||
npcIds: IntArray,
|
||||
level: Int,
|
||||
experience: Double,
|
||||
rewards: Array<Item>,
|
||||
private val summoningLevel: Int
|
||||
) : TrapNode(npcIds, level, experience, intArrayOf(), rewards) {
|
||||
|
||||
override fun canCatch(wrapper: TrapWrapper, npc: NPC): Boolean {
|
||||
if (getStatLevel(wrapper.player, Skills.SUMMONING) < summoningLevel) {
|
||||
return false
|
||||
}
|
||||
return super.canCatch(wrapper, npc)
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,8 @@ import core.tools.Log;
|
|||
import core.tools.SystemLogger;
|
||||
import core.game.world.map.Location;
|
||||
import core.game.world.update.flag.context.Animation;
|
||||
import org.rs09.consts.Items;
|
||||
import org.rs09.consts.NPCs;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
|
@ -33,16 +35,30 @@ public enum Traps {
|
|||
}
|
||||
}),
|
||||
BOX_TRAP(new TrapSetting(10008, new int[] { 19187 }, new int[] { 1963, 12579, 1869, 9996, 5972, 12535 }, "lay", 19192, Animation.create(5208), new Animation(9726), 27),
|
||||
new BoxTrapNode(new int[] { 5081 }, 27, 100, new Item[] { new Item(10092) }, 1),
|
||||
new BoxTrapNode(new int[] { 6918, 7289, 7290, 7291, 7292 }, 27, 100, new Item[] { new Item(12184) }, 10),
|
||||
new BoxTrapNode(new int[] { 1487 }, 27, 100, new Item[] { new Item(4033, 1) }, 95),
|
||||
new BoxTrapNode(new int[] { 7021, 7022, 7023 }, 48, 150, new Item[] { new Item(12551, 1) }, 1),
|
||||
new BoxTrapNode(new int[] { 5079 }, 53, 198, new Item[] { new Item(10033, 1) }, 1),
|
||||
new BoxTrapNode(new int[] { 5428, 5430, 5449, 5450, 5451 }, 56, 150, new Item[] { new Item(12188) }, 1),
|
||||
new BoxTrapNode(new int[] { 5080 }, 63, 265, new Item[] { new Item(10034, 1) }, 1),
|
||||
new BoxTrapNode(new int[] { 7012, 7014 }, 66, 400, new Item[] { new Item(12535) }, 1),
|
||||
new BoxTrapNode(new int[] { 8654 }, 73, 315, new Item[] { new Item(14861) }, 1),
|
||||
new BoxTrapNode(new int[] { 7010, 7011 }, 77, 0, new Item[] { new Item(12539, 1) }, 1) {
|
||||
new BoxTrapNode(new int[] { 5081 }, 27, 100, new Item[] { new Item(10092) }, 1), // Ferret
|
||||
new BoxTrapNode(new int[] {NPCs.BABY_GECKO_6917 }, 27, 100, new Item[] { new Item(Items.BABY_GECKO_12488) }, 10), // Gecko Orange
|
||||
new BoxTrapNode(new int[] {NPCs.BABY_GECKO_7285 }, 27, 100, new Item[] { new Item(Items.BABY_GECKO_12738) }, 10), // Gecko Speckled
|
||||
new BoxTrapNode(new int[] {NPCs.BABY_GECKO_7286 }, 27, 100, new Item[] { new Item(Items.BABY_GECKO_12739) }, 10), // Gecko Green
|
||||
new BoxTrapNode(new int[] {NPCs.BABY_GECKO_7287 }, 27, 100, new Item[] { new Item(Items.BABY_GECKO_12740) }, 10), // Gecko Blue
|
||||
new BoxTrapNode(new int[] {NPCs.BABY_GECKO_7288 }, 27, 100, new Item[] { new Item(Items.BABY_GECKO_12741) }, 10), // Gecko Red
|
||||
new BoxTrapNode(new int[] {NPCs.BABY_RACCOON_6997 }, 27, 100, new Item[] { new Item(Items.BABY_RACCOON_12486) }, 80), // Raccoon Gray
|
||||
new BoxTrapNode(new int[] {NPCs.BABY_RACCOON_7275 }, 27, 100, new Item[] { new Item(Items.BABY_RACCOON_12734) }, 80), // Raccoon Tan
|
||||
new BoxTrapNode(new int[] {NPCs.BABY_RACCOON_7276 }, 27, 100, new Item[] { new Item(Items.BABY_RACCOON_12736) }, 80), // Raccoon Red
|
||||
new BoxTrapNode(new int[] { NPCs.BABY_MONKEY_6944 }, 27, 100, new Item[] { new Item(Items.BABY_MONKEY_12496) }, 95), // Monkey
|
||||
new BoxTrapNode(new int[] { NPCs.BABY_MONKEY_7228 }, 27, 100, new Item[] { new Item(Items.BABY_MONKEY_12682) }, 95), // Monkey
|
||||
new BoxTrapNode(new int[] { NPCs.BABY_MONKEY_7229 }, 27, 100, new Item[] { new Item(Items.BABY_MONKEY_12684) }, 95), // Monkey
|
||||
new BoxTrapNode(new int[] { NPCs.BABY_MONKEY_7230 }, 27, 100, new Item[] { new Item(Items.BABY_MONKEY_12686) }, 95), // Monkey
|
||||
new BoxTrapNode(new int[] { NPCs.BABY_MONKEY_7231 }, 27, 100, new Item[] { new Item(Items.BABY_MONKEY_12688) }, 95), // Monkey
|
||||
new BoxTrapNode(new int[] { NPCs.BABY_MONKEY_7232 }, 27, 100, new Item[] { new Item(Items.BABY_MONKEY_12690) }, 95), // Monkey
|
||||
new BoxTrapNode(new int[] { NPCs.BABY_MONKEY_7233 }, 27, 100, new Item[] { new Item(Items.BABY_MONKEY_12692) }, 95), // Monkey
|
||||
new BoxTrapNode(new int[] { NPCs.BABY_MONKEY_7234 }, 27, 100, new Item[] { new Item(Items.BABY_MONKEY_12694) }, 95), // Monkey
|
||||
new BoxTrapNode(new int[] { NPCs.BABY_MONKEY_7235 }, 27, 100, new Item[] { new Item(Items.BABY_MONKEY_12696) }, 95), // Monkey
|
||||
new BoxTrapNode(new int[] { NPCs.BABY_MONKEY_7236 }, 27, 100, new Item[] { new Item(Items.BABY_MONKEY_12698) }, 95), // Monkey
|
||||
new BoxTrapNode(new int[] { 7021, 7022, 7023 }, 48, 150, new Item[] { new Item(12551, 1) }, 1), // Platypus
|
||||
new BoxTrapNode(new int[] { 5079 }, 53, 198, new Item[] { new Item(10033, 1) }, 1), // Chinchompa
|
||||
new BoxTrapNode(new int[] { 5080 }, 63, 265, new Item[] { new Item(10034, 1) }, 1), // Red Chinchompa
|
||||
new BoxTrapNode(new int[] { 7012, 7014 }, 66, 400, new Item[] { new Item(12535) }, 1), // Pawya
|
||||
new BoxTrapNode(new int[] { 7010, 7011 }, 77, 0, new Item[] { new Item(12539, 1) }, 1) { // Grenwall
|
||||
@Override
|
||||
public boolean canCatch(TrapWrapper wrapper, final NPC npc) {
|
||||
//old xp: 726
|
||||
|
|
@ -59,11 +75,16 @@ public enum Traps {
|
|||
new TrapNode(new int[] { 5086 }, 37, 204, new int[] { 19208, 19208, 19217 }, new Item[] { new Item(10105), new Item(526) }),
|
||||
new TrapNode(new int[] { 7039 }, 44, 200, new int[] { 28939, 28940, 28941 }, new Item[] { new Item(12567), new Item(526) }),
|
||||
new TrapNode(new int[] { 5087 }, 51, 200, new int[] { 19209, 19210, 19216 }, new Item[] { new Item(10109), new Item(526) })),
|
||||
NET_TRAP(new NetTrapSetting(), new TrapNode(new int[] { 5117 }, 29, 152, new int[] {}, new Item[] { new Item(10149) }),
|
||||
new TrapNode(new int[] { 5114 }, 47, 224, new int[] {}, new Item[] { new Item(10146) }),
|
||||
new TrapNode(new int[] { 6921 }, 29, 152, new int[] {}, new Item[] { new Item(12130) }),
|
||||
new TrapNode(new int[] { 5115 }, 59, 272, new int[] {}, new Item[] { new Item(10147) }),
|
||||
new TrapNode(new int[] { 5116 }, 67, 304, new int[] {}, new Item[] { new Item(10148) }));
|
||||
NET_TRAP(new NetTrapSetting(),
|
||||
new NetTrapNode(new int[] { 5117 }, 29, 152, new Item[] { new Item(10149) }, 1), // Swamp Lizard
|
||||
new NetTrapNode(new int[] { 5114 }, 47, 224, new Item[] { new Item(10146) }, 1), // Orange Salamander
|
||||
new NetTrapNode(new int[] { NPCs.BABY_SQUIRREL_6921 }, 29, 152, new Item[] { new Item(Items.BABY_SQUIRREL_12490) }, 60), // Squirrel Gray
|
||||
new NetTrapNode(new int[] { NPCs.BABY_SQUIRREL_7309 }, 29, 152, new Item[] { new Item(Items.BABY_SQUIRREL_12754) }, 60), // Squirrel Tan
|
||||
new NetTrapNode(new int[] { NPCs.BABY_SQUIRREL_7310 }, 29, 152, new Item[] { new Item(Items.BABY_SQUIRREL_12756) }, 60), // Squirrel White
|
||||
new NetTrapNode(new int[] { NPCs.BABY_SQUIRREL_7311 }, 29, 152, new Item[] { new Item(Items.BABY_SQUIRREL_12758) }, 60), // Squirrel Grayish/Brown w/e
|
||||
new NetTrapNode(new int[] { NPCs.BABY_SQUIRREL_7312 }, 29, 152, new Item[] { new Item(Items.BABY_SQUIRREL_12760) }, 60), // Squirrel Brown
|
||||
new NetTrapNode(new int[] { 5115 }, 59, 272, new Item[] { new Item(10147) }, 1), // Red Salamander
|
||||
new NetTrapNode(new int[] { 5116 }, 67, 304, new Item[] { new Item(10148) }, 1)); // Black Salamander
|
||||
|
||||
/**
|
||||
* The location hooks for this node.
|
||||
|
|
|
|||
|
|
@ -37,6 +37,10 @@ import org.rs09.consts.Items
|
|||
import org.rs09.consts.Sounds
|
||||
import kotlin.math.floor
|
||||
|
||||
private const val DREAM_HEAL_INTERVAL_TICKS = 50
|
||||
private const val DREAM_HARD_RESET_INTERVAL_TICKS = 90
|
||||
private const val DREAM_HARD_RESET_DELAY_TICKS = 0
|
||||
|
||||
class LunarListeners : SpellListener("lunar"), Commands {
|
||||
|
||||
override fun defineListeners() {
|
||||
|
|
@ -592,32 +596,46 @@ class LunarListeners : SpellListener("lunar"), Commands {
|
|||
|
||||
// Level 79
|
||||
private fun dream(player: Player) {
|
||||
if(player.skills.lifepoints >= getStatLevel(player, Skills.HITPOINTS)) {
|
||||
if (player.skills.lifepoints >= getStatLevel(player, Skills.HITPOINTS)) {
|
||||
sendMessage(player, "You have no need to cast this spell since your hitpoints are already full.")
|
||||
throw IllegalStateException()
|
||||
}
|
||||
|
||||
// https://runescape.wiki/w/Dream?oldid=880976 claims Dream makes you heal 1 hp every 20 seconds
|
||||
// https://oldschool.runescape.wiki/w/Dream claims that Dream has its own timer, so the Dream heals don't need
|
||||
// to align with the natural heals
|
||||
val timer = getOrStartTimer<SkillRestore>(player)
|
||||
val dreamStartAnimationTicks = animationDuration(Animation(Animations.LUNAR_SPELLBOOK_DREAM_START_6295))
|
||||
var nextHealTick = getWorldTicks() + dreamStartAnimationTicks + DREAM_HEAL_INTERVAL_TICKS
|
||||
var nextHardResetTick = -1
|
||||
var waitingForHardReset = false
|
||||
animate(player, Animations.LUNAR_SPELLBOOK_DREAM_START_6295)
|
||||
removeRunes(player, true)
|
||||
addXP(player, 82.0)
|
||||
delayEntity(player, 4)
|
||||
queueScript(player, 4, QueueStrength.WEAK) { stage: Int ->
|
||||
delayEntity(player, dreamStartAnimationTicks)
|
||||
queueScript(player, dreamStartAnimationTicks, QueueStrength.WEAK) { stage: Int ->
|
||||
if (stage == 0) {
|
||||
sendGraphics(Graphics.LUNAR_SPELLBOOK_DREAM_1056, player.location)
|
||||
playAudio(player, Sounds.LUNAR_SLEEP_3619)
|
||||
return@queueScript delayScript(player, 5)
|
||||
}
|
||||
if (waitingForHardReset) {
|
||||
waitingForHardReset = false
|
||||
nextHardResetTick = getWorldTicks() + DREAM_HARD_RESET_INTERVAL_TICKS
|
||||
} else if (nextHardResetTick != -1 && getWorldTicks() >= nextHardResetTick) {
|
||||
// The 530 client eventually drops Dream back to idle if it only sees repeated 6296 updates
|
||||
// Sending an explicit reset makes the next 6296 a full restart instead of a same-sequence refresh
|
||||
resetAnimator(player)
|
||||
waitingForHardReset = true
|
||||
return@queueScript delayScript(player, DREAM_HARD_RESET_DELAY_TICKS)
|
||||
} else if (nextHardResetTick == -1) {
|
||||
nextHardResetTick = getWorldTicks() + DREAM_HARD_RESET_INTERVAL_TICKS
|
||||
}
|
||||
animate(player, Animations.LUNAR_SPELLBOOK_DREAM_MID_6296)
|
||||
sendGraphics(Graphics.LUNAR_SPELLBOOK_DREAM_1056, player.location)
|
||||
// This heals 2 HP every min. Naturally you heal 1 for a total of 3
|
||||
// The script steps every 5 ticks and we want 50 ticks before a heal
|
||||
if (stage.mod(10) == 0) {
|
||||
if (getWorldTicks() >= nextHealTick) {
|
||||
val amt = timer.getHealAmount(player) //accounts for regen brace
|
||||
heal(player, amt)
|
||||
nextHealTick += DREAM_HEAL_INTERVAL_TICKS
|
||||
if (player.skills.lifepoints >= getStatLevel(player, Skills.HITPOINTS)) {
|
||||
animate(player, Animations.LUNAR_SPELLBOOK_DREAM_END_6297)
|
||||
return@queueScript stopExecuting(player)
|
||||
|
|
@ -874,4 +892,3 @@ class LunarListeners : SpellListener("lunar"), Commands {
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ enum class SkillcapePerks(val attribute: String, val effect: ((Player) -> Unit)?
|
|||
// For Temple of Ikov - if you are in the dark basement and put on the firemaking cape with its 2009Scape light source perk, switch to the light basement.
|
||||
// For the listener that teleports if you light a normal light source, see content.global.skill.crafting.lightsources.LightSourceLighter.kt
|
||||
if(player.location.isInRegion(10648) && player.location.withinDistance(Location(2639,9738,0), 8)) {
|
||||
teleport(player, Location.create(player.getLocation().getX(), player.getLocation().getY() + 23, player.getLocation().getZ()))
|
||||
teleport(player, Location.create(player.getLocation().x, player.getLocation().y + 23, player.getLocation().z))
|
||||
closeDialogue(player)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ public enum Tasks {
|
|||
ABERRANT_SPECTRES(65, new int[] { 1604, 1605, 1606, 1607, 7801, 7802, 7803, 7804 }, new String[] { "Aberrant Spectres are fetid, vile ghosts. The very", "smell of them will paralyse and harm you. A nose peg", "will help ignore their stink." }, 60, true, false),
|
||||
ABYSSAL_DEMONS(85, new int[] { 1615 }, new String[] { "Abyssal Demons are nasty creatures to fight. They", "aren't really part of this realm, and are able to", "move very quickly to trap their prey."}, 85, false, false),
|
||||
ANKOU(40, new int[] { 4381, 4382, 4383 }, new String[] { "Ankou are undead skeletal ghosts. They'll fight you", "up close but make sure to take advantage out of their", "limited defence." }, 1, true, false),
|
||||
AVIANSIES(60, new int[] { 6245, 6243, 6235, 6232, 6244, 6246, 6233, 6241, 6238, 6237, 6240, 6242, 6239, 6234 }, new String[] { "Aviansies are bird-like creatures found in the icy", "dungeons of the north. Melee weapons can't reach them,", "so use Magic or Ranged attacks." }, 1, false, false),
|
||||
BANSHEE(20, new int[] { 1612 }, new String[] { "Banshees use a piercing scream to shock their enemies.", "You'll need some earmuffs to protect yourself from them." }, 15, true, false),
|
||||
BASILISKS(40, new int[] { 1616, 1617 }, new String[] { "Basilisks, like Cockatrice, have a gaze which will", "paralyse and harm their prey. You'll need a Mirror", "Shield to protect you." }, 40, false, false),
|
||||
BATS(5, new int[] { 412, 78, 3711 }, new String[] { "Bats are rarely found on the ground, so you'll have", "to fight them while they're airborne, which won't be", "easy for melee." }, 1, false, false),
|
||||
|
|
@ -107,12 +106,10 @@ public enum Tasks {
|
|||
SPIRTUAL_WARRIORS(60, new int[] { 6219, 6229, 6255, 6277, }, new String[] { "Spiritual warriors can be found in the icy caverns near", "Trollheim, supporting the cause of their chosen god." }, 68, Quests.DEATH_PLATEAU),
|
||||
STEEL_DRAGONS( 85,new int[] { 1592, 3590 }, new String[] { "Steel dragons are dangerous and metallic, with steel", "scales that are far thicker than normal steel armour. As", "you are an accomplished slayer, I am sure you'll be", "able to deal with them easily."}, 1, false, true),
|
||||
SUQAHS (65, new int[] { 4527, 4528, 4529, 4530, 4531, 4532, 4533 }, new String[] { "Suqahs can only be found on the mystical Lunar Isle.", "They are capable of melee and magic attacks and often", "drop hide, teeth and herbs!" }, 1, Quests.LUNAR_DIPLOMACY),
|
||||
// No access to Lair of Tarn Razorlor but this should be added as a task when there is access
|
||||
TERROR_DOGS(1, new int[] { 5417, 5418 }, new String[] { "Terror dogs are the personal pets of Tarn Razorlor.", "Wherever you find him, you will find them. They are", "bad-tempered and generally unfriendly." }, 40, Quests.HAUNTED_MINE),
|
||||
TROLLS(60, new int[] { 72, 3584, 1098, 1096, 1097, 1095, 1101, 1105, 1102, 1103, 1104, 1130, 1131, 1132, 1133, 1134, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1138, 1560, 1561, 1562, 1563, 1564, 1565, 1566, 1935, 1936, 1937, 1938, 1939, 1940, 1941, 1942, 3840, 3841, 3842, 3843, 3845, 1933, 1934, 1115, 1116, 1117, 1118, 1119, 1120, 1121, 1122, 1123, 1124, 391, 392, 393, 394, 395, 396}, new String[] { "Trolls regenerate damage quickly but are still", "vulnerable to poisons, they usually use crushing", "weapons." }, 1, false, false),
|
||||
TUROTHS(60, new int[] { 1622, 1611, 1623, 1626, 1627, 1628, 1629, 1630, 7800}, new String[] { "Turoth are large vicious creatures with thick hides.", "You'll need a Leaf-Tipped Spear Sword or Battle-axe,", "Broad Arrows, or a Magic Dart to harm them." }, 55, false, false),
|
||||
VAMPIRES(35, new int[] { 1220, 1223, 1225, 6214 }, new String[] { "Vampires are extremely powerful beings. They feed on", "the blood of the living so watch out you don't", "get bitten." }, 1, false, false),
|
||||
// Waiting for the wall beast movement bug to be fixed before adding this as a task
|
||||
WALL_BEASTS(1, new int[] { 7823 }, new String[] { "Wall Beasts are really much larger creatures but", "you'll only see their arms. You'll want something", "sharp on your head to stop them grabbing you." }, 35, false, false ),
|
||||
// No way to get to Poison Swamp Cave
|
||||
// If a grapple is implemented from W Castle Wars to E Posion Swamps
|
||||
|
|
@ -124,15 +121,6 @@ public enum Tasks {
|
|||
WEREWOLVES(60, new int[] { 6006, 6007, 6008, 6009, 6010, 6011, 6012, 6013, 6014, 6015, 6016, 6017, 6018, 6019, 6020, 6021, 6022, 6023, 6024, 6025, 6212, 6213, 6607, 6609, 6614, 6617, 6625, 6632, 6644, 6663, 6675, 6686, 6701, 6712, 6724, 6728, }, new String[] { "Werewolves are feral creatures, they are strong and", "tough with sharp claws and teeth." }, 1, false, false),
|
||||
WOLVES(20, new int[] { 95, 96, 97, 141, 142, 143, 839, 1198, 1330, 1558, 1559, 1951, 1952, 1953, 1954, 1955, 1956, 4413, 4414, 6046, 6047, 6048, 6049, 6050, 6051, 6052, 6829, 6830, 7005 }, new String[] { "Wolves are pack animals, so you'll always find them", "in groups. Watch out for their bite, it can be nasty." }, 1, false, false),
|
||||
ZOMBIES(10, new int[] { 73, 74, 75, 76, 2060, 2714, 2863, 2866, 2869, 2878, 3622, 4392, 4393, 4394, 5293, 5294, 5295, 5296, 5297, 5298, 5299, 5300, 5301, 5302, 5303, 5304, 5305, 5306, 5307, 5308, 5309, 5310, 5311, 5312, 5313, 5314, 5315, 5316, 5317, 5318, 5319, 5320, 5321, 5322, 5323, 5324, 5325, 5326, 5327, 5328, 5329, 5330, 5331, 5375, 5376, 5377, 5378, 5379, 5380, 5393, 5394, 5395, 5396, 5397, 5398, 5399, 5400, 5401, 5402, 5403, 5404, 5405, 5406, 5407, 5408, 5409, 5410, 6099, 6100, 6131, 8149, 8150, 8151, 8152, 8153, 8159, 8160, 8161, 8162, 8163, 8164, 2044, 2045, 2046, 2047, 2048, 2049, 2050, 2051, 2052, 2053, 2054, 2055, 7641, 1465, 1466, 1467, 2837, 2838, 2839, 2840, 2841, 2842, 5629, 5630, 5631, 5632, 5633, 5634, 5635, 5636, 5637, 5638, 5639, 5640, 5641, 5642, 5643, 5644, 5645, 5646, 5647, 5648, 5649, 5650, 5651, 5652, 5653, 5654, 5655, 5656, 5657, 5658, 5659, 5660, 5661, 5662, 5663, 5664, 5665, 2843, 2844, 2845, 2846, 2847, 2848}, new String[] { "Zombies are undead so magic is your best bet against", "them, there is even a spell specially for", "fighting the undead." }, 1, true, false),
|
||||
// Bosses need to be handled differently/have a source. They should probably be removed from here
|
||||
JAD(90, new int[] { }, new String[] { "You must complete the entire fight cave, including", "TzTok-Jad. Beware, only those skilled in combat should", "attempt this and death will reset your task." }, 1, false, false),
|
||||
CHAOS_ELEMENTAL(90, new int[] { 3200 }, new String[] { "The Chaos Elemental roams the deepest Wilderness. It", "can teleport you and make you unequip items randomly." }, 1, false, false),
|
||||
GIANT_MOLE(75, new int[] { 3340 }, new String[] { "Dig on the mole-hills in Falador Park to enter the", "mole cave, and bring a lantern he can't extinguish." }, 1, false, false),
|
||||
KING_BLACK_DRAGON(75, new int[] { 50 }, new String[] { "The King Black Dragon's cave is reached by pulling a", "lever in the Wilderness. An anti-fire shield is", "strongly recommended." }, 1, false, true),
|
||||
COMMANDER_ZILYANA(90, new int[] { 6247 }, new String[] { "Commander Zilyana is in the God Wars Dungeon.", "She frequently uses magic attacks." }, 1, false, false),
|
||||
GENERAL_GRARDOOR(90, new int[] { 6260 }, new String[] { "General Graardor is in the God Wars Dungeon.", "He uses melee and ranged attacks." }, 1, false, false),
|
||||
KRIL_TSUTSAROTH(90, new int[] { 6203 }, new String[] { "K'ril Tsutsaroth is in the God Wars Dungeon.", "He's poisonous and he can hit through prayers." }, 1, false, false),
|
||||
KREE_ARRA(90, new int[] { 6222 }, new String[] { "Kree'arra roosts in the God Wars Dungeon.", "Melee attacks don't work on flying creatures,", "and you'll need a grappling hook to get in." }, 1, false, false),
|
||||
;
|
||||
|
||||
static final HashMap<Integer, Tasks> taskMap = new HashMap<>();
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ public enum SmithingType {
|
|||
/**
|
||||
* Grapple Tips
|
||||
*/
|
||||
TYPE_GRAPPLE_TIP(1, 170, 171, new int[] { 175, 176, 175, 174, 173 }, 1),
|
||||
TYPE_GRAPPLE_TIP(1, 170, 171, new int[] { 176, 175, 174, 173 }, 1),
|
||||
|
||||
/**
|
||||
* The studs type.
|
||||
|
|
|
|||
|
|
@ -82,6 +82,8 @@ public abstract class Familiar extends NPC implements Plugin<Object> {
|
|||
* The amount of special points left.
|
||||
*/
|
||||
protected int specialPoints = 60;
|
||||
|
||||
public static final String INFINITE_SPECIAL_MOVE_ATTRIBUTE = "infinite-special-move";
|
||||
|
||||
/**
|
||||
* The pouch id.
|
||||
|
|
@ -494,7 +496,9 @@ public abstract class Familiar extends NPC implements Plugin<Object> {
|
|||
owner.getInventory().remove(new Item(scroll.getItemId()));
|
||||
playAudio(owner, Sounds.SPELL_4161);
|
||||
visualizeSpecialMove();
|
||||
updateSpecialPoints(specialCost);
|
||||
if (!owner.getAttribute(INFINITE_SPECIAL_MOVE_ATTRIBUTE, false)) {
|
||||
updateSpecialPoints(specialCost);
|
||||
}
|
||||
owner.getSkills().addExperience(Skills.SUMMONING, scroll.getExperience(), true);
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package content.global.skill.summoning.familiar;
|
||||
|
||||
import content.data.Quests;
|
||||
import content.global.skill.summoning.pet.Pet;
|
||||
import content.global.skill.summoning.pet.Pets;
|
||||
import core.cache.def.impl.ItemDefinition;
|
||||
|
|
@ -31,6 +32,15 @@ import static core.api.ContentAPIKt.*;
|
|||
*/
|
||||
public final class FamiliarManager {
|
||||
|
||||
/**
|
||||
* These varbits are packed into varp 1160. Legacy code added 243269632 directly to the raw varp,
|
||||
* which toggled the Summoning orb visibility on every login.
|
||||
* They are now written as individual varbits, but two of them remain unknown.
|
||||
*/
|
||||
private static final int VARBIT_SUMMONING_ORB_VISIBILITY = 4280;
|
||||
private static final int VARBIT_SUMMONING_UNKNOWN1 = 4281;
|
||||
private static final int VARBIT_SUMMONING_UNKNOWN2 = 4282;
|
||||
|
||||
/**
|
||||
* The familiars mapping.
|
||||
*/
|
||||
|
|
@ -158,7 +168,11 @@ public final class FamiliarManager {
|
|||
if (hasFamiliar()) {
|
||||
familiar.init();
|
||||
}
|
||||
player.getFamiliarManager().setConfig(243269632);
|
||||
boolean unlocked = player.getQuestRepository().isComplete(Quests.WOLF_WHISTLE);
|
||||
|
||||
setVarbit(player, VARBIT_SUMMONING_ORB_VISIBILITY, unlocked ? 1 : 0);
|
||||
setVarbit(player, VARBIT_SUMMONING_UNKNOWN1, 0);
|
||||
setVarbit(player, VARBIT_SUMMONING_UNKNOWN2, 7);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -456,16 +470,6 @@ public final class FamiliarManager {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a config value.
|
||||
* @param value the value.
|
||||
*/
|
||||
public void setConfig(int value) {
|
||||
int current = getVarp(player, 1160);
|
||||
int newVal = current + value;
|
||||
setVarp(player, 1160, newVal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the familiar.
|
||||
* @return The familiar.
|
||||
|
|
|
|||
|
|
@ -151,7 +151,6 @@ public final class BarrowsActivityPlugin extends ActivityPlugin {
|
|||
Player player = (Player) e;
|
||||
PacketRepository.send(MinimapState.class, new MinimapStateContext(player, 2));
|
||||
player.getInterfaceManager().openOverlay(OVERLAY);
|
||||
setVarp(player, 0, 1);
|
||||
if (getVarp(player, 452) == 0) {
|
||||
shuffleCatacombs(player);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ object RewardChest {
|
|||
|
||||
InterfaceContainer.generateItems(player, rewards.toTypedArray(), arrayOf("Examine"), 364, 4, 3, 4)
|
||||
player.interfaceManager.open(Component(Components.TRAIL_REWARD_364))
|
||||
BossKillCounter.addtoBarrowsCount(player)
|
||||
BossKillCounter.addToBarrowsChestCount(player)
|
||||
for (item in rewards) {
|
||||
announceIfRare(player, item)
|
||||
if (!player.inventory.add(item)) {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
package content.region.asgarnia.burthorpe.quest.deathplateau
|
||||
|
||||
import content.data.Quests
|
||||
import content.global.handlers.iface.ScrollInterface
|
||||
import core.api.*
|
||||
import core.game.global.action.DoorActionHandler
|
||||
import core.game.interaction.IntType
|
||||
import core.game.interaction.InteractionListener
|
||||
import core.game.node.item.GroundItemManager
|
||||
import org.rs09.consts.Components
|
||||
import org.rs09.consts.Items
|
||||
import org.rs09.consts.Scenery
|
||||
|
||||
|
|
@ -23,6 +25,11 @@ class DeathPlateauInteractionListener : InteractionListener {
|
|||
Scenery.STONE_MECHANISM_3676, // 4 Outer stone plates
|
||||
Scenery.STONE_MECHANISM_3677 // 2 Inner stone plates
|
||||
)
|
||||
val combinationScroll = arrayOf(
|
||||
"Red is North of Blue. Yellow is South of Purple.",
|
||||
"Green is North of Purple. Blue is West of",
|
||||
"Yellow. Purple is East of Red."
|
||||
)
|
||||
}
|
||||
override fun defineListeners() {
|
||||
on(Scenery.DOOR_3747, SCENERY, "open") { player, node ->
|
||||
|
|
@ -48,10 +55,10 @@ class DeathPlateauInteractionListener : InteractionListener {
|
|||
}
|
||||
|
||||
on(Items.COMBINATION_3102, ITEM, "read") { player, _ ->
|
||||
openInterface(player, 220)
|
||||
setInterfaceText(player, "<col=3D1E00>Red is North of Blue. Yellow is South of Purple.", 220, 7)
|
||||
setInterfaceText(player, "<col=3D1E00>Green is North of Purple. Blue is West of", 220, 8)
|
||||
setInterfaceText(player, "<col=3D1E00>Yellow. Purple is East of Red.", 220, 9)
|
||||
// https://youtu.be/C8n8Yi-J8wU?t=466
|
||||
openInterface(player, 222)
|
||||
setInterfaceText(player, combinationScroll.joinToString("<br>"), 222, 5)
|
||||
|
||||
return@on true
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@ import content.data.Quests
|
|||
import core.api.*
|
||||
import core.game.dialogue.DialogueFile
|
||||
import core.game.dialogue.FacialExpression
|
||||
import core.game.interaction.IntType
|
||||
import core.game.interaction.InteractionListeners
|
||||
import core.game.node.item.Item
|
||||
import core.tools.END_DIALOGUE
|
||||
import org.rs09.consts.Items
|
||||
|
||||
|
|
@ -26,10 +29,7 @@ class IOUNoteDialogueFile : DialogueFile() {
|
|||
4 -> {
|
||||
end()
|
||||
stage = END_DIALOGUE
|
||||
openInterface(player!!, 220)
|
||||
setInterfaceText(player!!, "<col=3D1E00>Red is North of Blue. Yellow is South of Purple.", 220, 7)
|
||||
setInterfaceText(player!!, "<col=3D1E00>Green is North of Purple. Blue is West of", 220, 8)
|
||||
setInterfaceText(player!!, "<col=3D1E00>Yellow. Purple is East of Red.", 220, 9)
|
||||
InteractionListeners.run(Items.COMBINATION_3102, IntType.ITEM, "read", player!!, Item(Items.COMBINATION_3102))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -299,7 +299,7 @@ public final class GiantMoleNPC extends AbstractNPC {
|
|||
super.finalizeDeath(killer);
|
||||
if (killer instanceof Player) {
|
||||
Player player = killer.asPlayer();
|
||||
BossKillCounter.addtoKillcount(player, this.getId());
|
||||
BossKillCounter.addToBossKillCount(player, this.getId());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import core.game.world.update.flag.context.Animation
|
|||
import core.game.world.update.flag.context.Graphics
|
||||
import core.plugin.Initializable
|
||||
import core.tools.RandomFunction
|
||||
import core.tools.colorize
|
||||
import org.rs09.consts.Items
|
||||
import org.rs09.consts.NPCs
|
||||
import org.rs09.consts.Scenery
|
||||
|
|
@ -119,9 +120,8 @@ class MudSkipperPointListeners : InteractionListener {
|
|||
}
|
||||
|
||||
on(Scenery.SIGNPOST_10090, IntType.SCENERY, "read") { player, _ ->
|
||||
setInterfaceText(player, "Mudskipper Point.", 220, 2)
|
||||
setInterfaceText(player, "WARNING! BEWARE OF THE MUDSKIPPERS!", 220, 4)
|
||||
openInterface(player, 220)
|
||||
// https://runescape.wiki/w/Mudskipper_Point?oldid=969991
|
||||
sendDialogue(player, colorize("%RBEWARE OF THE MUDSKIPPERS!"))
|
||||
return@on true
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,11 @@ public class WolfWhistle extends Quest {
|
|||
*/
|
||||
public static final Item WOLF_BONES = new Item(2859, 2);
|
||||
|
||||
/**
|
||||
* Gates the visibility of the Summoning orb next to the minimap behind quest completion.
|
||||
*/
|
||||
private static final int VARBIT_SUMMONING_ORB_VISIBILITY = 4280;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code WolfWhistle} {@code Object}.
|
||||
*/
|
||||
|
|
@ -164,6 +169,7 @@ public class WolfWhistle extends Quest {
|
|||
player.getSkills().addExperience(Skills.SUMMONING, 276);
|
||||
player.getInventory().add(new Item(12158, 275), player);
|
||||
player.removeAttribute("searched-body");
|
||||
setVarbit(player, VARBIT_SUMMONING_ORB_VISIBILITY, 1);
|
||||
player.getQuestRepository().syncronizeTab(player);
|
||||
player.getInterfaceManager().openInfoBars();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -202,7 +202,7 @@ public final class TrollheimPlugin extends OptionHandler {
|
|||
switch (id) {
|
||||
case 32738:
|
||||
if (loc.equals(new Location(2892, 10072, 0))) {
|
||||
player.getProperties().setTeleportLocation(LOCATIONS[0]);
|
||||
player.getProperties().setTeleportLocation(LOCATIONS[9]);
|
||||
return true;
|
||||
}
|
||||
player.teleport(LOCATIONS[1]);
|
||||
|
|
|
|||
|
|
@ -231,7 +231,7 @@ public final class GodwarsBossNPC extends AbstractNPC {
|
|||
public void finalizeDeath(Entity killer) {
|
||||
super.finalizeDeath(killer);
|
||||
if (getId() == 6222 || getId() == 6260 || getId() == 6247 || getId() == 6203) {
|
||||
BossKillCounter.addtoKillcount((Player) killer, this.getId());
|
||||
BossKillCounter.addToBossKillCount((Player) killer, this.getId());
|
||||
}
|
||||
if (minions == null) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -97,10 +97,10 @@ public final class KalphiteQueenNPC extends AbstractNPC {
|
|||
removeAttribute("disable:drop");
|
||||
super.finalizeDeath(killer);
|
||||
reTransform();
|
||||
BossKillCounter.addtoKillcount((Player) killer, 1160);
|
||||
BossKillCounter.addToBossKillCount((Player) killer, 1160);
|
||||
return;
|
||||
}
|
||||
BossKillCounter.addtoKillcount((Player) killer, this.getId());
|
||||
BossKillCounter.addToBossKillCount((Player) killer, this.getId());
|
||||
setAttribute("disable:drop", true);
|
||||
super.finalizeDeath(killer);
|
||||
super.setRespawnTick(-1);
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ class MysteriousGhostRennardDialogueFile : DialogueLabeller() {
|
|||
player("Why don't you tell me what happened? I might be able to help...")
|
||||
npc("Well, I was making me merry way along, having just pulled off a glorious jewellery heist from a bunch of stinking dwarves...")
|
||||
player("Hey, that's no way to talk about dwarves! Some of my best friends are short!")
|
||||
npc("Ah, yer misunderstand me [lad/lass], I wasn't generalising about the whole dwarf species, I had just stolen a bundle of jewels from a very specific group of dwarves who happened to have an odious stench about them!")
|
||||
npc("Ah, yer misunderstand me @g[lad,lass], I wasn't generalising about the whole dwarf species, I had just stolen a bundle of jewels from a very specific group of dwarves who happened to have an odious stench about them!")
|
||||
player("Oh. Well I guess that's okay then. Please continue.")
|
||||
npc("Well, as I headed on me merry way, hoping the foul odours that lingered in me nostrils would soon pass, I see in front of me this explorer fella, all decked out in in his fine clothing, and carrying some long package")
|
||||
npc("bundled in rags.")
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ class MysteriousGhostViggoraDialogueFile : DialogueLabeller() {
|
|||
npc("Hello yourself.")
|
||||
player("I really liked your little story. Can you tell me another one?")
|
||||
player("Preferably something with a big fight and lots of explosions!")
|
||||
npc("...You are a very strange young @g[man/woman].")
|
||||
npc("...You are a very strange young @g[man,woman].")
|
||||
|
||||
label("lostghostlything")
|
||||
player(ChatAnim.SAD, "Can I have that cloak back?")
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import org.rs09.consts.NPCs
|
|||
import core.game.dialogue.DialogueBuilder
|
||||
import core.game.dialogue.DialogueBuilderFile
|
||||
import content.data.Quests
|
||||
import content.global.handlers.iface.ScrollLine
|
||||
|
||||
@Initializable
|
||||
public final class ClayGolemDialoguePlugin(player: Player? = null) : DialoguePlugin(player) {
|
||||
|
|
@ -107,19 +108,18 @@ class CuratorHaigHalenGolemDialogue : DialogueBuilderFile() {
|
|||
}
|
||||
}
|
||||
|
||||
// https://youtu.be/owPSLUB9E8k?t=261
|
||||
val LETTER_LINES = arrayOf(
|
||||
"",
|
||||
"",
|
||||
"Dearest Varmen,",
|
||||
"I hope this finds you well. Here are the books you asked for",
|
||||
"There has been an exciting development closer to home --",
|
||||
"another city from the same period has been discovered east",
|
||||
"of Varrock, and we are starting a huge excavation project",
|
||||
"here. I don't know if the museum will be able to finance your",
|
||||
"expedition as well as this one, so I fear your current trip will be",
|
||||
"the last.",
|
||||
"May Saradomin grant you a safe journey home",
|
||||
"Your loving Elissa.",
|
||||
ScrollLine("Dearest Varmen,", 3),
|
||||
ScrollLine("I hope this finds you well. Here are the books you asked for", 4),
|
||||
ScrollLine("There has been an exciting development closer to home --", 5),
|
||||
ScrollLine("another city from the same period has been discovered east", 6),
|
||||
ScrollLine("of Varrock, and we are starting a huge excavation project", 7),
|
||||
ScrollLine("here. I don't know if the museum will be able to finance your", 8),
|
||||
ScrollLine("expedition as well as this one, so I fear your current trip will be", 9),
|
||||
ScrollLine("the last.", 10),
|
||||
ScrollLine("May Saradomin grant you a safe journey home", 11),
|
||||
ScrollLine("Your loving Elissa.", 12)
|
||||
)
|
||||
|
||||
val DISPLAY_CASE_TEXT = arrayOf("3rd age - yr 3000-4000",
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ import core.game.interaction.InteractionListener
|
|||
import core.game.interaction.InterfaceListener
|
||||
import core.game.world.GameWorld
|
||||
import content.data.Quests
|
||||
import content.global.handlers.iface.ScrollInterface
|
||||
import org.rs09.consts.Components
|
||||
|
||||
@Initializable
|
||||
class TheGolemQuest : Quest(Quests.THE_GOLEM, 70, 69, 1, 437, 0, 1, 10) {
|
||||
|
|
@ -112,19 +114,6 @@ class ClayGolemNPC : AbstractNPC {
|
|||
}
|
||||
}
|
||||
|
||||
class LetterListener : InterfaceListener {
|
||||
override fun defineInterfaceListeners() {
|
||||
onOpen(220) { player, component ->
|
||||
val lines: Array<String> = player.getAttribute("ifaces:220:lines", arrayOf())
|
||||
for(i in 0 until Math.min(lines.size, 15)) {
|
||||
setInterfaceText(player, lines[i], 220, i+1)
|
||||
//setInterfaceText(player, "${i}", 220, i+1)
|
||||
}
|
||||
return@onOpen true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class DisplayCaseListener : InterfaceListener {
|
||||
override fun defineInterfaceListeners() {
|
||||
onOpen(534) { player, component ->
|
||||
|
|
@ -372,9 +361,8 @@ class TheGolemListeners : InteractionListener {
|
|||
on(34978, IntType.SCENERY, "climb-down") { player, node -> core.game.global.action.ClimbActionHandler.climb(player, core.game.global.action.ClimbActionHandler.CLIMB_DOWN, core.game.global.action.SpecialLadders.getDestination(node.location)); return@on true }
|
||||
on(6372, IntType.SCENERY, "climb-up") { player, node -> core.game.global.action.ClimbActionHandler.climb(player, core.game.global.action.ClimbActionHandler.CLIMB_UP, core.game.global.action.SpecialLadders.getDestination(node.location)); return@on true }
|
||||
on(4615, IntType.ITEM, "read") { player, node ->
|
||||
player.setAttribute("ifaces:220:lines", LETTER_LINES)
|
||||
player.setAttribute("/save:the-golem:read-elissa-letter", true)
|
||||
openInterface(player, 220)
|
||||
ScrollInterface.scrollSetup(player, Components.MESSAGESCROLL_220, LETTER_LINES)
|
||||
return@on true
|
||||
}
|
||||
on(35226, IntType.SCENERY, "search") { player, node ->
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ public final class DagannothKingNPC extends AbstractNPC {
|
|||
public void finalizeDeath(Entity killer) {
|
||||
super.finalizeDeath(killer);
|
||||
if (getId() == 2881 || getId() == 2882 || getId() == 2883) {
|
||||
BossKillCounter.addtoKillcount((Player) killer, this.getId());
|
||||
BossKillCounter.addToBossKillCount((Player) killer, this.getId());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -406,16 +406,17 @@ class PlagueCityListeners : InteractionListener {
|
|||
}
|
||||
}
|
||||
|
||||
// https://youtu.be/AG81LH51WME?t=302
|
||||
private fun scruffyNote(player: Player) {
|
||||
val scruffynotes =
|
||||
arrayOf(
|
||||
"Got a bncket of nnilk",
|
||||
"Tlen grind sorne lhoculate",
|
||||
"Tlen qrind sorne lhoculate",
|
||||
"vnith a pestal and rnortar",
|
||||
"ald the grourd dlocolate to tho milt",
|
||||
"finales add 5cme snape gras5",
|
||||
"fnales add 5cme snape gras5",
|
||||
)
|
||||
setInterfaceText(player, scruffynotes.joinToString("<br>"), 222, 5)
|
||||
setInterfaceText(player, scruffynotes.joinToString("<br>"), 222, 4)
|
||||
}
|
||||
|
||||
override fun defineDestinationOverrides() {
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ public class DwarfCannonPlugin extends OptionHandler {
|
|||
SceneryDefinition.forId(3).getHandlers().put("option:open", this);
|
||||
SceneryDefinition.forId(5).getHandlers().put("option:inspect", this);
|
||||
SceneryDefinition.forId(2).getHandlers().put("option:enter", this);
|
||||
SceneryDefinition.forId(11).getHandlers().put("option:climb-up", this);
|
||||
SceneryDefinition.forId(13).getHandlers().put("option:climb-over", this);
|
||||
SceneryDefinition.forId(15601).getHandlers().put("option:inspect", this);
|
||||
for (int i = 15; i < 21; i++) {
|
||||
|
|
@ -110,6 +111,13 @@ public class DwarfCannonPlugin extends OptionHandler {
|
|||
player.animate(Animation.create(845));
|
||||
player.teleport(new Location(2619, 9797, 0), 2);
|
||||
break;
|
||||
case 11:
|
||||
if (node.getLocation().equals(new Location(2570, 3443, 1))
|
||||
&& quest.getStage(player) == 20
|
||||
&& !player.hasItem(DwarfCannon.DWARF_REMAINS)) {
|
||||
setVarp(player, 0, 3, true);
|
||||
}
|
||||
return ClimbActionHandler.climbLadder(player, node.asScenery(), option);
|
||||
case 13:
|
||||
ClimbActionHandler.climb(player, new Animation(828), new Location(2623, 3391, 0));
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import content.global.handlers.iface.BookInterface
|
|||
import content.global.handlers.iface.BookLine
|
||||
import content.global.handlers.iface.Page
|
||||
import content.global.handlers.iface.PageSet
|
||||
import core.api.setAttribute
|
||||
import core.game.interaction.IntType
|
||||
import core.game.interaction.InteractionListener
|
||||
import core.game.node.entity.player.Player
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@ import org.rs09.consts.Items
|
|||
import org.rs09.consts.NPCs
|
||||
import org.rs09.consts.Sounds
|
||||
import content.data.Quests
|
||||
import content.global.handlers.iface.ScrollInterface
|
||||
import content.global.handlers.iface.ScrollLine
|
||||
import org.rs09.consts.Components
|
||||
|
||||
class GrandTreeListeners: InteractionListener {
|
||||
|
||||
|
|
@ -26,12 +29,11 @@ class GrandTreeListeners: InteractionListener {
|
|||
Location(2473,9897,0),
|
||||
)
|
||||
|
||||
val hazelmerescroll = Items.HAZELMERES_SCROLL_786
|
||||
|
||||
val hazelmerescrollText = arrayOf(
|
||||
"<col=FFF900>Es lemanto meso pro eis prit ta Cinqo mond.</col>",
|
||||
"<col=FFF900>Mi lovos ta lemanto Daconia arpos</col>",
|
||||
"<col=FFF900>et Daconia arpos eto meriz ta priw!</col>",
|
||||
// https://youtu.be/-jfueZpRhzU?t=184
|
||||
val hazelmereScrollText = arrayOf(
|
||||
ScrollLine("Es lemanto meso pro eis prit ta Cinqo mond.", 6),
|
||||
ScrollLine("Mi lovos ta lemanto Daconia arpos", 7),
|
||||
ScrollLine("et Daconia arpos eto meriz ta priw!", 8)
|
||||
)
|
||||
|
||||
fun unlockTUZODoor(player: Player) {
|
||||
|
|
@ -84,8 +86,8 @@ class GrandTreeListeners: InteractionListener {
|
|||
openDialogue(player, AnitaDialogue(), npc)
|
||||
return@on true
|
||||
}
|
||||
on(hazelmerescroll, IntType.ITEM, "read") { player, node ->
|
||||
hazelmereScroll(player, node.asItem())
|
||||
on(Items.HAZELMERES_SCROLL_786, IntType.ITEM, "read") { player, node ->
|
||||
ScrollInterface.scrollSetup(player, Components.MESSAGESCROLL_220, hazelmereScrollText)
|
||||
return@on true
|
||||
}
|
||||
|
||||
|
|
@ -209,14 +211,5 @@ class GrandTreeListeners: InteractionListener {
|
|||
return@on true
|
||||
}
|
||||
}
|
||||
|
||||
private fun hazelmereScroll(player: Player, item: Item) {
|
||||
val id = item.id
|
||||
openInterface(player, 222).also {
|
||||
when (id) {
|
||||
hazelmerescroll -> setInterfaceText(player, hazelmerescrollText.joinToString("<br>"), 222, 6)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ class TribalTotemListeners : InteractionListener {
|
|||
|
||||
on(realCrate, IntType.SCENERY, "Investigate"){ player, node ->
|
||||
if(player.questRepository.getStage(Quests.TRIBAL_TOTEM) in 1..19 && !player.inventory.containsAtLeastOneItem(Items.ADDRESS_LABEL_1858)){
|
||||
sendDialogue(player,"There is a label on this crate. It says; To Lord Handelmort, Handelmort Mansion Ardogune.You carefully peel it off and take it.")
|
||||
sendDialogue(player,"There is a label on this crate. It says; To Lord Handelmort, Handelmort Mansion, Ardougne.You carefully peel it off and take it.")
|
||||
addItemOrDrop(player,Items.ADDRESS_LABEL_1858,1)
|
||||
}
|
||||
else if(player.questRepository.getStage(Quests.TRIBAL_TOTEM) in 1..19 && player.inventory.containsAtLeastOneItem(Items.ADDRESS_LABEL_1858)){
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package content.region.karamja.tzhaar.handlers;
|
||||
|
||||
import content.global.skill.slayer.SlayerManager;
|
||||
import core.game.event.NPCKillEvent;
|
||||
import core.game.activity.ActivityPlugin;
|
||||
import content.data.BossKillCounter;
|
||||
|
|
@ -10,8 +9,6 @@ import core.game.node.entity.Entity;
|
|||
import core.game.node.entity.npc.NPC;
|
||||
import core.game.node.entity.player.Player;
|
||||
import core.game.node.entity.player.link.diary.DiaryType;
|
||||
import core.game.node.entity.skill.Skills;
|
||||
import content.global.skill.slayer.Tasks;
|
||||
import core.game.node.item.GroundItemManager;
|
||||
import core.game.node.item.Item;
|
||||
import core.game.node.scenery.Scenery;
|
||||
|
|
@ -23,6 +20,7 @@ import core.plugin.Initializable;
|
|||
import core.tools.RandomFunction;
|
||||
import core.game.world.GameWorld;
|
||||
import core.game.world.repository.Repository;
|
||||
import org.rs09.consts.NPCs;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
|
@ -147,11 +145,6 @@ public final class TzhaarFightCavesPlugin extends ActivityPlugin {
|
|||
public void leave(Player player, int wave) {
|
||||
activeNPCs.clear();
|
||||
player.getProperties().setTeleportLocation(getSpawnLocation());
|
||||
player.getSkills().restore();
|
||||
player.timers.removeTimer("poison");
|
||||
player.timers.removeTimer("disease");
|
||||
player.timers.removeTimer("teleblock");
|
||||
player.getSettings().updateRunEnergy(-100);
|
||||
boolean practice = player.getAttribute("fc_practice_jad", false);
|
||||
if (wave == 63) {
|
||||
if (!practice) {
|
||||
|
|
@ -167,12 +160,7 @@ public final class TzhaarFightCavesPlugin extends ActivityPlugin {
|
|||
}
|
||||
player.getPacketDispatch().sendMessage("You were victorious!");
|
||||
if (!practice) {
|
||||
BossKillCounter.addtoKillcount(player, 2745);
|
||||
if (SlayerManager.getInstance(player).getTask() == Tasks.JAD) {
|
||||
player.getSkills().addExperience(Skills.SLAYER, 25000);
|
||||
SlayerManager.getInstance(player).clear();
|
||||
player.sendMessage("You receive 25,000 slayer experience for defeating TzTok-Jad.");
|
||||
}
|
||||
BossKillCounter.addToBossKillCount(player, NPCs.TZTOK_JAD_2745);
|
||||
player.getDialogueInterpreter().sendDialogues(2617, null, "You even defeated TzTok-Jad, I am most impressed!", "Please accept this gift as a reward.");
|
||||
Repository.sendNews(player.getUsername() + " has been victorious in defeating TzTok-Jad for a firecape!");
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -178,8 +178,8 @@ public final class CharacterDesign {
|
|||
case 40:
|
||||
player.getSettings().toggleMouseButton();
|
||||
break;
|
||||
case 92://hair style
|
||||
case 93:
|
||||
case 92://hair style left arrow
|
||||
case 93://hair style right arrow
|
||||
changeLook(player, 0, buttonId == 93);
|
||||
break;
|
||||
case 97:
|
||||
|
|
@ -348,18 +348,23 @@ public final class CharacterDesign {
|
|||
private static int getValue(Player player, String key, int index, int currentIndex, boolean increment) {
|
||||
int[] array = player.getAttribute("male", player.getAppearance().isMale()) ? MALE_LOOK_IDS[index] : FEMALE_LOOK_IDS[index];
|
||||
int val = 0;
|
||||
if (increment && currentIndex + 1 > array.length -1) {
|
||||
val = (int) array[0];
|
||||
currentIndex = 0;
|
||||
} else if (!increment && currentIndex -1 < 0) {
|
||||
val = (int) array[array.length -1];
|
||||
currentIndex = array.length -1;
|
||||
} else if (increment) {
|
||||
val = (int) array[currentIndex + 1];
|
||||
currentIndex++;
|
||||
if (player.isArtificial() && index <= 1) {
|
||||
currentIndex = RandomFunction.random(array.length -1);
|
||||
val = array[currentIndex];
|
||||
} else {
|
||||
val = (int) array[currentIndex - 1];
|
||||
currentIndex--;
|
||||
if (increment && currentIndex + 1 > array.length -1) {
|
||||
val = (int) array[0];
|
||||
currentIndex = 0;
|
||||
} else if (!increment && currentIndex -1 < 0) {
|
||||
val = (int) array[array.length -1];
|
||||
currentIndex = array.length -1;
|
||||
} else if (increment) {
|
||||
val = (int) array[currentIndex + 1];
|
||||
currentIndex++;
|
||||
} else {
|
||||
val = (int) array[currentIndex - 1];
|
||||
currentIndex--;
|
||||
}
|
||||
}
|
||||
player.setAttribute(key + ":" + index, currentIndex);
|
||||
return val;
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ package content.region.misthalin.barbvillage.stronghold.playersafety
|
|||
SceneryConst.JAIL_DOOR_29601 to 698,
|
||||
)
|
||||
|
||||
private val creviceClimbedAttribute = "player_strong:crevice_climbed"
|
||||
private val creviceClimbedAttribute = "/save:player_strong:crevice_climbed"
|
||||
|
||||
}
|
||||
override fun defineListeners() {
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ class CaveGoblinMinerNPC(id: Int = 0, location: Location? = null) : AbstractNPC(
|
|||
mining = (id > 2074)
|
||||
|
||||
if(properties.combatPulse.isAttacking && mining){
|
||||
transform(id - 6)
|
||||
transformWithHpCarryover(id - 6)
|
||||
this.isWalks = true
|
||||
this.walkRadius = 4
|
||||
this.isNeverWalks = false
|
||||
|
|
|
|||
|
|
@ -31,10 +31,10 @@ class DraynorManorHouseZone : MapZone("Draynor Manor House", true), Plugin<Any?>
|
|||
if (n.shouldPreventStacking(e)) {
|
||||
val s1 = e.size()
|
||||
val s2 = n.size()
|
||||
val x = destination.getX()
|
||||
val y = destination.getY()
|
||||
val x = destination.x
|
||||
val y = destination.y
|
||||
val l = n.getLocation()
|
||||
if (Pathfinder.isStandingIn(x, y, s1, s1, l.getX(), l.getY(), s2, s2)) {
|
||||
if (Pathfinder.isStandingIn(x, y, s1, s1, l.x, l.y, s2, s2)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ public class TormentedDemonNPC extends AbstractNPC {
|
|||
super.finalizeDeath(killer);
|
||||
reTransform();
|
||||
fireShield = true;
|
||||
BossKillCounter.addtoKillcount((Player) killer, this.getId());
|
||||
BossKillCounter.addToBossKillCount((Player) killer, this.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package content.region.morytania.canifis.handlers
|
|||
import core.api.*
|
||||
import core.game.interaction.QueueStrength
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.skill.Skills
|
||||
import core.game.node.entity.combat.BattleState
|
||||
import core.game.node.entity.combat.DeathTask
|
||||
import core.game.node.entity.npc.NPC
|
||||
|
|
@ -38,7 +39,9 @@ class WerewolfBehavior : NPCBehavior(*HUMAN_NPCS) {
|
|||
return@queueScript delayScript(self, WEREWOLF_IN_ANIMATION.duration)
|
||||
}
|
||||
1 -> {
|
||||
transformNpc(self, WEREWOLF_NPCS[self.id - 6026], 200)
|
||||
val humanMaxLp = self.getSkills().getMaximumLifepoints()
|
||||
transformNpcWithHpCarryover(self, WEREWOLF_NPCS[self.id - 6026], 200)
|
||||
self.getSkills().heal(self.getSkills().getMaximumLifepoints() - humanMaxLp)
|
||||
return@queueScript delayScript(self, 1)
|
||||
}
|
||||
2 -> {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ import core.game.interaction.InteractionListener
|
|||
import core.game.interaction.IntType
|
||||
import kotlin.random.Random
|
||||
import content.data.Quests
|
||||
import core.game.interaction.InterfaceListener
|
||||
import org.rs09.consts.Components
|
||||
|
||||
/**
|
||||
* File to be used for anything Morytania related.
|
||||
|
|
@ -40,12 +42,15 @@ class MorytaniaListeners : InteractionListener {
|
|||
on(SWAMP_GATES, IntType.SCENERY, "open"){ player, node ->
|
||||
if(player.location.y == 3457){
|
||||
core.game.global.action.DoorActionHandler.handleAutowalkDoor(player, node.asScenery())
|
||||
sendMessage(player, "You skip gladly out of murky Mort Myre.")
|
||||
removeTimer<SwampDecayTimer>(player)
|
||||
GlobalScope.launch {
|
||||
findLocalNPC(player, NPCs.ULIZIUS_1054)?.sendChat("Oh my! You're still alive!", 2)
|
||||
}
|
||||
} else {
|
||||
if (player.questRepository.hasStarted(Quests.NATURE_SPIRIT)) {
|
||||
core.game.global.action.DoorActionHandler.handleAutowalkDoor(player, node.asScenery())
|
||||
setAttribute(player, "swampgate", node)
|
||||
openInterface(player, Components.CWS_WARNING_20_580)
|
||||
} else {
|
||||
sendNPCDialogue(
|
||||
player,
|
||||
|
|
@ -97,4 +102,24 @@ class MorytaniaListeners : InteractionListener {
|
|||
return@on true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class warningInterface : InterfaceListener {
|
||||
override fun defineInterfaceListeners() {
|
||||
on(Components.CWS_WARNING_20_580) { player, _, _, buttonID, _, _ ->
|
||||
when(buttonID) {
|
||||
17 -> {
|
||||
val gate = getAttribute(player, "swampgate", null) as? core.game.node.scenery.Scenery
|
||||
if (gate != null) {
|
||||
core.game.global.action.DoorActionHandler.handleAutowalkDoor(player, gate)
|
||||
sendMessage(player, "You walk into the gloomy atmosphere of Mort Myre.")
|
||||
}
|
||||
closeInterface(player)
|
||||
}
|
||||
18 -> closeInterface(player)
|
||||
}
|
||||
removeAttribute(player, "swampgate")
|
||||
return@on true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
package content.region.morytania.handlers;
|
||||
|
||||
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.plugin.Initializable;
|
||||
import core.plugin.Plugin;
|
||||
|
||||
/**
|
||||
* Represents the mortynia swamp plugin.
|
||||
* @author 'Vexia
|
||||
* @version 1.0
|
||||
*/
|
||||
@Initializable
|
||||
public final class MoyrtniaSwampPlugin extends OptionHandler {
|
||||
|
||||
@Override
|
||||
public Plugin<Object> newInstance(Object arg) throws Throwable {
|
||||
SceneryDefinition.forId(3506).getHandlers().put("option:open", this);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(Player player, Node node, String option) {
|
||||
player.getDialogueInterpreter().sendDialogue("There's a message attached to this gate, it reads:~", "~ Mort Myre is a dangerous Ghast infested swamp. ~", "~ Do not enter if you value your life. ~", "~ All persons wishing to enter must see Drezel. ~");
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
package content.region.morytania.handlers
|
||||
|
||||
import core.api.*
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.system.timer.PersistTimer
|
||||
import core.game.system.timer.RSTimer
|
||||
import core.game.system.timer.TimerFlag
|
||||
import core.game.world.map.zone.ZoneBorders
|
||||
import org.rs09.consts.Items
|
||||
import kotlin.random.Random
|
||||
|
||||
|
||||
/**
|
||||
* The area for swamp decay
|
||||
*/
|
||||
class SwampDecayArea : MapArea {
|
||||
override fun defineAreaBorders(): Array<ZoneBorders> {
|
||||
return arrayOf(
|
||||
ZoneBorders(3392, 3328, 3519, 3455)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sources:
|
||||
* General mechanic: https://runescape.wiki/w/Swamp_decay
|
||||
* Historic damage: https://runescape.wiki/w/Mort_Myre_Swamp?oldid=1961846
|
||||
* Precise area: https://oldschool.runescape.wiki/w/Swamp_decay
|
||||
* Video: https://www.youtube.com/watch?v=gkw959x8Q6s
|
||||
* Video: https://www.youtube.com/watch?v=N86RywmEyEU
|
||||
*/
|
||||
|
||||
override fun areaEnter(entity: Entity) {
|
||||
if (entity is Player) {
|
||||
getOrStartTimer<SwampDecayTimer>(entity)
|
||||
}
|
||||
super.areaEnter(entity)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The timer for swamp decay
|
||||
*/
|
||||
class SwampDecayTimer : PersistTimer (200, "swampdecay", isSoft = true, flags = arrayOf(TimerFlag.ClearOnDeath)) {
|
||||
companion object {
|
||||
// Silver sickle, Rod of Ivandis, or Ivandis Flail in equip or inv will protect the player.
|
||||
private val PROTECTIVE_ITEMS = intArrayOf(
|
||||
Items.SILVER_SICKLEB_2963,
|
||||
Items.ROD_OF_IVANDIS10_7639,
|
||||
Items.ROD_OF_IVANDIS9_7640,
|
||||
Items.ROD_OF_IVANDIS8_7641,
|
||||
Items.ROD_OF_IVANDIS7_7642,
|
||||
Items.ROD_OF_IVANDIS6_7643,
|
||||
Items.ROD_OF_IVANDIS5_7644,
|
||||
Items.ROD_OF_IVANDIS4_7645,
|
||||
Items.ROD_OF_IVANDIS3_7646,
|
||||
Items.ROD_OF_IVANDIS2_7647,
|
||||
Items.ROD_OF_IVANDIS1_7648,
|
||||
Items.IVANDIS_FLAIL_30_13117,
|
||||
Items.IVANDIS_FLAIL_29_13118,
|
||||
Items.IVANDIS_FLAIL28_13119,
|
||||
Items.IVANDIS_FLAIL_27_13120,
|
||||
Items.IVANDIS_FLAIL_26_13121,
|
||||
Items.IVANDIS_FLAIL_25_13122,
|
||||
Items.IVANDIS_FLAIL_24_13123,
|
||||
Items.IVANDIS_FLAIL_23_13124,
|
||||
Items.IVANDIS_FLAIL_22_13125,
|
||||
Items.IVANDIS_FLAIL_21_13126,
|
||||
Items.IVANDIS_FLAIL_20_13127,
|
||||
Items.IVANDIS_FLAIL_19_13128,
|
||||
Items.IVANDIS_FLAIL_18_13129,
|
||||
Items.IVANDIS_FLAIL_17_13130,
|
||||
Items.IVANDIS_FLAIL_16_13131,
|
||||
Items.IVANDIS_FLAIL_15_13132,
|
||||
Items.IVANDIS_FLAIL_14_13133,
|
||||
Items.IVANDIS_FLAIL_13_13134,
|
||||
Items.IVANDIS_FLAIL_12_13135,
|
||||
Items.IVANDIS_FLAIL_11_13136,
|
||||
Items.IVANDIS_FLAIL_10_13137,
|
||||
Items.IVANDIS_FLAIL_9_13138,
|
||||
Items.IVANDIS_FLAIL_8_13139,
|
||||
Items.IVANDIS_FLAIL_7_13140,
|
||||
Items.IVANDIS_FLAIL_6_13141,
|
||||
Items.IVANDIS_FLAIL_5_13142,
|
||||
Items.IVANDIS_FLAIL_4_13143,
|
||||
Items.IVANDIS_FLAIL_3_13144,
|
||||
Items.IVANDIS_FLAIL_2_13145,
|
||||
Items.IVANDIS_FLAIL_1_13146
|
||||
)
|
||||
}
|
||||
|
||||
// returning false stops the timer. returning true keeps it running.
|
||||
override fun run(entity: Entity): Boolean {
|
||||
if (entity !is Player) return false
|
||||
|
||||
// player is outside the zone
|
||||
if (entity.location.x !in 3392..3519 || entity.location.y !in 3328..3455) {
|
||||
sendMessage(entity, "The swamp decay effect is now over.")
|
||||
return false
|
||||
}
|
||||
|
||||
// the nature spirit camp zone is safe
|
||||
if (entity.location.x in 3435..3445 && entity.location.y in 3331..3442) {
|
||||
sendMessage(entity, "The aura of Filliman's camp protects you from the swamp.")
|
||||
return true
|
||||
}
|
||||
|
||||
// protected
|
||||
if (hasProtection(entity)) {
|
||||
return true
|
||||
}
|
||||
|
||||
// decayed (2-4 random damage)
|
||||
sendMessage(entity, "The swamp decays you!")
|
||||
impact(entity, Random.nextInt(2, 5))
|
||||
visualize(entity, -1, 255)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onRegister(entity: Entity) {
|
||||
if (entity !is Player) return
|
||||
}
|
||||
|
||||
override fun getTimer(vararg args: Any): RSTimer {
|
||||
val t = SwampDecayTimer()
|
||||
t.runInterval = args.getOrNull(0) as? Int ?: 200
|
||||
return t
|
||||
}
|
||||
|
||||
// always remember your protection
|
||||
private fun hasProtection(player: Player): Boolean {
|
||||
for (itemId in PROTECTIVE_ITEMS) {
|
||||
if (inEquipmentOrInventory(player, itemId)) {
|
||||
val prot = when(itemId) {
|
||||
2963 -> "blessed silver sickle"
|
||||
in 7639..7648 -> "rod of Ivandis"
|
||||
in 13117..13146 -> "Ivandis flail"
|
||||
else -> "item" // fallback
|
||||
}
|
||||
sendMessage(player, "The power of the $prot prevents the swamp decay.")
|
||||
visualize(player, -1, 259)
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
@ -18,7 +18,7 @@ class GardenerGhostDialogue (player: Player? = null) : DialoguePlugin(player) {
|
|||
if (gardenerGhost.location.withinDistance(gardenerGhost.graveLocation, 5)) {
|
||||
sendChat(gardenerGhost, "Here is the place where I met me' maker.")
|
||||
} else {
|
||||
sendChat(gardenerGhost, "Go " + gardenerGhost.location.deriveDirection(gardenerGhost.graveLocation).name.lowercase(Locale.getDefault()).replace('_', '-') + ", mate")
|
||||
sendChat(gardenerGhost, "Go " + gardenerGhost.location.deriveDirection(gardenerGhost.graveLocation)!!.name.lowercase(Locale.getDefault()).replace('_', '-') + ", mate")
|
||||
gardenerGhost.continueFollowing(player)
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ public class BorkNPC extends AbstractNPC {
|
|||
@Override
|
||||
public void finalizeDeath(Entity killer){
|
||||
super.finalizeDeath(killer);
|
||||
BossKillCounter.addtoKillcount((Player) killer, this.getId());
|
||||
BossKillCounter.addToBossKillCount((Player) killer, this.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ public class ChaosElementalNPC extends AbstractNPC {
|
|||
@Override
|
||||
public void finalizeDeath(Entity killer) {
|
||||
super.finalizeDeath(killer);
|
||||
BossKillCounter.addtoKillcount((Player) killer, this.getId());
|
||||
BossKillCounter.addToBossKillCount((Player) killer, this.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ public final class CorporealBeastNPC extends NPCBehavior {
|
|||
|
||||
@Override
|
||||
public void onDeathFinished(NPC self, Entity killer) {
|
||||
BossKillCounter.addtoKillcount((Player) killer, NPCs.CORPOREAL_BEAST_8133);
|
||||
BossKillCounter.addToBossKillCount((Player) killer, NPCs.CORPOREAL_BEAST_8133);
|
||||
if (darkEnergyCore != null) {
|
||||
darkEnergyCore.clear();
|
||||
darkEnergyCore = null;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import core.game.node.entity.impl.Animator.Priority;
|
|||
import core.game.node.entity.npc.AbstractNPC;
|
||||
import core.game.node.entity.npc.NPC;
|
||||
import core.game.node.entity.player.Player;
|
||||
import core.game.world.GameWorld;
|
||||
import core.game.world.map.Location;
|
||||
import core.game.world.update.flag.context.Animation;
|
||||
import core.plugin.Initializable;
|
||||
|
|
@ -48,7 +49,7 @@ public final class KingBlackDragonNPC extends AbstractNPC {
|
|||
@Override
|
||||
public void finalizeDeath(Entity killer) {
|
||||
super.finalizeDeath(killer);
|
||||
BossKillCounter.addtoKillcount((Player) killer, this.getId());
|
||||
BossKillCounter.addToBossKillCount((Player) killer, this.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -127,7 +128,6 @@ public final class KingBlackDragonNPC extends AbstractNPC {
|
|||
@Override
|
||||
public void adjustBattleState(Entity entity, Entity victim, BattleState state) {
|
||||
if (style == CombatStyle.RANGE) {
|
||||
fireType.getTask().exec(victim, entity);
|
||||
state.setStyle(null);
|
||||
DRAGONFIRE.adjustBattleState(entity, victim, state);
|
||||
state.setStyle(CombatStyle.RANGE);
|
||||
|
|
@ -184,6 +184,9 @@ public final class KingBlackDragonNPC extends AbstractNPC {
|
|||
|
||||
@Override
|
||||
public void impact(Entity entity, Entity victim, BattleState state) {
|
||||
if (style != CombatStyle.MELEE && victim.getImpactHandler().getDisabledTicks() <= GameWorld.getTicks()) {
|
||||
fireType.getTask().exec(victim, entity);
|
||||
}
|
||||
style.getSwingHandler().impact(entity, victim, state);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import core.game.system.SystemState
|
|||
import core.game.system.config.ServerConfigParser
|
||||
import core.game.world.GameWorld
|
||||
import core.net.NioReactor
|
||||
import core.net.websocket.GameWebSocketServer
|
||||
import core.net.websocket.WebSocketTls
|
||||
import core.tools.Log
|
||||
import core.tools.NetworkReachability
|
||||
import core.tools.TimeStamp
|
||||
|
|
@ -44,6 +46,9 @@ object Server {
|
|||
@JvmStatic
|
||||
var reactor: NioReactor? = null
|
||||
|
||||
@JvmStatic
|
||||
var webSocketServer: GameWebSocketServer? = null
|
||||
|
||||
var networkReachability = NetworkReachability.Reachable
|
||||
|
||||
/**
|
||||
|
|
@ -70,6 +75,16 @@ object Server {
|
|||
try {
|
||||
reactor = NioReactor.configure(43594 + GameWorld.settings?.worldId!!)
|
||||
reactor!!.start()
|
||||
if (ServerConstants.WEBSOCKET_ENABLED) {
|
||||
val websocketPort = if (ServerConstants.WEBSOCKET_PORT > 0) {
|
||||
ServerConstants.WEBSOCKET_PORT
|
||||
} else {
|
||||
53594 + GameWorld.settings?.worldId!!
|
||||
}
|
||||
webSocketServer = GameWebSocketServer(websocketPort, 1)
|
||||
WebSocketTls.configure(webSocketServer!!)
|
||||
webSocketServer!!.start()
|
||||
}
|
||||
} catch (e: BindException) {
|
||||
log(this::class.java, Log.ERR, "Port " + (43594 + GameWorld.settings?.worldId!!) + " is already in use!")
|
||||
throw e
|
||||
|
|
|
|||
|
|
@ -374,5 +374,20 @@ class ServerConstants {
|
|||
|
||||
@JvmField
|
||||
var CONNECTIVITY_TIMEOUT = 500
|
||||
|
||||
@JvmField
|
||||
var WEBSOCKET_ENABLED = false
|
||||
|
||||
@JvmField
|
||||
var WEBSOCKET_PORT = 0
|
||||
|
||||
@JvmField
|
||||
var WEBSOCKET_TLS_ENABLED = false
|
||||
|
||||
@JvmField
|
||||
var WEBSOCKET_TLS_KEYSTORE_PATH = ""
|
||||
|
||||
@JvmField
|
||||
var WEBSOCKET_TLS_KEYSTORE_PASSWORD = ""
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1343,6 +1343,25 @@ fun transformNpc(npc: NPC, transformTo: Int, restoreTicks: Int) {
|
|||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms an NPC for the given number of ticks with hp carryover
|
||||
* @param npc the NPC object to transform
|
||||
* @param transformTo the ID of the NPC to turn into
|
||||
* @param restoreTicks the number of ticks until the NPC returns to normal
|
||||
*/
|
||||
fun transformNpcWithHpCarryover(npc: NPC, transformTo: Int, restoreTicks: Int) {
|
||||
npc.transformWithHpCarryover(transformTo)
|
||||
queueScript(npc, 0, QueueStrength.SOFT) { stage: Int ->
|
||||
when (stage) {
|
||||
0 -> return@queueScript delayScript(npc, restoreTicks)
|
||||
else -> {
|
||||
npc.reTransform()
|
||||
return@queueScript stopExecuting(npc)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces a Location object using the given x,y,z values
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ public final class AIPBuilder {
|
|||
//Varrock Ge bank
|
||||
RandomAfkPlayer(new Location(3189, 3439));
|
||||
|
||||
//Home Bank
|
||||
// Lunar Island Bank
|
||||
RandomAfkPlayer(new Location(2099, 3918));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ public class AIPlayer extends Player {
|
|||
* Generates bot stats/equipment/etc based on OSRScopyLine
|
||||
*/
|
||||
public void updateRandomValues() {
|
||||
this.getAppearance().setGender(RandomFunction.random(5) == 1 ? Gender.FEMALE : Gender.MALE);
|
||||
this.getAppearance().setGender(RandomFunction.random(3) == 1 ? Gender.FEMALE : Gender.MALE);
|
||||
int setTo = RandomFunction.random(0,10);
|
||||
CharacterDesign.randomize(this,true);
|
||||
this.setDirection(Direction.values()[new Random().nextInt(Direction.values().length)]); //Random facing dir
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package core.game.bots
|
|||
|
||||
import core.game.node.item.Item
|
||||
import core.game.world.map.Location
|
||||
import org.rs09.consts.Items
|
||||
|
||||
class SkillingBotAssembler {
|
||||
fun produce(type: Wealth, loc: Location): AIPlayer {
|
||||
|
|
@ -39,7 +40,161 @@ class SkillingBotAssembler {
|
|||
RICH
|
||||
}
|
||||
|
||||
val POORSETS = arrayOf(listOf(542,544), listOf(581), listOf(6654,6655,6656), listOf(6654,6656), listOf(636,646), listOf(638,648), listOf(), listOf(), listOf())
|
||||
val AVGSETS = arrayOf(listOf(2649,342,344), listOf(2651,542,544), listOf(6654,6655,6656), listOf(6139,6141), listOf(9923,9924,9925), listOf(10400,10402,2649), listOf(10404,10406), listOf(12971,12978))
|
||||
val RICHSETS = arrayOf(listOf(10330,10332,2649), listOf(12873,12880,1046), listOf(13858,13861,13864), listOf(13887,13893), listOf(3481,3483), listOf(2653,2655), listOf(2661,2663), listOf(2591,2593), listOf(14490,14492))
|
||||
val POORSETS = arrayOf(
|
||||
listOf(Items.BLACK_ROBE_581, Items.BLACK_SKIRT_1015, Items.STAFF_OF_AIR_1381),
|
||||
listOf(Items.BLACK_ROBE_581, Items.BLACK_SKIRT_1015),
|
||||
listOf(Items.BLACK_ROBE_581, Items.BLACK_SKIRT_1015, Items.WIZARD_HAT_1017),
|
||||
listOf(), // No equipment
|
||||
listOf(Items.WIZARD_HAT_579),
|
||||
listOf(Items.WIZARD_HAT_579, Items.STAFF_OF_AIR_1381),
|
||||
listOf(Items.WIZARD_HAT_579, Items.STAFF_1379),
|
||||
listOf(Items.WIZARD_HAT_579, Items.WIZARD_ROBE_577, Items.BLUE_SKIRT_1011),
|
||||
listOf(Items.WIZARD_HAT_579, Items.WIZARD_ROBE_577, Items.BLUE_SKIRT_1011, Items.TIARA_5525),
|
||||
listOf(Items.WIZARD_HAT_579, Items.WIZARD_ROBE_577, Items.BLUE_SKIRT_1011, Items.TEAM_1_CAPE_4315),
|
||||
listOf(Items.WIZARD_HAT_579, Items.WIZARD_ROBE_577, Items.BLUE_SKIRT_1011, Items.STAFF_OF_AIR_1381),
|
||||
listOf(Items.WIZARD_HAT_579, Items.WIZARD_ROBE_577, Items.BLUE_SKIRT_1011, Items.STAFF_OF_WATER_1383),
|
||||
listOf(Items.WIZARD_ROBE_577, Items.BLUE_SKIRT_1011),
|
||||
listOf(Items.WIZARD_ROBE_577, Items.BLUE_SKIRT_1011, Items.TIARA_5525),
|
||||
listOf(Items.WIZARD_ROBE_577, Items.BLUE_SKIRT_1011, Items.TEAM_1_CAPE_4315),
|
||||
listOf(Items.WIZARD_ROBE_577, Items.BLUE_SKIRT_1011, Items.STAFF_OF_AIR_1381),
|
||||
listOf(Items.WIZARD_ROBE_577, Items.BLUE_SKIRT_1011, Items.STAFF_OF_WATER_1383),
|
||||
listOf(), // No equipment
|
||||
listOf(Items.STEEL_PLATELEGS_1069, Items.STEEL_PLATEBODY_1119, Items.STEEL_KITESHIELD_1193, Items.STEEL_LONGSWORD_1295, Items.TEAM_29_CAPE_4371),
|
||||
listOf(Items.STEEL_PLATESKIRT_1083, Items.STEEL_PLATEBODY_1119, Items.STEEL_KITESHIELD_1193, Items.STEEL_LONGSWORD_1295, Items.TEAM_30_CAPE_4373),
|
||||
listOf(Items.STEEL_PLATESKIRT_1083, Items.STEEL_PLATEBODY_1119, Items.STEEL_FULL_HELM_1157, Items.TEAM_30_CAPE_4373),
|
||||
listOf(Items.STEEL_PLATELEGS_1069, Items.STEEL_CHAINBODY_1105, Items.STEEL_FULL_HELM_1157, Items.TEAM_31_CAPE_4375),
|
||||
listOf(Items.STEEL_PLATELEGS_1069, Items.STEEL_PLATEBODY_1119, Items.TEAM_29_CAPE_4371),
|
||||
listOf(Items.STEEL_PLATESKIRT_1083, Items.STEEL_PLATEBODY_1119, Items.TEAM_30_CAPE_4373),
|
||||
listOf(Items.STEEL_PLATELEGS_1069, Items.STEEL_CHAINBODY_1105, Items.TEAM_31_CAPE_4375),
|
||||
listOf(Items.STEEL_PLATELEGS_1069, Items.STEEL_CHAINBODY_1105, Items.STEEL_2H_SWORD_1311, Items.TEAM_34_CAPE_4381),
|
||||
listOf(Items.STEEL_PLATELEGS_1069, Items.STEEL_CHAINBODY_1105, Items.STEEL_SCIMITAR_1325, Items.TEAM_35_CAPE_4383),
|
||||
listOf(Items.STEEL_PLATELEGS_1069, Items.STEEL_CHAINBODY_1105, Items.STEEL_BATTLEAXE_1365, Items.TEAM_35_CAPE_4383),
|
||||
listOf(Items.STEEL_PLATELEGS_1069, Items.STEEL_CHAINBODY_1105, Items.STEEL_BATTLEAXE_1365, Items.STEEL_SQ_SHIELD_1177, Items.TEAM_35_CAPE_4383),
|
||||
listOf(), // No equipment
|
||||
listOf(Items.IRON_PLATELEGS_1067, Items.IRON_PLATEBODY_1115, Items.IRON_FULL_HELM_1153, Items.IRON_KITESHIELD_1191, Items.IRON_LONGSWORD_1293, Items.TEAM_36_CAPE_4385),
|
||||
listOf(Items.IRON_PLATELEGS_1067, Items.IRON_PLATEBODY_1115, Items.IRON_FULL_HELM_1153, Items.IRON_2H_SWORD_1309, Items.TEAM_37_CAPE_4387),
|
||||
listOf(Items.IRON_PLATESKIRT_1081, Items.IRON_PLATEBODY_1115, Items.IRON_FULL_HELM_1153, Items.IRON_SCIMITAR_1323, Items.TEAM_32_CAPE_4377),
|
||||
listOf(Items.IRON_PLATESKIRT_1081, Items.IRON_PLATEBODY_1115, Items.IRON_FULL_HELM_1153, Items.IRON_BATTLEAXE_1363, Items.TEAM_32_CAPE_4377),
|
||||
listOf(Items.IRON_PLATELEGS_1067, Items.IRON_CHAINBODY_1101, Items.IRON_KITESHIELD_1191, Items.IRON_LONGSWORD_1293, Items.TEAM_33_CAPE_4379),
|
||||
listOf(Items.IRON_PLATESKIRT_1081, Items.IRON_PLATEBODY_1115, Items.IRON_FULL_HELM_1153, Items.TEAM_39_CAPE_4391),
|
||||
listOf(Items.IRON_PLATELEGS_1067, Items.IRON_PLATEBODY_1115, Items.IRON_FULL_HELM_1153, Items.TEAM_37_CAPE_4387),
|
||||
listOf(Items.IRON_PLATELEGS_1067, Items.IRON_PLATEBODY_1115, Items.IRON_SCIMITAR_1323, Items.TEAM_32_CAPE_4377),
|
||||
listOf(Items.IRON_PLATESKIRT_1081, Items.IRON_PLATEBODY_1115, Items.TEAM_32_CAPE_4377),
|
||||
listOf(Items.IRON_PLATELEGS_1067, Items.IRON_CHAINBODY_1101, Items.TEAM_33_CAPE_4379),
|
||||
listOf(Items.IRON_PLATESKIRT_1081, Items.IRON_PLATEBODY_1115, Items.IRON_FULL_HELM_1153, Items.TEAM_32_CAPE_4377),
|
||||
listOf(Items.IRON_PLATESKIRT_1081, Items.IRON_CHAINBODY_1101, Items.IRON_FULL_HELM_1153, Items.TEAM_32_CAPE_4377),
|
||||
listOf(Items.IRON_PLATELEGS_1067, Items.IRON_CHAINBODY_1101, Items.IRON_FULL_HELM_1153, Items.TEAM_33_CAPE_4379),
|
||||
listOf(), // No equipment
|
||||
listOf(Items.BRONZE_PLATELEGS_1075,Items.BRONZE_PLATEBODY_1117,Items.BRONZE_FULL_HELM_1155,Items.BRONZE_KITESHIELD_1189,Items.BRONZE_LONGSWORD_1291,Items.TEAM_27_CAPE_4367),
|
||||
listOf(Items.BRONZE_PLATESKIRT_1087,Items.BRONZE_PLATEBODY_1117,Items.BRONZE_FULL_HELM_1155,Items.BRONZE_KITESHIELD_1189,Items.BRONZE_LONGSWORD_1291,Items.TEAM_27_CAPE_4367),
|
||||
listOf(Items.BRONZE_PLATELEGS_1075,Items.BRONZE_PLATEBODY_1117,Items.BRONZE_FULL_HELM_1155,Items.BRONZE_2H_SWORD_1307, Items.TEAM_28_CAPE_4369),
|
||||
listOf(Items.BRONZE_PLATELEGS_1075,Items.BRONZE_CHAINBODY_1103),
|
||||
listOf(Items.BRONZE_PLATELEGS_1075,Items.BRONZE_CHAINBODY_1103,Items.BRONZE_2H_SWORD_1307),
|
||||
listOf(Items.BRONZE_PLATELEGS_1075,Items.BRONZE_CHAINBODY_1103,Items.BRONZE_SCIMITAR_1321),
|
||||
listOf(Items.BRONZE_PLATELEGS_1075,Items.BRONZE_CHAINBODY_1103,Items.BRONZE_BATTLEAXE_1375),
|
||||
listOf(Items.BRONZE_PLATELEGS_1075,Items.BRONZE_CHAINBODY_1103,Items.BRONZE_BATTLEAXE_1375,Items.BRONZE_SQ_SHIELD_1173),
|
||||
listOf(Items.BRONZE_PLATELEGS_1075,Items.BRONZE_PLATEBODY_1117, Items.TEAM_27_CAPE_4367),
|
||||
listOf(Items.BRONZE_PLATELEGS_1075,Items.BRONZE_PLATEBODY_1117,Items.BRONZE_FULL_HELM_1155, Items.TEAM_27_CAPE_4367),
|
||||
listOf(Items.BRONZE_PLATESKIRT_1087,Items.BRONZE_CHAINBODY_1103),
|
||||
listOf(Items.BRONZE_PLATESKIRT_1087,Items.BRONZE_CHAINBODY_1103,Items.BRONZE_FULL_HELM_1155),
|
||||
listOf(Items.BRONZE_PLATESKIRT_1087,Items.BRONZE_CHAINBODY_1103,Items.BRONZE_FULL_HELM_1155, Items.TEAM_28_CAPE_4369),
|
||||
listOf(Items.BRONZE_PLATESKIRT_1087,Items.BRONZE_PLATEBODY_1117, Items.TEAM_28_CAPE_4369),
|
||||
listOf(), // No equipment
|
||||
listOf(Items.LEATHER_BODY_1129,Items.LEATHER_CHAPS_1095),
|
||||
listOf(), // No equipment
|
||||
listOf(Items.STUDDED_CHAPS_1097,Items.STUDDED_BODY_1133),
|
||||
listOf(Items.MIME_LEGS_3059,Items.MIME_TOP_3058,Items.MIME_BOOTS_3061,Items.MIME_GLOVES_3060,Items.MIME_MASK_3057),
|
||||
listOf(Items.MIME_LEGS_3059,Items.MIME_TOP_3058,Items.MIME_BOOTS_3061,Items.MIME_GLOVES_3060),
|
||||
listOf(Items.MONKS_ROBE_542,Items.MONKS_ROBE_544),
|
||||
listOf(Items.CHICKEN_LEGS_11022,Items.CHICKEN_WINGS_11020,Items.CHICKEN_HEAD_11021,Items.CHICKEN_FEET_11019),
|
||||
listOf(Items.TOY_KITE_12844,Items.CHOCATRICE_CAPE_12634),
|
||||
listOf(), // No equipment
|
||||
listOf(Items.WHITE_APRON_1005, Items.CHEFS_HAT_1949),
|
||||
listOf(Items.TEAM_10_CAPE_4333),
|
||||
listOf(Items.TEAM_2_CAPE_4317),
|
||||
listOf(), // No equipment
|
||||
listOf(), // No equipment
|
||||
listOf(), // No equipment
|
||||
listOf())
|
||||
|
||||
val AVGSETS = arrayOf(
|
||||
listOf(Items.SKELETAL_TOP_6139, Items.SKELETAL_BOTTOMS_6141),
|
||||
listOf(Items.SKELETON_LEGGINGS_9923, Items.SKELETON_SHIRT_9924, Items.SKELETON_MASK_9925),
|
||||
listOf(Items.BLACK_ELE_SHIRT_10400,Items.BLACK_ELE_LEGS_10402,Items.BROWN_HEADBAND_2649),
|
||||
listOf(Items.RED_ELE_SHIRT_10404,Items.RED_ELE_LEGS_10406),
|
||||
listOf(Items.COMBAT_ROBE_TOP_100_12971, Items.COMBAT_ROBE_BOTTOM_100_12978),
|
||||
listOf(Items.COMBAT_ROBE_TOP_100_12971, Items.COMBAT_ROBE_BOTTOM_100_12978, Items.COMBAT_HOOD_100_12964),
|
||||
listOf(Items.COMBAT_ROBE_TOP_100_12971, Items.COMBAT_ROBE_BOTTOM_100_12978, Items.RUNE_BERSERKER_SHIELD_100_12929),
|
||||
listOf(Items.COMBAT_ROBE_TOP_100_12971, Items.COMBAT_ROBE_BOTTOM_100_12978, Items.ADAMANT_BERSERKER_SHIELD_100_12915),
|
||||
listOf(Items.DRUIDIC_MAGE_TOP_100_12894, Items.DRUIDIC_MAGE_BOTTOM_100_12901, Items.DRUIDIC_MAGE_HOOD_100_12887),
|
||||
listOf(), // No equipment
|
||||
listOf(Items.MITHRIL_PLATELEGS_1071, Items.MITHRIL_PLATEBODY_1121, Items.MITHRIL_KITESHIELD_1197, Items.MITHRIL_LONGSWORD_1299, Items.TEAM_29_CAPE_4371),
|
||||
listOf(Items.MITHRIL_PLATESKIRT_1085, Items.MITHRIL_PLATEBODY_1121, Items.MITHRIL_KITESHIELD_1197, Items.MITHRIL_LONGSWORD_1299, Items.TEAM_30_CAPE_4373),
|
||||
listOf(Items.MITHRIL_PLATELEGS_1071, Items.MITHRIL_PLATEBODY_1121, Items.TEAM_29_CAPE_4371),
|
||||
listOf(Items.MITHRIL_PLATESKIRT_1085, Items.MITHRIL_PLATEBODY_1121, Items.TEAM_30_CAPE_4373),
|
||||
listOf(Items.MITHRIL_PLATESKIRT_1085, Items.MITHRIL_CHAINBODY_1109, Items.TEAM_30_CAPE_4373),
|
||||
listOf(Items.MITHRIL_PLATELEGS_1071, Items.MITHRIL_CHAINBODY_1109, Items.TEAM_31_CAPE_4375),
|
||||
listOf(Items.MITHRIL_PLATELEGS_1071, Items.MITHRIL_CHAINBODY_1109, Items.MITHRIL_2H_SWORD_1315, Items.TEAM_34_CAPE_4381),
|
||||
listOf(Items.MITHRIL_PLATELEGS_1071, Items.MITHRIL_CHAINBODY_1109, Items.MITHRIL_SCIMITAR_1329, Items.TEAM_35_CAPE_4383),
|
||||
listOf(Items.MITHRIL_PLATELEGS_1071, Items.MITHRIL_CHAINBODY_1109, Items.MITHRIL_BATTLEAXE_1369, Items.TEAM_36_CAPE_4385),
|
||||
listOf(), // No equipment
|
||||
listOf(Items.ADAMANT_PLATELEGS_1073,Items.ADAMANT_PLATEBODY_1124,Items.ADAMANT_KITESHIELD_1199,Items.ADAMANT_LONGSWORD_1301, Items.TEAM_29_CAPE_4371),
|
||||
listOf(Items.ADAMANT_PLATESKIRT_1091,Items.ADAMANT_PLATEBODY_1124,Items.ADAMANT_KITESHIELD_1199,Items.ADAMANT_LONGSWORD_1301, Items.TEAM_30_CAPE_4373),
|
||||
listOf(Items.ADAMANT_PLATELEGS_1073,Items.ADAMANT_PLATEBODY_1124, Items.TEAM_29_CAPE_4371),
|
||||
listOf(Items.ADAMANT_PLATESKIRT_1091,Items.ADAMANT_PLATEBODY_1124, Items.TEAM_30_CAPE_4373),
|
||||
listOf(Items.ADAMANT_PLATESKIRT_1091,Items.ADAMANT_CHAINBODY_1111, Items.TEAM_30_CAPE_4373),
|
||||
listOf(Items.ADAMANT_PLATELEGS_1073,Items.ADAMANT_CHAINBODY_1111, Items.TEAM_31_CAPE_4375),
|
||||
listOf(Items.ADAMANT_PLATESKIRT_1091,Items.ADAMANT_CHAINBODY_1111,Items.ADAMANT_FULL_HELM_1161, Items.TEAM_30_CAPE_4373),
|
||||
listOf(Items.ADAMANT_PLATELEGS_1073,Items.ADAMANT_CHAINBODY_1111,Items.ADAMANT_FULL_HELM_1161, Items.TEAM_31_CAPE_4375),
|
||||
listOf(Items.ADAMANT_PLATELEGS_1073,Items.ADAMANT_CHAINBODY_1111,Items.ADAMANT_2H_SWORD_1317, Items.TEAM_34_CAPE_4381),
|
||||
listOf(Items.ADAMANT_PLATELEGS_1073,Items.ADAMANT_CHAINBODY_1111,Items.ADAMANT_SCIMITAR_1331, Items.TEAM_35_CAPE_4383),
|
||||
listOf(Items.ADAMANT_PLATELEGS_1073,Items.ADAMANT_CHAINBODY_1111,Items.ADAMANT_BATTLEAXE_1371, Items.TEAM_35_CAPE_4383),
|
||||
listOf(), // No equipment
|
||||
listOf(Items.GREEN_DHIDE_BODY_1135,Items.GREEN_DHIDE_CHAPS_1099,Items.GREEN_DHIDE_VAMB_1065,Items.GREEN_DHIDE_COIF_100_12936,Items.AVAS_ACCUMULATOR_10499),
|
||||
listOf(Items.GREEN_DHIDE_BODY_1135,Items.GREEN_DHIDE_CHAPS_1099,Items.GREEN_DHIDE_VAMB_1065,Items.GREEN_DHIDE_COIF_100_12936,Items.ADAMANT_CROSSBOW_9183,Items.AVAS_ACCUMULATOR_10499),
|
||||
listOf(Items.TEAM_10_CAPE_4333),
|
||||
listOf(Items.TEAM_1_CAPE_4315),
|
||||
listOf(), // No equipment
|
||||
listOf(), // No equipment
|
||||
listOf())
|
||||
|
||||
val RICHSETS = arrayOf(
|
||||
listOf(Items.RUNE_PLATELEGS_1079,Items.RUNE_PLATEBODY_1127,Items.RUNE_KITESHIELD_1201,Items.RUNE_FULL_HELM_1163,Items.RUNE_LONGSWORD_1303,Items.TEAM_29_CAPE_4371),
|
||||
listOf(Items.RUNE_PLATESKIRT_1093,Items.RUNE_PLATEBODY_1127,Items.RUNE_KITESHIELD_1201,Items.RUNE_FULL_HELM_1163,Items.RUNE_LONGSWORD_1303,Items.TEAM_30_CAPE_4373),
|
||||
listOf(Items.RUNE_PLATESKIRT_1093,Items.RUNE_PLATEBODY_1127, Items.TEAM_29_CAPE_4371),
|
||||
listOf(Items.RUNE_PLATELEGS_1079,Items.RUNE_PLATEBODY_1127,Items.RUNE_FULL_HELM_1163,Items.TEAM_29_CAPE_4371),
|
||||
listOf(Items.RUNE_PLATELEGS_1079,Items.RUNE_PLATEBODY_1127,Items.RUNE_BERSERKER_SHIELD_100_12929,Items.TEAM_29_CAPE_4371),
|
||||
listOf(Items.RUNE_PLATESKIRT_1093,Items.RUNE_PLATEBODY_1127,Items.TEAM_30_CAPE_4373),
|
||||
listOf(Items.RUNE_PLATESKIRT_1093,Items.RUNE_CHAINBODY_1113,Items.TEAM_30_CAPE_4373),
|
||||
listOf(Items.RUNE_PLATELEGS_1079,Items.RUNE_CHAINBODY_1113,Items.TEAM_31_CAPE_4375),
|
||||
listOf(Items.RUNE_PLATESKIRT_1093,Items.RUNE_CHAINBODY_1113,Items.RUNE_FULL_HELM_1163,Items.TEAM_30_CAPE_4373),
|
||||
listOf(Items.RUNE_PLATELEGS_1079,Items.RUNE_CHAINBODY_1113,Items.RUNE_FULL_HELM_1163,Items.TEAM_31_CAPE_4375),
|
||||
listOf(Items.RUNE_PLATELEGS_1079,Items.RUNE_CHAINBODY_1113,Items.RUNE_2H_SWORD_1319,Items.TEAM_34_CAPE_4381),
|
||||
listOf(Items.RUNE_PLATELEGS_1079,Items.RUNE_CHAINBODY_1113,Items.RUNE_SCIMITAR_1333,Items.TEAM_35_CAPE_4383),
|
||||
listOf(Items.RUNE_PLATELEGS_1079,Items.RUNE_CHAINBODY_1113,Items.RUNE_BATTLEAXE_1373,Items.TEAM_35_CAPE_4383),
|
||||
listOf(Items.RUNE_PLATELEGS_1079,Items.RUNE_PLATEBODY_1127,Items.ABYSSAL_WHIP_4151,Items.TEAM_29_CAPE_4371),
|
||||
listOf(), // No equipment
|
||||
listOf(Items.RUNE_PLATEBODY_G_2615,Items.RUNE_PLATELEGS_G_2618,Items.RUNE_KITESHIELD_G_2621,Items.RUNE_FULL_HELMG_2619, Items.TEAM_27_CAPE_4367),
|
||||
listOf(Items.RUNE_PLATEBODY_T_2623,Items.RUNE_PLATELEGS_T_2625,Items.RUNE_KITESHIELD_T_2629,Items.RUNE_FULL_HELM_T_2627, Items.TEAM_27_CAPE_4367),
|
||||
listOf(Items.GILDED_PLATEBODY_3481,Items.GILDED_PLATELEGS_3483,Items.CAPE_1030),
|
||||
listOf(Items.ZAMORAK_PLATEBODY_2653,Items.ZAMORAK_PLATELEGS_2655,Items.ZAMORAK_FULL_HELM_2657),
|
||||
listOf(Items.SARADOMIN_PLATEBODY_2661,Items.SARADOMIN_PLATELEGS_2663,Items.SARADOMIN_FULL_HELM_2665),
|
||||
listOf(Items.GUTHIX_PLATEBODY_2669,Items.GUTHIX_PLATELEGS_2671,Items.GUTHIX_FULL_HELM_2673),
|
||||
listOf(Items.ZAMORAK_PLATEBODY_2653,Items.ZAMORAK_PLATELEGS_2655,Items.ZAMORAK_FULL_HELM_2657,Items.ZAMORAK_CAPE_2414),
|
||||
listOf(Items.SARADOMIN_PLATEBODY_2661,Items.SARADOMIN_PLATELEGS_2663,Items.SARADOMIN_FULL_HELM_2665,Items.SARADOMIN_CAPE_2412),
|
||||
listOf(Items.GUTHIX_PLATEBODY_2669,Items.GUTHIX_PLATELEGS_2671,Items.GUTHIX_FULL_HELM_2673,Items.GUTHIX_CAPE_2413),
|
||||
listOf(Items.THIRD_AGE_ROBE_10340,Items.THIRD_AGE_ROBE_TOP_10338,Items.SANTA_HAT_1050),
|
||||
listOf(), // No equipment
|
||||
listOf(Items.DRAGON_PLATELEGS_4087,Items.DRAGON_CHAINBODY_3140,Items.ABYSSAL_WHIP_4151,Items.DRAGON_FULL_HELM_11335),
|
||||
listOf(Items.DRAGON_PLATELEGS_4087,Items.DRAGON_CHAINBODY_3140,Items.DRAGONFIRE_SHIELD_11283,Items.DRAGON_FULL_HELM_11335),
|
||||
listOf(), // No equipment
|
||||
listOf(Items.BLACK_DHIDE_BODY_2503,Items.BLACK_DHIDE_CHAPS_2497,Items.BLACK_DHIDE_VAMB_2491,Items.RUNE_CROSSBOW_9185,Items.AVAS_ACCUMULATOR_10499),
|
||||
listOf(Items.BLACK_DHIDE_BODY_2503,Items.BLACK_DHIDE_CHAPS_2497,Items.BLACK_DHIDE_VAMB_2491,Items.BLACK_DHIDE_COIF_100_12957,Items.RUNE_CROSSBOW_9185,Items.RUNE_KITESHIELD_1201),
|
||||
listOf(Items.ELITE_BLACK_PLATEBODY_14492,Items.ELITE_BLACK_PLATELEGS_14490, Items.ELITE_BLACK_FULL_HELM_14494),
|
||||
listOf(Items.BATTLE_ROBE_BOTTOM_100_12880,Items.BATTLE_ROBE_TOP_100_12873,Items.PURPLE_PARTYHAT_1046),
|
||||
listOf(Items.ZURIELS_ROBE_BOTTOM_13862,Items.ZURIELS_ROBE_TOP_13858,Items.ZURIELS_HOOD_13864,Items.ZURIELS_HOOD_13864,Items.ZURIELS_STAFF_13867),
|
||||
listOf(Items.VESTAS_CHAINBODY_13887,Items.VESTAS_PLATESKIRT_13893),
|
||||
listOf(), // No equipment
|
||||
listOf(), // No equipment
|
||||
listOf())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import core.game.node.entity.combat.spell.CombatSpell;
|
|||
|
||||
/**
|
||||
* Represents an entity's current battle state.
|
||||
*
|
||||
* @author Emperor
|
||||
*/
|
||||
public final class BattleState {
|
||||
|
|
@ -99,6 +100,7 @@ public final class BattleState {
|
|||
|
||||
/**
|
||||
* Constructs a new {@code BattleState} {@Code Object}
|
||||
*
|
||||
* @param victim The victim entity.
|
||||
*/
|
||||
public BattleState(Entity entity, Entity victim) {
|
||||
|
|
@ -134,6 +136,7 @@ public final class BattleState {
|
|||
|
||||
/**
|
||||
* Gets the estimatedHit.
|
||||
*
|
||||
* @return The estimatedHit.
|
||||
*/
|
||||
public int getEstimatedHit() {
|
||||
|
|
@ -142,6 +145,7 @@ public final class BattleState {
|
|||
|
||||
/**
|
||||
* Sets the estimated hit.
|
||||
*
|
||||
* @param estimatedHit The estimated hit to set.
|
||||
*/
|
||||
public void setEstimatedHit(int estimatedHit) {
|
||||
|
|
@ -164,6 +168,7 @@ public final class BattleState {
|
|||
|
||||
/**
|
||||
* Gets the recoilDamage.
|
||||
*
|
||||
* @return The recoilDamage.
|
||||
*/
|
||||
public int getRecoilDamage() {
|
||||
|
|
@ -172,6 +177,7 @@ public final class BattleState {
|
|||
|
||||
/**
|
||||
* Sets the recoilDamage.
|
||||
*
|
||||
* @param recoilDamage The recoilDamage to set.
|
||||
*/
|
||||
public void setRecoilDamage(int recoilDamage) {
|
||||
|
|
@ -236,6 +242,7 @@ public final class BattleState {
|
|||
|
||||
/**
|
||||
* Gets the maximumHit.
|
||||
*
|
||||
* @return The maximumHit.
|
||||
*/
|
||||
public int getMaximumHit() {
|
||||
|
|
@ -244,6 +251,7 @@ public final class BattleState {
|
|||
|
||||
/**
|
||||
* Sets the maximumHit.
|
||||
*
|
||||
* @param maximumHit The maximumHit to set.
|
||||
*/
|
||||
public void setMaximumHit(int maximumHit) {
|
||||
|
|
@ -252,6 +260,7 @@ public final class BattleState {
|
|||
|
||||
/**
|
||||
* Gets the rangeWeapon.
|
||||
*
|
||||
* @return The rangeWeapon.
|
||||
*/
|
||||
public RangeWeapon getRangeWeapon() {
|
||||
|
|
@ -260,6 +269,7 @@ public final class BattleState {
|
|||
|
||||
/**
|
||||
* Sets the rangeWeapon.
|
||||
*
|
||||
* @param rangeWeapon The rangeWeapon to set.
|
||||
*/
|
||||
public void setRangeWeapon(RangeWeapon rangeWeapon) {
|
||||
|
|
@ -268,6 +278,7 @@ public final class BattleState {
|
|||
|
||||
/**
|
||||
* Gets the ammunition.
|
||||
*
|
||||
* @return The ammunition.
|
||||
*/
|
||||
public Ammunition getAmmunition() {
|
||||
|
|
@ -276,6 +287,7 @@ public final class BattleState {
|
|||
|
||||
/**
|
||||
* Sets the ammunition.
|
||||
*
|
||||
* @param ammunition The ammunition to set.
|
||||
*/
|
||||
public void setAmmunition(Ammunition ammunition) {
|
||||
|
|
@ -284,6 +296,7 @@ public final class BattleState {
|
|||
|
||||
/**
|
||||
* Gets the frozen.
|
||||
*
|
||||
* @return The frozen.
|
||||
*/
|
||||
public boolean isFrozen() {
|
||||
|
|
@ -292,6 +305,7 @@ public final class BattleState {
|
|||
|
||||
/**
|
||||
* Sets the frozen.
|
||||
*
|
||||
* @param frozen The frozen to set.
|
||||
*/
|
||||
public void setFrozen(boolean frozen) {
|
||||
|
|
@ -300,6 +314,7 @@ public final class BattleState {
|
|||
|
||||
/**
|
||||
* Gets the style.
|
||||
*
|
||||
* @return The style.
|
||||
*/
|
||||
public CombatStyle getStyle() {
|
||||
|
|
@ -308,6 +323,7 @@ public final class BattleState {
|
|||
|
||||
/**
|
||||
* Sets the style.
|
||||
*
|
||||
* @param style The style to set.
|
||||
*/
|
||||
public void setStyle(CombatStyle style) {
|
||||
|
|
@ -316,6 +332,7 @@ public final class BattleState {
|
|||
|
||||
/**
|
||||
* Gets the armourEffect.
|
||||
*
|
||||
* @return The armourEffect.
|
||||
*/
|
||||
public ArmourSet getArmourEffect() {
|
||||
|
|
@ -324,6 +341,7 @@ public final class BattleState {
|
|||
|
||||
/**
|
||||
* Sets the armourEffect.
|
||||
*
|
||||
* @param armourEffect The armourEffect to set.
|
||||
*/
|
||||
public void setArmourEffect(ArmourSet armourEffect) {
|
||||
|
|
@ -332,6 +350,7 @@ public final class BattleState {
|
|||
|
||||
/**
|
||||
* Gets the attacking entity.
|
||||
*
|
||||
* @return The entity.
|
||||
*/
|
||||
public Entity getAttacker() {
|
||||
|
|
@ -340,10 +359,9 @@ public final class BattleState {
|
|||
|
||||
public int getTotalDamage() {
|
||||
int hit = Math.max(estimatedHit, 0) + Math.max(secondaryHit, 0);
|
||||
|
||||
if (targets != null) {
|
||||
for (BattleState s : targets) {
|
||||
if (s != null) {
|
||||
if (s != null && s != this) {
|
||||
hit += Math.max(s.getEstimatedHit(), 0) + Math.max(s.getSecondaryHit(), 0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -254,9 +254,15 @@ abstract class CombatSwingHandler(var type: CombatStyle?) {
|
|||
?: return InteractionType.STILL_INTERACT //if we cannot derive a direction, it's because both tiles are the same, so hand off control to the main logic which already handles this case
|
||||
var next = closestEntityTile
|
||||
|
||||
while (next.getDistance(closestVictimTile) > 3) { //skip the initial gap in distance if it exists, because standard pathfinding would already stop us before this point if something was between us and the NPC or vice versa
|
||||
//Skip the initial gap in distance if it exists, because standard pathfinding would already stop us before this point if something was between us and the NPC or vice versa.
|
||||
//A fixed-direction walk can only arrive within its starting distance in steps; on oblique approaches it
|
||||
//passes beside the target and never converges, so the walk is hard-capped at that many steps.
|
||||
val maxSkipSteps = next.getDistance(closestVictimTile).toInt() + 1
|
||||
for (i in 0 until maxSkipSteps) {
|
||||
if (next.getDistance(closestVictimTile) <= 3) break
|
||||
next = next.transform(dir)
|
||||
}
|
||||
if (next.getDistance(closestVictimTile) > 3) return InteractionType.STILL_INTERACT //never converged (oblique approach), so defer to the range checks instead
|
||||
|
||||
var result: InteractionType = InteractionType.STILL_INTERACT
|
||||
val maxIterations = next.getDistance(closestVictimTile).toInt()
|
||||
|
|
|
|||
|
|
@ -253,10 +253,14 @@ open class MeleeSwingHandler (vararg flags: SwingHandlerFlag)
|
|||
|
||||
return 1.0 + (e!!.skills.maximumLifepoints - e.skills.lifepoints) * 0.01
|
||||
}
|
||||
var multiplier = 1.0
|
||||
if(e is Player && e.isWearingVoid(CombatStyle.MELEE) && (skillId == Skills.ATTACK || skillId == Skills.STRENGTH)) {
|
||||
return 1.1
|
||||
multiplier += 0.1
|
||||
}
|
||||
return 1.0
|
||||
if (e is Player && e.properties.armourSet === ArmourSet.BERSERKER_NECKLACE_SETS && skillId == Skills.STRENGTH) {
|
||||
multiplier += 0.2
|
||||
}
|
||||
return multiplier
|
||||
}
|
||||
|
||||
override fun getArmourSet(e: Entity?): ArmourSet? {
|
||||
|
|
@ -269,6 +273,9 @@ open class MeleeSwingHandler (vararg flags: SwingHandlerFlag)
|
|||
if (ArmourSet.VERAC.isUsing(e)) {
|
||||
return ArmourSet.VERAC
|
||||
}
|
||||
if (ArmourSet.BERSERKER_NECKLACE_SETS.isUsing(e)) {
|
||||
return ArmourSet.BERSERKER_NECKLACE_SETS
|
||||
}
|
||||
return if (ArmourSet.TORAG.isUsing(e)) {
|
||||
ArmourSet.TORAG
|
||||
} else super.getArmourSet(e)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import core.game.node.entity.player.Player;
|
|||
import core.game.node.item.Item;
|
||||
import core.game.world.update.flag.context.Graphics;
|
||||
import core.tools.RandomFunction;
|
||||
import org.rs09.consts.Items;
|
||||
|
||||
/**
|
||||
* Represents the types of armour sets.
|
||||
|
|
@ -129,6 +130,15 @@ public enum ArmourSet {
|
|||
}
|
||||
return super.isUsing(e);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Berserker Necklace sets
|
||||
*/
|
||||
BERSERKER_NECKLACE_SETS(null, new int[][] { { Items.BERSERKER_NECKLACE_11128 }, { Items.TOKTZ_XIL_AK_6523, Items.TOKTZ_XIL_EK_6525, Items.TZHAAR_KET_EM_6527, Items.TZHAAR_KET_OM_6528 } }) {
|
||||
@Override
|
||||
public boolean isUsing(Entity e) {
|
||||
return super.isUsing(e);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -148,8 +158,9 @@ public enum ArmourSet {
|
|||
*/
|
||||
private ArmourSet(Graphics endGraphic, int[][] set) {
|
||||
this.endGraphic = endGraphic;
|
||||
this.sets = new Item[4][5];
|
||||
this.sets = new Item[set.length][];
|
||||
for (int i = 0; i < set.length; i++) {
|
||||
sets[i] = new Item[set[i].length];
|
||||
for (int k = 0; k < sets[i].length; k++) {
|
||||
sets[i][k] = new Item(set[i][k]);
|
||||
}
|
||||
|
|
@ -197,7 +208,7 @@ public enum ArmourSet {
|
|||
}
|
||||
}
|
||||
}
|
||||
return hits == 4;
|
||||
return hits == sets.length;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -751,6 +751,18 @@ public class NPC extends Entity {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms this NPC with HP carried over from pre-transformed entity.
|
||||
* HP adjustments (ie healing/scaling HP to new maximum) should be done manually per-NPC
|
||||
* @param id The new NPC id.
|
||||
*/
|
||||
public NPC transformWithHpCarryover(int id) {
|
||||
int lp = getSkills().getLifepoints();
|
||||
this.transform(id);
|
||||
getSkills().setLifepoints(lp);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms this NPC back to original.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -45,6 +45,10 @@ public final class SystemTermination {
|
|||
log(this.getClass(), Log.INFO, "Stopping all bots...");
|
||||
AIRepository.clearAllBots();
|
||||
Server.getReactor().terminate();
|
||||
if (Server.getWebSocketServer() != null) {
|
||||
Server.getWebSocketServer().stop(1000, "Server shutting down");
|
||||
Server.setWebSocketServer(null);
|
||||
}
|
||||
log(this.getClass(), Log.INFO, "Stopping all pulses...");
|
||||
GameWorld.getMajorUpdateWorker().stop();
|
||||
for (Iterator<Player> it = Repository.getPlayers().iterator(); it.hasNext();) {
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ class VisualCommand : CommandPlugin() {
|
|||
return true
|
||||
}
|
||||
location = if (args.size > 2) Location.create(args[1]!!.toInt(), args[2]!!.toInt(), player!!.location.z) else player!!.location
|
||||
`object` = RegionManager.getObject(location)
|
||||
`object` = RegionManager.getObject(location!!)
|
||||
if (`object` == null) {
|
||||
player!!.debug("error: object not found in region cache.")
|
||||
return true
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package core.game.system.command.sets
|
||||
|
||||
import content.global.handlers.iface.*
|
||||
import content.global.skill.summoning.familiar.Familiar
|
||||
import content.global.skill.cooking.fermenting.BrewGrowth
|
||||
import content.global.skill.farming.timers.*
|
||||
import content.minigame.fishingtrawler.TrawlerLoot
|
||||
|
|
@ -40,6 +41,27 @@ import java.awt.HeadlessException
|
|||
import java.awt.Toolkit
|
||||
import java.awt.datatransfer.StringSelection
|
||||
|
||||
private const val INFINITE_SPECIAL_ATTRIBUTE = "infinite-special"
|
||||
private const val ALLOW_ADMIN_AGGRESSION_ATTRIBUTE = "/save:allow_admin_aggression"
|
||||
|
||||
private fun resolveBooleanToggle(player: Player, args: Array<String>, attribute: String): Boolean? {
|
||||
return when {
|
||||
args.size < 2 -> !player.getAttribute(attribute, false)
|
||||
args[1].equals("true", ignoreCase = true) -> true
|
||||
args[1].equals("false", ignoreCase = true) -> false
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun setBooleanAttribute(player: Player, attribute: String, enabled: Boolean, label: String) {
|
||||
if (enabled) {
|
||||
setAttribute(player, attribute, true)
|
||||
} else {
|
||||
removeAttribute(player, attribute)
|
||||
}
|
||||
sendMessage(player, "$label is now ${if (enabled) "enabled" else "disabled"}.")
|
||||
}
|
||||
|
||||
@Initializable
|
||||
class MiscCommandSet : CommandSet(Privilege.ADMIN){
|
||||
override fun defineCommands() {
|
||||
|
|
@ -662,29 +684,49 @@ class MiscCommandSet : CommandSet(Privilege.ADMIN){
|
|||
notify(player,"No parent NPC found.")
|
||||
}
|
||||
}
|
||||
define("infinitespecial", Privilege.ADMIN, "::infinitespecial <true|false>", "Turns the infinite special-attack flag on or off for your player."){ player, args ->
|
||||
val usageStr = "Usage: ::infinitespecial true|false"
|
||||
if(args.size < 2){
|
||||
reject(player, usageStr)
|
||||
}
|
||||
when(args[1]){
|
||||
"true" -> player.setAttribute("infinite-special", true)
|
||||
"false" -> player.removeAttribute("infinite-special")
|
||||
else -> reject(player, usageStr)
|
||||
}
|
||||
}
|
||||
define("allowaggro", Privilege.ADMIN, "allowaggro true | false", "Toggle NPCs aggroing on you") { player, args ->
|
||||
val usageStr = "Usage: ::allowaggro true | false"
|
||||
if(args.size < 2) {
|
||||
notify(player, "Allow admin aggression is currently ${player.getAttribute("/save:allow_admin_aggression", false)}")
|
||||
define(
|
||||
"infinitespecial",
|
||||
Privilege.ADMIN,
|
||||
"::infinitespecial [true|false]",
|
||||
"Toggles infinite special attack energy for your player (special-attack flag)."
|
||||
) { player, args ->
|
||||
val enabled = resolveBooleanToggle(player, args, INFINITE_SPECIAL_ATTRIBUTE)
|
||||
if (enabled == null) {
|
||||
reject(player, "Usage: ::infinitespecial [true|false]")
|
||||
return@define
|
||||
}
|
||||
when(args[1]) {
|
||||
"true" -> player.setAttribute("/save:allow_admin_aggression", true)
|
||||
"false" -> player.setAttribute("/save:allow_admin_aggression", false)
|
||||
else -> reject(player, usageStr)
|
||||
setBooleanAttribute(player, INFINITE_SPECIAL_ATTRIBUTE, enabled, "Infinite special attack")
|
||||
}
|
||||
define(
|
||||
"infinitespecialmove",
|
||||
Privilege.ADMIN,
|
||||
"::infinitespecialmove [true|false]",
|
||||
"Toggles infinite Summoning familiar special move points for your player."
|
||||
) { player, args ->
|
||||
val enabled = resolveBooleanToggle(player, args, Familiar.INFINITE_SPECIAL_MOVE_ATTRIBUTE)
|
||||
if (enabled == null) {
|
||||
reject(player, "Usage: ::infinitespecialmove [true|false]")
|
||||
return@define
|
||||
}
|
||||
notify(player, "Setting aggro ${args[1]}")
|
||||
setBooleanAttribute(
|
||||
player,
|
||||
Familiar.INFINITE_SPECIAL_MOVE_ATTRIBUTE,
|
||||
enabled,
|
||||
"Infinite familiar special move energy"
|
||||
)
|
||||
}
|
||||
define(
|
||||
"allowaggro",
|
||||
Privilege.ADMIN,
|
||||
"::allowaggro [true|false]",
|
||||
"Toggles NPCs aggroing on you as an admin."
|
||||
) { player, args ->
|
||||
val enabled = resolveBooleanToggle(player, args, ALLOW_ADMIN_AGGRESSION_ATTRIBUTE)
|
||||
if (enabled == null) {
|
||||
reject(player, "Usage: ::allowaggro [true|false]")
|
||||
return@define
|
||||
}
|
||||
setBooleanAttribute(player, ALLOW_ADMIN_AGGRESSION_ATTRIBUTE, enabled, "Admin NPC aggression")
|
||||
}
|
||||
|
||||
define("rules", Privilege.STANDARD, "", "Shows the rules."){ player, _ ->
|
||||
|
|
|
|||
|
|
@ -29,20 +29,38 @@ class QuestCommandSet : CommandSet(Privilege.ADMIN){
|
|||
/**
|
||||
* Displays the currently implemented quests with debug information
|
||||
*/
|
||||
define("quest", usage = "::quest [player-name]", description = "Shows quest stages for you, or for [player-name] if provided."){player,args ->
|
||||
if (args.size < 3) {
|
||||
val lookupP = if (args.size == 1) {
|
||||
player
|
||||
} else if (Repository.getPlayerByName(args[1]) != null) {
|
||||
Repository.getPlayerByName(args[1]) ?: return@define
|
||||
define("quest",
|
||||
usage = "::quest [-p username] [quest-filter]",
|
||||
description = "Shows quest stages for you, or for [username] if -p is used. Add optional text to filter by quest name."
|
||||
) { player, args ->
|
||||
|
||||
var target = player
|
||||
var filter: String? = null
|
||||
|
||||
if (args.size > 1) {
|
||||
if (args[1].equals("-p", ignoreCase = true)) {
|
||||
// need at least 3 arguments if -p is used: command, -p, username
|
||||
if (args.size < 3) {
|
||||
reject(player, "ERROR: Missing player name. Usage: ::quest -p <username> [quest-filter]")
|
||||
return@define
|
||||
}
|
||||
|
||||
val playerName = args[2]
|
||||
target = Repository.getPlayerByName(playerName) ?: run {
|
||||
reject(player, "ERROR: Username '$playerName' not found.")
|
||||
return@define
|
||||
}
|
||||
|
||||
// arguments after the player name are the quest filter
|
||||
if (args.size > 3) {
|
||||
filter = args.drop(3).joinToString(" ")
|
||||
}
|
||||
} else {
|
||||
reject(player, "ERROR: Username not found. Usage: ::quest <username>")
|
||||
return@define
|
||||
// no -p, so the arguments are the quest filter
|
||||
filter = args.drop(1).joinToString(" ")
|
||||
}
|
||||
sendQuestsDebug(player, lookupP)
|
||||
} else {
|
||||
reject(player, "Usage: ::quest || ::quest <username>")
|
||||
}
|
||||
sendQuestsDebug(player, target, filter)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -96,24 +114,49 @@ class QuestCommandSet : CommandSet(Privilege.ADMIN){
|
|||
/**
|
||||
* Sends the list of quests with debug information
|
||||
* @param admin the player.
|
||||
* @param lookupUser the target player to view quests for.
|
||||
* @param questFilter optional string to filter quests by name.
|
||||
*/
|
||||
private fun sendQuestsDebug(admin: Player?, lookupUser: Player?) {
|
||||
private fun sendQuestsDebug(admin: Player?, lookupUser: Player?, questFilter: String? = null) {
|
||||
admin!!.interfaceManager.open(Component(275))
|
||||
|
||||
// clear interface lines
|
||||
for (i in 0..310) {
|
||||
admin.packetDispatch.sendString("", 275, i)
|
||||
}
|
||||
|
||||
var lineId = 11
|
||||
|
||||
// title
|
||||
admin.packetDispatch.sendString("<col=ecf0f1>${lookupUser!!.username}'s Quest Debug</col>", 275, 2)
|
||||
for (q in QuestRepository.getQuests().values) {
|
||||
// Add a space to beginning and end of string for the strikethrough
|
||||
|
||||
// filtered quests
|
||||
val questsToDisplay = QuestRepository.getQuests().values.filter { q ->
|
||||
questFilter.isNullOrBlank() || q.quest.toString().contains(questFilter, ignoreCase = true)
|
||||
}
|
||||
|
||||
// no quests to filter
|
||||
if (questsToDisplay.isEmpty()) {
|
||||
admin.packetDispatch.sendString("<col=ff0000>No quests found matching: $questFilter</col>", 275, lineId++)
|
||||
return
|
||||
}
|
||||
|
||||
for (q in questsToDisplay) {
|
||||
// can't display more than 308 lines
|
||||
if (lineId >= 308) {
|
||||
admin.packetDispatch.sendString("<col=ff0000>List truncated (too many results).</col>", 275, lineId)
|
||||
break
|
||||
}
|
||||
|
||||
val stage = lookupUser.questRepository.getStage(q)
|
||||
val statusColor = when {
|
||||
stage >= 100 -> "80ff00"
|
||||
stage in 1..99 -> "ff8400"
|
||||
else -> "ff0000"
|
||||
}
|
||||
|
||||
admin.packetDispatch.sendString("<col=ecf0f1>${q.quest}</col>", 275, lineId++)
|
||||
admin.packetDispatch.sendString("<col=ecf0f1>Index: </col><col=ff1f1f><shad=2>${q.index}</shad></col> | <col=ecf0f1>Stage:</col> <col=$statusColor><shad=2>${lookupUser.questRepository.getStage(q)}</shad></col>", 275, lineId++)
|
||||
admin.packetDispatch.sendString("<col=ecf0f1>Index: </col><col=ff1f1f><shad=2>${q.index}</shad></col> | <col=ecf0f1>Stage:</col> <col=$statusColor><shad=2>${stage}</shad></col>", 275, lineId++)
|
||||
admin.packetDispatch.sendString("<str> ", 275, lineId++)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ class GroundSpawnLoader {
|
|||
* Method used to initialize this spawn.
|
||||
*/
|
||||
fun init(): GroundItem {
|
||||
if (respawnRate shr 16 == 0) respawnRate = respawnRate or (respawnRate shl 16)
|
||||
return GroundItemManager.create(this)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -176,6 +176,11 @@ object ServerConfigParser {
|
|||
ServerConstants.BOOSTED_TRAWLER_REWARDS = data.getBoolean("world.boosted_trawler_rewards", false)
|
||||
ServerConstants.CONNECTIVITY_CHECK_URL = data.getString("server.connectivity_check_url", "https://google.com,https://2009scape.org")
|
||||
ServerConstants.CONNECTIVITY_TIMEOUT = data.getLong("server.connectivity_timeout", 500L).toInt()
|
||||
ServerConstants.WEBSOCKET_ENABLED = data.getBoolean("server.websocket_enabled", false)
|
||||
ServerConstants.WEBSOCKET_PORT = data.getLong("server.websocket_port", 0L).toInt()
|
||||
ServerConstants.WEBSOCKET_TLS_ENABLED = data.getBoolean("server.websocket_tls_enabled", false)
|
||||
ServerConstants.WEBSOCKET_TLS_KEYSTORE_PATH = data.getString("server.websocket_tls_keystore_path", "")
|
||||
ServerConstants.WEBSOCKET_TLS_KEYSTORE_PASSWORD = data.getString("server.websocket_tls_keystore_password", "")
|
||||
|
||||
val logLevel = data.getString("server.log_level", "VERBOSE").uppercase()
|
||||
ServerConstants.LOG_LEVEL = parseEnumEntry<LogLevel>(logLevel) ?: LogLevel.VERBOSE
|
||||
|
|
|
|||
|
|
@ -1,578 +0,0 @@
|
|||
package core.game.world.map;
|
||||
|
||||
import core.game.interaction.DestinationFlag;
|
||||
import core.game.node.Node;
|
||||
import core.game.world.map.path.Path;
|
||||
import core.game.world.map.path.Pathfinder;
|
||||
import core.tools.RandomFunction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import core.api.utils.Vector;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.lang.Math;
|
||||
|
||||
/**
|
||||
* Represents a location on the world map.
|
||||
* @author Emperor
|
||||
*/
|
||||
public final class Location extends Node {
|
||||
|
||||
/**
|
||||
* The x-coordinate.
|
||||
*/
|
||||
private int x;
|
||||
|
||||
/**
|
||||
* The y-coordinate.
|
||||
*/
|
||||
private int y;
|
||||
|
||||
/**
|
||||
* The plane.
|
||||
*/
|
||||
private int z;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code Location} {@code Object}.
|
||||
* @param x The x-coordinate.
|
||||
* @param y The y-coordinate.
|
||||
* @param z The z-coordinate.
|
||||
*/
|
||||
public Location(int x, int y, int z) {
|
||||
super(null, null);
|
||||
super.destinationFlag = DestinationFlag.LOCATION;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
if (z < 0) {
|
||||
z += 4;
|
||||
}
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code Location} {@code Object}
|
||||
* @param x The x-coordinate.
|
||||
* @param y The y-coordinate.
|
||||
*/
|
||||
public Location(int x, int y) {
|
||||
this(x, y, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code Location} {@code Object}.
|
||||
* @param x The x-coordinate.
|
||||
* @param y The y coordinate.
|
||||
* @param z The z-coordinate.
|
||||
* @param randomizer The amount we should randomize the x and y coordinates
|
||||
* with (x + random(randomizer), y + random(randomizer)).
|
||||
*/
|
||||
public Location(int x, int y, int z, int randomizer) {
|
||||
this(x + RandomFunction.getRandom(randomizer), y + RandomFunction.getRandom(randomizer), z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new Location.
|
||||
* @param x The x-coordinate.
|
||||
* @param y The y-coordinate.
|
||||
* @param z The z-coordinate.
|
||||
* @return The constructed location.
|
||||
*/
|
||||
public static Location create(int x, int y, int z) {
|
||||
return new Location(x, y, z);
|
||||
}
|
||||
|
||||
public static Location create(int x, int y) {
|
||||
return new Location(x, y, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of the given location.
|
||||
* @param location The given location.
|
||||
* @return The new instance.
|
||||
*/
|
||||
public static Location create(Location location) {
|
||||
return create(location.getX(), location.getY(), location.getZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a location instance with coordinates being the difference between
|
||||
* {@code other} & {@code location}.
|
||||
* @param location The first location.
|
||||
* @param other The other location.
|
||||
* @return The delta location.
|
||||
*/
|
||||
public static Location getDelta(Location location, Location other) {
|
||||
return Location.create(other.x - location.x, other.y - location.y, other.z - location.z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a random location near the main location.
|
||||
* @param main The main location.
|
||||
* @param radius The radius.
|
||||
* @param reachable If the locations should be able to reach eachother.
|
||||
* @return The location.
|
||||
*/
|
||||
public static Location getRandomLocation(Location main, int radius, boolean reachable) {
|
||||
Location location = RegionManager.getTeleportLocation(main, radius);
|
||||
if (!reachable) {
|
||||
return location;
|
||||
}
|
||||
Path path = Pathfinder.find(main, location, false, Pathfinder.DUMB);
|
||||
if (!path.isSuccessful()) {
|
||||
location = main;
|
||||
if (!path.getPoints().isEmpty()) {
|
||||
Point p = path.getPoints().getLast();
|
||||
location = Location.create(p.getX(), p.getY(), main.getZ());
|
||||
}
|
||||
}
|
||||
return location;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getLocation() {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this location is right next to the node (assuming the node is
|
||||
* size 1x1).
|
||||
* @param node The node to check.
|
||||
* @return {@code True} if this location is 1 tile north, west, south or
|
||||
* east of the node location.
|
||||
*/
|
||||
public boolean isNextTo(Node node) {
|
||||
Location l = node.getLocation();
|
||||
if (l.getY() == y) {
|
||||
return l.getX() - x == -1 || l.getX() - x == 1;
|
||||
}
|
||||
if (l.getX() == x) {
|
||||
return l.getY() - y == -1 || l.getY() - y == 1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the region id.
|
||||
* @return The region id.
|
||||
*/
|
||||
public int getRegionId() {
|
||||
return (x >> 6) << 8 | (y >> 6);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the users region with the one given
|
||||
* @return True if user is in given region
|
||||
*/
|
||||
public boolean isInRegion(int region) {
|
||||
return getRegionId() == region;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location incremented by the given coordinates.
|
||||
* @param dir The direction to transform this location.
|
||||
* @return The location.
|
||||
*/
|
||||
public Location transform(Direction dir) {
|
||||
return transform(dir, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location incremented by the given coordinates.
|
||||
* @param dir The direction to transform this location.
|
||||
* @param steps The amount of steps to move in this direction.
|
||||
* @return The location.
|
||||
*/
|
||||
public Location transform(Direction dir, int steps) {
|
||||
return new Location(x + (dir.getStepX() * steps), y + (dir.getStepY() * steps), this.z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location incremented by the given coordinates.
|
||||
* @param l incremental location
|
||||
* @return The location.
|
||||
*/
|
||||
public Location transform(Location l) {
|
||||
return new Location(x + l.getX(), y + l.getY(), this.z + l.getZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location incremented by the given coordinates.
|
||||
* @param diffX The x-difference.
|
||||
* @param diffY The y-difference.
|
||||
* @param z The height difference.
|
||||
* @return The location.
|
||||
*/
|
||||
public Location transform(int diffX, int diffY, int z) {
|
||||
return new Location(x + diffX, y + diffY, this.z + z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the other location is within viewing distance.
|
||||
* @param other The other location.
|
||||
* @return If you're within the other distance.
|
||||
*/
|
||||
public boolean withinDistance(Location other) {
|
||||
return withinDistance(other, MapDistance.RENDERING.getDistance());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if a player is within a specified distance.
|
||||
* @param other The other location.
|
||||
* @param dist The amount of distance.
|
||||
* @return If you're within the other distance.
|
||||
*/
|
||||
public boolean withinDistance(Location other, int dist) {
|
||||
if (other.z != z) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int a = (other.x - x);
|
||||
int b = (other.y - y);
|
||||
double product = Math.sqrt((a*a) + (b*b));
|
||||
return product <= dist;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if a player is within a specified distance using max norm distance.
|
||||
* @param other The other location.
|
||||
* @param dist The amount of distance.
|
||||
* @return If you're within the other distance.
|
||||
*/
|
||||
public boolean withinMaxnormDistance(Location other, int dist) {
|
||||
if (other.z != z) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int a = Math.abs(other.x - x);
|
||||
int b = Math.abs(other.y - y);
|
||||
double max = Math.max(a, b);
|
||||
return max <= dist;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the distance between you and the other.
|
||||
* @param other The other location.
|
||||
* @return The amount of distance between you and other.
|
||||
*/
|
||||
public double getDistance(Location other) {
|
||||
int xdiff = this.getX() - other.getX();
|
||||
int ydiff = this.getY() - other.getY();
|
||||
return Math.sqrt(xdiff * xdiff + ydiff * ydiff);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the distance between the first and the second specified distance.
|
||||
* @param first The first location.
|
||||
* @param second The other location.
|
||||
* @return The amount of distance between first and other.
|
||||
*/
|
||||
public static double getDistance(Location first, Location second) {
|
||||
int xdiff = first.getX() - second.getX();
|
||||
int ydiff = first.getY() - second.getY();
|
||||
return Math.sqrt(xdiff * xdiff + ydiff * ydiff);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the 8 tiles surrounding this location as an ArrayList<Location>
|
||||
*/
|
||||
public ArrayList<Location> getSurroundingTiles() {
|
||||
ArrayList<Location> locs = new ArrayList<>();
|
||||
|
||||
locs.add(transform(-1,-1,0));//SW
|
||||
locs.add(transform(0,-1,0)); //S
|
||||
locs.add(transform(1,-1,0)); //SE
|
||||
locs.add(transform(1,0,0)); //E
|
||||
locs.add(transform(1,1,0)); //NE
|
||||
locs.add(transform(0,1,0)); //N
|
||||
locs.add(transform(-1,1,0));//NW
|
||||
locs.add(transform(-1,0,0));//W
|
||||
|
||||
return locs;
|
||||
}
|
||||
|
||||
public ArrayList<Location> getCardinalTiles() {
|
||||
ArrayList<Location> locs = new ArrayList<>();
|
||||
|
||||
locs.add(transform(-1, 0, 0));
|
||||
locs.add(transform(0, -1, 0));
|
||||
locs.add(transform(1, 0, 0));
|
||||
locs.add(transform(0, 1, 0));
|
||||
return locs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a square of 3 x 3 tiles as an ArrayList<Location>
|
||||
*/
|
||||
public ArrayList<Location> get3x3Tiles() {
|
||||
ArrayList<Location> locs = new ArrayList<>();
|
||||
locs.add(transform(0,0,0)); //Center
|
||||
locs.add(transform(0,1,0)); //N
|
||||
locs.add(transform(1,1,0)); //NE
|
||||
locs.add(transform(1,0,0)); //E
|
||||
locs.add(transform(1,-1,0)); //SE
|
||||
locs.add(transform(0,-1,0)); //S
|
||||
locs.add(transform(-1,-1,0));//SW
|
||||
locs.add(transform(-1,0,0));//W
|
||||
locs.add(transform(-1,1,0));//NW
|
||||
return locs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the x position on the region chunk.
|
||||
* @return The x position on the region chunk.
|
||||
*/
|
||||
public int getChunkOffsetX() {
|
||||
int x = getLocalX();
|
||||
//return x - ((x / RegionChunk.SIZE) * RegionChunk.SIZE);
|
||||
return x & 7;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the y position on the region chunk.
|
||||
* @return The y position on the region chunk.
|
||||
*/
|
||||
public int getChunkOffsetY() {
|
||||
int y = getLocalY();
|
||||
//return y - ((y / RegionChunk.SIZE) * RegionChunk.SIZE);
|
||||
return y & 7;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the base location for the chunk this location is in.
|
||||
* @return The base location.
|
||||
*/
|
||||
public Location getChunkBase() {
|
||||
return create(getRegionX() << 3, getRegionY() << 3, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the region x-coordinate.
|
||||
* @return The region x-coordinate.
|
||||
*/
|
||||
public int getRegionX() {
|
||||
return x >> 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the region y-coordinate.
|
||||
* @return The region y-coordinate.
|
||||
*/
|
||||
public int getRegionY() {
|
||||
return y >> 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the local x-coordinate on the current region in [0, 64).
|
||||
* @return The local x-coordinate.
|
||||
*/
|
||||
public int getLocalX() {
|
||||
return x & 63;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the local y-coordinate on the current region in [0, 64).
|
||||
* @return The local y-coordinate.
|
||||
*/
|
||||
public int getLocalY() {
|
||||
return y & 63;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the scene x-coordinate in [48, 55] (note that 104/2 = 52).
|
||||
* @return The local x-coordinate.
|
||||
*/
|
||||
public int getSceneX() {
|
||||
return x - ((getRegionX() - 6) << 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the local y-coordinate in [48, 55] (note that 104/2 = 52).
|
||||
* @return The local y-coordinate.
|
||||
*/
|
||||
public int getSceneY() {
|
||||
return y - ((getRegionY() - 6) << 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the local x-coordinate.
|
||||
* @param loc The location containing the regional coordinates.
|
||||
* @return The local x-coordinate.
|
||||
*/
|
||||
public int getSceneX(Location loc) {
|
||||
return x - ((loc.getRegionX() - 6) << 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the local y-coordinate.
|
||||
* @param loc The location containing the regional coordinates.
|
||||
* @return The local y-coordinate.
|
||||
*/
|
||||
public int getSceneY(Location loc) {
|
||||
return y - ((loc.getRegionY() - 6) << 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the chunk's x-coordinate (0-7).
|
||||
* @return The x in the (8x8) region.
|
||||
*/
|
||||
public int getChunkX() {
|
||||
return getLocalX() >> 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the chunk's y-coordinate (0-7).
|
||||
* @return The y in the (8x8) region.
|
||||
*/
|
||||
public int getChunkY() {
|
||||
return getLocalY() >> 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof Location)) {
|
||||
return false;
|
||||
}
|
||||
Location loc = (Location) other;
|
||||
return loc.x == x && loc.y == y && loc.z == z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if these coordinates equal this location.
|
||||
* @param x the x.
|
||||
* @param y the y.
|
||||
* @param z the x.
|
||||
* @return {@code True} if so.
|
||||
*/
|
||||
public boolean equals(int x, int y, int z) {
|
||||
return equals(new Location(x, y, z));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[" + x + ", " + y + ", " + z + "]";
|
||||
}
|
||||
|
||||
public static Location fromString(String locString) {
|
||||
String trimmed = locString.replace("[", "").replace("]", "");
|
||||
String[] tokens = trimmed.split(",");
|
||||
return Location.create(
|
||||
Integer.parseInt(tokens[0].trim()),
|
||||
Integer.parseInt(tokens[1].trim()),
|
||||
Integer.parseInt(tokens[2].trim())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return z << 30 | x << 15 | y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the x.
|
||||
* @return The x.
|
||||
*/
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the x.
|
||||
* @param x The x to set.
|
||||
*/
|
||||
public void setX(int x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the y.
|
||||
* @return The y.
|
||||
*/
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the y.
|
||||
* @param y The y to set.
|
||||
*/
|
||||
public void setY(int y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the z.
|
||||
* @return The z.
|
||||
*/
|
||||
public int getZ() {
|
||||
return z % 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the z.
|
||||
* @param z The z to set.
|
||||
*/
|
||||
public void setZ(int z) {
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<Location> getStepComponents(Direction dir) {
|
||||
List<Location> output = new ArrayList<>(2);
|
||||
int stepX = dir.getStepX();
|
||||
int stepY = dir.getStepY();
|
||||
|
||||
// alright ill break it down real simple
|
||||
//
|
||||
// we can move diagonally but theres no melee attacking diagonally. its gotta be from N, W, S or E.
|
||||
// if we are moving diagonally, we then need to check if we can attack from one of the valid directions.
|
||||
// in other words we need to check the two tiles that share a corner with our destination and make sure they can be attacked from
|
||||
//
|
||||
// picture this: you are at (0,0). im at (1,1). you want to strangle my head off so you gotta check
|
||||
// 1. to the west of destination: (1,1) + (-1,0) = (0,1) or north from where you started
|
||||
// 2. to the south of the destination: (1,1) + (0,-1) = (1,0) or east from where you started
|
||||
// this function is used only by CombatSwingHandler.kt and assumes that we return the X tiles, west or east, FIRST
|
||||
// and then the Y tiles South and North.
|
||||
//
|
||||
// idk what else to say, if youre reading this youre either crazy or crazy good at weird ass shit like this
|
||||
// and dont even need letters to understand, theres just numbers and arrows and fking formulas or something in ur head (and a lot of work to do here)
|
||||
|
||||
if (stepX != 0) output.add(transform(-stepX, 0, 0)); // Ive never dealt with coordinate systems at this level, but it feels like Im in a cold, damp, deep and dark cave with fking goblins etc
|
||||
if (stepY != 0) output.add(transform(0, -stepY, 0)); // and minotaurs
|
||||
return output;
|
||||
}
|
||||
|
||||
public Direction deriveDirection(Location location) {
|
||||
int diffX = location.x - this.x;
|
||||
int diffY = location.y - this.y;
|
||||
|
||||
diffX = diffX >= 0 ? Math.min(diffX, 1) : -1;
|
||||
diffY = diffY >= 0 ? Math.min(diffY, 1) : -1;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (diffY != 0) {
|
||||
if (diffY > 0) {
|
||||
sb.append("NORTH");
|
||||
} else {
|
||||
sb.append("SOUTH");
|
||||
}
|
||||
}
|
||||
|
||||
if (diffX != 0) {
|
||||
if (sb.length() > 0) sb.append("_");
|
||||
if (diffX > 0) {
|
||||
sb.append("EAST");
|
||||
} else {
|
||||
sb.append("WEST");
|
||||
}
|
||||
}
|
||||
|
||||
if (sb.length() == 0) return null;
|
||||
return Direction.valueOf(sb.toString());
|
||||
}
|
||||
|
||||
public Location transform (Vector vector) {
|
||||
return Location.create(this.x + (int) Math.floor(vector.getX()), this.y + (int) Math.floor(vector.getY()));
|
||||
}
|
||||
}
|
||||
257
Server/src/main/core/game/world/map/Location.kt
Normal file
257
Server/src/main/core/game/world/map/Location.kt
Normal file
|
|
@ -0,0 +1,257 @@
|
|||
package core.game.world.map
|
||||
|
||||
import core.api.utils.Vector
|
||||
import core.game.interaction.DestinationFlag
|
||||
import core.game.node.Node
|
||||
import core.game.world.map.RegionManager.getTeleportLocation
|
||||
import core.game.world.map.path.Pathfinder
|
||||
import core.tools.RandomFunction
|
||||
import kotlin.math.*
|
||||
|
||||
/**
|
||||
* Specify a position (x,y,z), implements [Node].
|
||||
* - Coordinates x and y can be negative for delta values. Values ±16,383.
|
||||
* - Coordinate z (level) has a quirk, this class doesn't let you init with a negative z. Values 0 - 3.
|
||||
*/
|
||||
/*
|
||||
Official Terms
|
||||
- Zones: 8x8 tiles
|
||||
- Map Squares: 64x64 tiles
|
||||
- Build Area: 104x104 tiles (13 x 13 chunks centered around player's chunk) - client's loaded area
|
||||
|
||||
Some Definitions:
|
||||
- Cardinal: Four Base Direction (N E S W)
|
||||
- Diagonal: Four Diagonal directions (NE SE SW NW)
|
||||
- Compass: All 8 directions (For this game, compass in relation to 8-point Cardinal+Diagonal)
|
||||
- Euclidean distance: Straight-line length of two points. Direct calculation. e.g. [2,3] distance=√13(≈3.61)
|
||||
- Manhattan distance: Cardinal length of two points. Count of steps along grid lines. e.g. [2,3] distance=5
|
||||
- Chebyshev distance: Cardinal+Diagonal length of two points. Count of king moves to make. e.g. [2,3] distance=3
|
||||
*/
|
||||
class Location(var hash: LocationHash) : Node(null, null) {
|
||||
@JvmOverloads
|
||||
constructor(x: Int, y: Int, z: Int = 0) : this(
|
||||
LocationHash(x, y, (z % 4 + 4) % 4) // The previous z calc didn't make sense since they play around with negative numbers.
|
||||
)
|
||||
constructor(location: Location) : this(location.hash)
|
||||
constructor(x: Int, y: Int, z: Int, randomizer: Int) :
|
||||
this(x + RandomFunction.getRandom(randomizer), y + RandomFunction.getRandom(randomizer), z)
|
||||
init { super.destinationFlag = DestinationFlag.LOCATION } // This is to set the type of [Node].
|
||||
|
||||
// Map properties directly to the underlying hash for convenience
|
||||
var x: Int
|
||||
get() = hash.x
|
||||
set(value) { hash = LocationHash(value, y, z) }
|
||||
|
||||
var y: Int
|
||||
get() = hash.y
|
||||
set(value) { hash = LocationHash(x, value, z) }
|
||||
|
||||
var z: Int
|
||||
get() = hash.z
|
||||
set(value) { hash = LocationHash(x, y, (value % 4 + 4) % 4) }
|
||||
|
||||
companion object {
|
||||
// Alternate static constructors
|
||||
@JvmStatic @JvmOverloads fun create(x: Int, y: Int, z: Int = 0): Location = Location(x, y, z)
|
||||
@JvmStatic fun create(location: Location): Location = Location(location)
|
||||
/** @return new Location parsed from a string format "[x, y, z]". */
|
||||
fun fromString(locString: String): Location {
|
||||
val coordinates = locString.removeSurrounding("[", "]").split(",").map { it.trim().toInt() }
|
||||
return create(coordinates[0], coordinates[1], coordinates[2])
|
||||
}
|
||||
|
||||
/** @return Straight-line(Euclidean) distance between two locations. */
|
||||
@JvmStatic fun getDistance(first: Location, second: Location): Double {
|
||||
val xDiff: Int = first.x - second.x
|
||||
val yDiff: Int = first.y - second.y
|
||||
return sqrt((xDiff * xDiff + yDiff * yDiff).toDouble())
|
||||
}
|
||||
|
||||
/** @return A location representing the delta between two locations. This is not a good function because it doesn't care about z. */
|
||||
@JvmStatic fun getDelta(location: Location, other: Location): Location = create(other.x - location.x, other.y - location.y, other.z - location.z)
|
||||
|
||||
/** @return A random location within radius, optionally verifying reachability. */
|
||||
fun getRandomLocation(main: Location, radius: Int, reachable: Boolean): Location {
|
||||
val loc = getTeleportLocation(main, radius)
|
||||
if (!reachable) return loc
|
||||
val path = Pathfinder.find(main, loc, false, Pathfinder.DUMB)
|
||||
if (!path.isSuccessful && path.points.isNotEmpty()) {
|
||||
return create(path.points.last.x, path.points.last.y, main.z)
|
||||
} else if (path.isSuccessful) {
|
||||
return loc
|
||||
} else {
|
||||
return main
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Function overrides of Node class and Java class
|
||||
override fun getLocation(): Location = this
|
||||
override fun toString(): String = "[$x, $y, $z]"
|
||||
override fun hashCode(): Int = hash.hash
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return when (other) {
|
||||
is Location -> other.hash == this.hash
|
||||
is LocationHash -> other == this.hash
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
fun equals(x: Int, y: Int, z: Int): Boolean = hash == LocationHash(x, y, z)
|
||||
|
||||
// Derived variables. Please note the following isn't a 1-1 representation of what is officially used.
|
||||
|
||||
// Region - (Officially: Map Square) 64x64
|
||||
/** Unique index "key" (Officially: region_uid) for a 64x64 area. Made of x and y joined bitwise together. Used in xteas.json. */
|
||||
val regionId: Int get() = x shr 6 shl 8 or (y shr 6) // Cuts off the end 6 bits of both x y and joins them together. E.g. 10392
|
||||
/** The chunk x index for this position (x/8). For sets of 8x8 area. THIS IS NAMED WRONG, THIS IS A CHUNK(8) NOT REGION(64). */
|
||||
val regionX: Int get() = x shr 3 // shr 3 is essentially divide by 8
|
||||
/** The chunk y index for this position (y/8). For sets of 8x8 area. THIS IS NAMED WRONG, THIS IS A CHUNK(8) NOT REGION(64). */
|
||||
val regionY: Int get() = y shr 3 // shr 3 is essentially divide by 8
|
||||
// Local - x,y position inside a region
|
||||
/** The relative x position inside a region(64x64). */
|
||||
val localX: Int get() = x and 63 // and 63 is essentially modulo 64
|
||||
/** The relative y position inside a region(64x64). */
|
||||
val localY: Int get() = y and 63 // and 63 is essentially modulo 64
|
||||
/** @return Check if it is in the same region id. */
|
||||
fun isInRegion(region: Int): Boolean = regionId == region
|
||||
|
||||
// Chunk - (Officially: Zones) 8x8
|
||||
val chunkBase: Location get() = create(regionX shl 3, regionY shl 3, z)
|
||||
/** The chunk x index for this position RELATIVE to a region[localX](x/8). THIS IS NOT GLOBAL CHUNK X. */
|
||||
val chunkX: Int get() = localX shr 3 // shr 3 is essentially divide by 8 (note this is localX)
|
||||
/** The chunk y index for this position RELATIVE to a region[localY](y/8). THIS IS NOT GLOBAL CHUNK Y. */
|
||||
val chunkY: Int get() = localY shr 3 // shr 3 is essentially divide by 8 (note this is localX)
|
||||
/** The relative x position inside a chunk(8x8). */
|
||||
val chunkOffsetX: Int get() = localX and 7 // and 7 is essentially modulo 8
|
||||
/** The relative y position inside a chunk(8x8). */
|
||||
val chunkOffsetY: Int get() = localY and 7 // and 7 is essentially modulo 8
|
||||
|
||||
// Scene - (Officially: Build Area) 104x104 - Made of 13x13 chunks(8x8)
|
||||
/** The relative x position inside a scene(104x104). Used for client viewport rendering. */
|
||||
val sceneX: Int get() = x - (regionX - 6 shl 3) // Centers the current region at [7chunk,7chunk]
|
||||
/** The relative y position inside a scene(104x104). Used for client viewport rendering. */
|
||||
val sceneY: Int get() = y - (regionY - 6 shl 3) // Centers the current region at [7chunk,7chunk]
|
||||
/** @return The local scene x-coordinate relative to another location's regionX. */
|
||||
fun getSceneX(loc: Location): Int = x - (loc.regionX - 6 shl 3)
|
||||
/** @return The local scene y-coordinate relative to another location's regionY. */
|
||||
fun getSceneY(loc: Location): Int = y - (loc.regionY - 6 shl 3)
|
||||
|
||||
|
||||
|
||||
/** @return The location incremented by another location's coordinates. (POTENTIAL Z PROBLEMS HERE) */
|
||||
// TODO: THE FOLLOWING TRANSFORM HAS SHIT Z HANDLING.
|
||||
fun transform(l: Location): Location = Location(x + l.x, y + l.y, (z + l.z) % 4)
|
||||
/** @return The location incremented by specific x, y, z differences. */
|
||||
fun transform(diffX: Int, diffY: Int, z: Int): Location = Location(x + diffX, y + diffY, (this.z + z) % 4)
|
||||
/** @return The location incremented by direction and steps. */
|
||||
@JvmOverloads fun transform(dir: Direction, steps: Int = 1): Location = Location(x + dir.stepX * steps, y + dir.stepY * steps, z)
|
||||
/** Location transformed by a Vector. Limit usage to more complicated functionality. */
|
||||
fun transform(vector: Vector): Location = create(x + floor(vector.x).toInt(), y + floor(vector.y).toInt())
|
||||
|
||||
|
||||
/** @return True if this location is 1 tile N, W, S, or E of the node. THIS CAN BE REFACTORED OUT. */
|
||||
fun isNextTo(node: Node): Boolean {
|
||||
val l = node.location
|
||||
return if (l.y == y) abs(l.x - x) == 1 else if (l.x == x) abs(l.y - y) == 1 else false
|
||||
}
|
||||
|
||||
/** @return True if this other location is within dist of this location. */
|
||||
@JvmOverloads fun withinDistance(other: Location, dist: Int = MapDistance.RENDERING.distance): Boolean {
|
||||
if (other.z != z) return false
|
||||
return getDistance(this, other) <= dist
|
||||
}
|
||||
|
||||
/** @return True if within specified distance using max norm (Chebyshev) distance. */
|
||||
fun withinMaxnormDistance(other: Location, dist: Int): Boolean = if (other.z != z) false else max(abs(other.x - x), abs(other.y - y)) <= dist
|
||||
|
||||
/** @return The straight-line(Euclidean) distance between this and another location. */
|
||||
fun getDistance(other: Location): Double = getDistance(this, other)
|
||||
|
||||
/** @returns ArrayList of the 8 cardinal and diagonal tiles. Order is important and follows [Direction] indexing **/
|
||||
val surroundingTiles: ArrayList<Location> get() {
|
||||
val locations = ArrayList<Location>()
|
||||
locations.add(transform(-1, -1, 0))
|
||||
locations.add(transform(0, -1, 0))
|
||||
locations.add(transform(1, -1, 0))
|
||||
locations.add(transform(1, 0, 0))
|
||||
locations.add(transform(1, 1, 0))
|
||||
locations.add(transform(0, 1, 0))
|
||||
locations.add(transform(-1, 1, 0))
|
||||
locations.add(transform(-1, 0, 0))
|
||||
return locations
|
||||
}
|
||||
|
||||
/** @returns ArrayList of the 4 cardinal direction tiles. Order is important and follows [Direction] indexing **/
|
||||
val cardinalTiles: ArrayList<Location> get() {
|
||||
val locations = ArrayList<Location>()
|
||||
locations.add(transform(-1, 0, 0))
|
||||
locations.add(transform(0, -1, 0))
|
||||
locations.add(transform(1, 0, 0))
|
||||
locations.add(transform(0, 1, 0))
|
||||
return locations
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the directional components of a movement step.
|
||||
* TODO: would prefer this in the other place. This doesn't exactly belong here since this isn't a common function for other instances of Location
|
||||
*
|
||||
* we can move diagonally but there's no melee attacking diagonally. its gotta be from N, W, S or E.
|
||||
* if we are moving diagonally, we then need to check if we can attack from one of the valid directions.
|
||||
* in other words we need to check the two tiles that share a corner with our destination and make sure they can be attacked from
|
||||
*
|
||||
* picture this: you are at (0,0). im at (1,1). you want to strangle my head off, so you got to check
|
||||
* 1. to the west of destination: (1,1) + (-1,0) = (0,1) or north from where you started
|
||||
* 2. to the south of the destination: (1,1) + (0,-1) = (1,0) or east from where you started
|
||||
* this function is used only by CombatSwingHandler.kt and assumes that we return the X tiles, west or east, FIRST
|
||||
* and then the Y tiles South and North.
|
||||
*/
|
||||
fun getStepComponents(dir: Direction): List<Location> {
|
||||
val output = ArrayList<Location>(2)
|
||||
if (dir.stepX != 0) output.add(transform(-dir.stepX, 0, 0))
|
||||
if (dir.stepY != 0) output.add(transform(0, -dir.stepY, 0))
|
||||
return output
|
||||
}
|
||||
|
||||
/** @return the Direction of the another location relative to this one. */
|
||||
fun deriveDirection(location: Location): Direction? {
|
||||
val dx = (location.x - x).let { if (it >= 0) min(it, 1) else -1 }
|
||||
val dy = (location.y - y).let { if (it >= 0) min(it, 1) else -1 }
|
||||
val sb = StringBuilder()
|
||||
if (dy != 0) sb.append(if (dy > 0) "NORTH" else "SOUTH")
|
||||
if (dx != 0) { if (sb.isNotEmpty()) sb.append("_"); sb.append(if (dx > 0) "EAST" else "WEST") }
|
||||
return if (sb.isEmpty()) null else Direction.valueOf(sb.toString())
|
||||
}
|
||||
|
||||
/**
|
||||
* Locations as an Integer rather than a Location object. This is for space efficiency.
|
||||
* Inner class, because this is only used here, and to avoid adding another standard until this replaces Location
|
||||
*
|
||||
* 32 bits for an int (z z x x x x x x x x x x x x x x x y y y y y y y y y y y y y y y)
|
||||
* - Rightmost set of 15 bits is for y (can handle negative numbers)
|
||||
* - Middle set of 15 bits is for x (can handle negative numbers)
|
||||
* - Leftmost set of 2 bits is for z
|
||||
*
|
||||
* Since x and y occupy 15 bits (0 to 32,767) it becomes => 1 sign + 14 bits (e.g., 16,384) for range of ±16,383.
|
||||
*/
|
||||
@JvmInline
|
||||
value class LocationHash(val hash: Int) {
|
||||
constructor(x: Int, y: Int, z: Int = 0) : this(
|
||||
((z and 0x3) shl 30) or
|
||||
((x and 0x7FFF) shl 15) or
|
||||
(y and 0x7FFF)
|
||||
)
|
||||
val x: Int get() {
|
||||
val raw = (hash ushr 15) and 0x7FFF
|
||||
// If the 15th bit is set, it's a negative number in 15-bit range
|
||||
return if (raw >= 0x4000) raw - 0x8000 else raw
|
||||
}
|
||||
|
||||
val y: Int get() {
|
||||
val raw = hash and 0x7FFF
|
||||
// If the 15th bit is set, it's a negative number
|
||||
return if (raw >= 0x4000) raw - 0x8000 else raw
|
||||
}
|
||||
val z: Int get() = hash ushr 30
|
||||
}
|
||||
}
|
||||
|
|
@ -783,10 +783,10 @@ object RegionManager {
|
|||
for (regionX in ((l.regionX - 6) shr 3)..((l.regionX + 6) shr 3)) {
|
||||
for (regionY in ((l.regionY - 6) shr 3)..((l.regionY + 6) shr 3)) {
|
||||
for (player in forId((regionX shl 8) or regionY).planes[l.z].players) {
|
||||
if (player.location.x >= l.getX() - xdist &&
|
||||
player.location.x <= l.getX() + xdist &&
|
||||
player.location.y >= l.getY() - ydist &&
|
||||
player.location.y <= l.getY() + ydist) {
|
||||
if (player.location.x >= l.x - xdist &&
|
||||
player.location.x <= l.x + xdist &&
|
||||
player.location.y >= l.y - ydist &&
|
||||
player.location.y <= l.y + ydist) {
|
||||
players.add(player)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue