Compare commits

...

117 commits

Author SHA1 Message Date
sirdabalot
8bdfc43fba Rewrote fletching 2025-11-29 00:16:56 +11:00
oftheshire
12f217f8f3 Tortoise no longer drop 3 regular-sized bones on death
Tortoises have corrected HP (101 for level 79, 121 for level 92)
Added stats and animations for Gnome Driver, Gnome Mage, and Gnome Archer
Gnome-Mounted Tortoise now attacks with its mounted gnomes, and the gnomes spawn on the ground upon tortoise death
2025-11-28 23:43:00 +11:00
dam
07e48d91a8 Fixed the price of spirit shards and pouches 2025-11-28 23:37:26 +11:00
dam
0bf2f7d0ec Corrected destination coordinates of the Carrallangar teleport 2025-11-28 23:35:26 +11:00
Player Name
a38d3734bd Global news announcements no longer overrun the chatbox
Global news announcements are now locked behind the enable_global_chat server config setting
PvP and brawler drops from the Chaos Elemental now refer to it as "the Chaos Elemental", rather than "a Chaos Elemental"
PvP and brawler drops from revenants now lowercase the revenant's name
2025-11-27 23:18:27 +11:00
Player Name
96c42c18d9 Added a new server config option, shooting_star_ring, enabling whether the inauthentic ancient blueprint gets rolled 2025-11-27 23:08:58 +11:00
dam
1765f3a3b6 Fixed ice spell casts allowing frozen victim movement for 1 tick
Fixed ice barrage animations
Players who get successfully frozen by an ice spell now receive the message "You have been frozen!"
2025-11-27 23:04:25 +11:00
Player Name
5533a2f78a Fixed discord mod message logging
Fixed a typo when attempting to sell an item on the GE that is blacklisted
Implemented grinding of suqah teeth
2025-11-27 23:03:17 +11:00
oftheshire
846d55365a Fixed Wyson's dialogue so that he properly respects the choice of turning in mole parts
Corrected dialogue to authentic source
2025-11-27 23:01:33 +11:00
Syndromeramo
da7c62d10c Implemented Observatory Quest 2025-11-27 22:59:02 +11:00
Player Name
2239168074 Corrected the retreat mechanic to not heal the npc 2025-11-27 22:56:04 +11:00
Player Name
8ba45e0ee1 Corrected the deep wildy murder message to the authentic one
Fixed a bug that caused the prayer-recharge jingle to be played over the death jingle when the player died
Fixed redundant overload checks
Fixed lunar spells consuming double runes when a previous cast attempt failed
Fixed HP on halloween random-event spiders
Corrected the Dream spell logic
2025-11-27 22:55:00 +11:00
Player Name
82e5965220 Implemented periodic Grand Exchange update notifications 2025-11-27 22:48:23 +11:00
Player Name
3d5cbd90ed Improved random event kidnapping logic
Rewrote home teleport
Corrected shades and zombies to only multiply xp by 1/16 if they were random events
Unified non-hostile random event chat mechanics
Fixed random events repeating their opening message and/or saying their timeout message prematurely
Genie will now authentically address female players as 'Mistress'
Fixed hostile randoms wrongly teleporting the player after 3 minutes
Made quizmaster dialogues unclosable and added a hook to restart them if you lose it
Made the pillory dialog unclosable
Implemented rock golem switch between ranged and melee
Replaced sandwich lady chat lines with authentic quotes
Added authentic dialogue for interacting with another player's sandwich lady
Added a teleport block for the surprise exam random event
2025-11-27 22:44:43 +11:00
Poseidon
feb2b10247 Fixed Ghost Disciple dialogue typo at Ectofuntus 2025-11-27 22:10:23 +11:00
Kennynes
56986ad6bc Corrected rune essence mining behavior and speeds
Also corrected various mining messages across many rock types to be authentic
2025-11-26 00:16:48 +11:00
dam
6241ff9ce5 Improved pathfinding to handle cases when both player and target are moving 2025-11-26 00:14:40 +11:00
Player Name
dfb53cfa03 Made XP rates and ironman optional, locked behind new server config settings xp_rates and ironman
Removed the ironman_icons server config setting, locking it behind ironman instead
Removed the default_xp_rate server config setting and hardcoded the default xp rate to 1x
Changed a bunch of server config defaults for inauthentic features to disabled
Added enable_global_chat to the worldprops default config. Note the change from enable_globalchat to enable_global_chat
Removed the allow_slayer_rerolls worldprops config option
Large number of tutorial island improvements and authenticity enhancements
2025-11-26 00:12:56 +11:00
Kennynes
66030f36d6 Evil Bob's fishing event cutscene now much more authentic 2025-11-26 00:01:34 +11:00
oftheshire
8dd82dd356 Light source is now required to get boots of lightness
Boots of lightness now work as expected
2025-11-26 00:00:31 +11:00
Player Name
1fa2d3460f Unified and reimplemented various banker dialogues
Accessibility to second bank is now locked behind server config toggle second_bank
Eniola, Arnold Lydspor, and Emerald Benedict now offer access to second bank
Locked the backported ability to charge our ring of wealth with GE teleports behind server config toggle ring_of_wealth_teleport
Corrected enchant spells to always yield uncharged dragonstone items, rather than fully charged ones
Fixed inauthentic jewellery UI
Locked the availability of our inauthentic player commands behind server config toggle player_commands. Admins are immune to this and still always have all commands available. Note that this includes ::confirmrules, so be sure not to set your server to show rules and info, but not allow commands
2025-11-25 23:56:42 +11:00
Player Name
78f1c58b4e Fixed the remaining dramen tree inauthenticity, now provides reward after a single tick of cutting 2025-11-25 19:36:36 +11:00
dam
9a7a885818 Barrows equipment now degrades by 20% on grave death (fully repaired equipment is excluded from this)
Barrows equipment now breaks and drops on non-grave deaths (instead of converting to coins)
Rewrote Bob handlers
2025-11-25 19:12:24 +11:00
Player Name
8d182f2505 Corrected the Ape Atoll teleport location
Added Solihib npc spawn
Implemented Solihib's store
2025-11-25 19:04:03 +11:00
dam
f25f439bdf Fixed female characters not being able to pay Falador Hairdresser hairstyle change fee 2025-11-25 18:36:01 +11:00
oftheshire
4b3cfae309 Fixed typo in Larxus's dialogue (champion's challenge) 2025-11-25 18:28:09 +11:00
Ryan
e6b1203be4 Fixed IP address not getting written to DB on login 2025-11-25 18:10:02 +11:00
Syndromeramo
8694d36ee8 Another round of Entrana allowed item auditing, now much more authentic 2025-11-10 23:33:06 +11:00
Kennynes
618baf0662 Rewrote nettle tea handlers, additionally allowing emptying of cup of tea 2025-11-10 23:30:03 +11:00
Kennynes
f1f5a97859 Made the Black Demon cutscene more authentic and fixed Glough's chathead in the cutscene 2025-11-10 23:28:13 +11:00
Oven Bread
991d4aa364 Added some newly found examine texts 2025-11-10 23:24:45 +11:00
Player Name
789466e4ab Fixed incorrect ordering of operations when opening the bank
Somewhat improved sending of tab configurations and free space
2025-11-10 23:10:44 +11:00
Oven Bread
f9a193c8d7 Implemented the castle wars manual book 2025-11-10 22:43:16 +11:00
Ceikry
d1cfe299c6 Add default issue template now that Gitlab has changed how things work 2025-10-17 22:07:14 +00:00
Syndromeramo
7a23f6f0a3 First phase of TzHaar rewrite 2025-10-08 00:41:11 +11:00
Syndromeramo
c135877680 Catching a horned graahk now finishes the appropriate Karamja task
Checking the health of a fruit tree in Brimhaven now finishes the appropriate Karamja task
2025-10-08 00:19:49 +11:00
damighty
18f274be8e Implemented search command, ::commandsearch <query> 2025-10-08 00:16:28 +11:00
Syndromeramo
5719d03e4d Farmed trees will now correctly regrow based on the same timer as other trees, rather than being tied to growth cycles
Implemented admin ::instachop command
2025-10-07 23:46:14 +11:00
Syndromeramo
d6f32c56fc Chinchompa long fuse now properly splits ranged/defense XP 2025-10-07 23:45:33 +11:00
Syndromeramo
9eac712626 Fixed Cabin Fever charter discount; awarded via quest requirement system
Fixed charter boat exception
Fixed Mos Le'Harmless charter boat discount and prices
2025-10-07 23:08:27 +11:00
Player Name
b644a72bfc Corrected poison dagger attack animations for all metal daggers 2025-10-07 22:50:55 +11:00
oftheshire
efe936500b Fixed potato cactus spawns
Fixed 3 spawns in Kalphite Lair first floor
Fixed 5 spawns in Kalphite Lair bottom floor
2025-09-27 11:08:34 +10:00
Syndromeramo
6d8ef4247c Poison corrections
::poison command (admin) will now automatically remove poison immunity timers for faster testing
Poison will no longer give an inauthentic warning when it is about to expire
Newly applied poison timers will only overwrite old poison timers if they are greater in severity
Fixed up some logic for monster examine checking poison immunity
Fixed numerous poison stats
2025-09-23 23:35:52 +10:00
Bishop
676397f3fd Fixed bug causing herb and uncommon seed drop tables to only roll once when they should have rolled multiple times 2025-09-02 20:43:02 +10:00
Syndromeramo
74cbec067c Made Bork poison immune 2025-09-02 15:06:37 +10:00
Oven Bread
d03df027e0 Fixed minor regression in dialogue code causing "line1" to appear briefly before dialogue is shown 2025-09-01 20:26:00 +10:00
Syndromeramo
d09bdacf94 Fixed bug where All Fired Up beacons could be repaired with insufficient items
Fixed bug where All Fired Up beacons would consider boosted/dynamic skill level instead of actual skill level
Removed random inauthentic needle break when repairing All Fired Up beacon
2025-09-01 20:20:25 +10:00
Syndromeramo
a6eb6f5af6 Fixed dagon'hai robe top and bottom missing prayer bonus
Fixed saradomin bracers requiring 70 defense
Added missing animations and sounds to blessed axe
2025-08-31 20:47:08 +10:00
damighty
2ba1174678 Fixed multihit spells incorrectly targeting familiars
Fixed multihit spells incorrectly being limited to exclusively players or exclusively NPCs per cast
2025-08-31 19:23:58 +10:00
Sinipelto
3dd189d0f3 Improved docker support
Updated README for docker
Cleaned up run and build bash scripts
2025-08-31 19:10:54 +10:00
damighty
a5b5fdf4d6 Fixed Digsite quest items that damage player on drop potentially dealing more damage than intended 2025-08-31 19:03:14 +10:00
Syndromeramo
f39e432432 Removed inauthentic pets
Removed option to obtain inauthentic TzRek-Jad pet
2025-08-31 18:41:06 +10:00
damighty
36267b7a67 Corrected attack, defence and death animations used by Waterfiends (idle attack animation is an authentic bug) 2025-08-31 18:31:56 +10:00
Syndromeramo
79b3f431c1 Corrected list of god items 2025-08-31 18:24:24 +10:00
Oven Bread
75fd1dc475 Fixed the wall beasts in the lumbridge swamp dungeon 2025-08-18 22:06:35 +10:00
Player Name
12049d8ffb Corrected all four DT bosses' despawn behaviors
Added the missing music definition for the eastern half of Damis's cave
Buffed Kamil's ice barrage attack to always hit two 5s
Fixed a bug where Fareed's weapon unequip message would fire even if you did not have a weapon equipped
2025-08-18 22:04:40 +10:00
Lucid Enigma
1106cbac25 Fixed Varrock essence miner bot
Essence miner bot will now sell the acquired pure essence on the GE after it reaches at least 500
2025-08-18 21:50:24 +10:00
damighty
891cdf7de1 Fixed PK news announcement breaking due to incorrect time processing 2025-08-18 21:39:38 +10:00
damighty
80b1b4b01e Removed Grand Exchange privacy 2025-08-18 21:34:42 +10:00
Michael Veit
a0bf0d1d50 Implemented Gnome Barman dialogue 2025-08-18 21:30:02 +10:00
Syndromeramo
2471584c42 Implemented Murder Mystery 2025-08-18 21:26:45 +10:00
Syndromeramo
1ff19880ef Fixed seers diary inferno adze bonus
Fixed Thormac staff enchantment
2025-08-18 21:13:31 +10:00
Michael Veit
89edf78e54 Changed most of the doors in Draynor Manor to not autowalk
Implemented Draynor Manor chair NPCs (The ones that follow you around the house)
2025-08-18 21:08:56 +10:00
Syndromeramo
faf2222f4c Refactored Peer the Seer to better handle edge cases 2025-08-18 21:03:31 +10:00
damighty
b68f914440 Fixed skull visually persisting on death 2025-08-18 20:59:26 +10:00
damighty
c7afeab2ab Fixed first stage of Kalphite Queen not counting as a Kalphite slayer task 2025-08-18 20:55:05 +10:00
damighty
ee9a704ad0 Fixed spam casting Humidify consuming additional runes upon next cast 2025-08-18 20:50:53 +10:00
damighty
93d2c8f4aa Poison immune enemies are now immune to poison 2025-08-18 20:49:54 +10:00
damighty
dc0a0b1cff Removed usage of predetermined GE prices 2025-08-18 20:49:14 +10:00
Syndromeramo
d99e6b2541 Improved battlestaff crafting 2025-08-18 20:46:07 +10:00
damighty
1ebbed5453 Restricted random events inside KBD lair 2025-08-18 20:32:52 +10:00
Freidan
af6d260a1e Changed Rogue's Purse herblore level requirement for cleaning from 8 to 3 and corrected XP awarded 2025-07-15 22:47:39 +10:00
Michael Veit
9cff5cc314 Added dialogue for gnome woman NPCs 2025-07-15 22:45:58 +10:00
Cole Reilly
ef0c208bfb Seers' flax claim migrated to daily-seers-flax.json file
Geoffrey in Seers' Village should give the correct amount of noted flax every day
2025-07-15 22:45:48 +10:00
Syndromeramo
db05c190fe Added the "You do not have an axe to use." message for trying to chop a fruit tree without an axe 2025-07-15 22:42:37 +10:00
Syndromeramo
3634616475 Willow branches now properly regrow every 5 minutes 2025-07-15 22:41:03 +10:00
Oven Bread
bef103e259 Implemented semi-authentic Pious Pete random event 2025-07-15 22:29:09 +10:00
Syndromeramo
98f662d0c6 Cats will no longer eat buckets
Created a new command, ::petrate, for testing pet growth. ::petrate 0 is for pausing growth, 1 for 1x rate, and 2 uses the dev rate of growth (100x normal)
Adult and overgrown cats will not grow hungry
Removed several pets inauthentic to 2009
Dogs no longer can turn into minotaurs
Wolpertingers now double yield and experience from bushes
2025-07-15 22:23:58 +10:00
Syndromeramo
cb17786a86 Relicym's Balm is now created as a 3-dose rather than 4-dose potion
All Barbarian Mixes can now be consumed with appropriate effects
Corrected healing for caviar Barbarian Mixes
2025-07-15 22:14:25 +10:00
Syndromeramo
5c13610776 Implemented farming spirit trees 2025-07-15 22:13:02 +10:00
Cole Reilly
2a438ce349 Fixed exception running ::completediaries 2025-07-15 21:58:20 +10:00
Player Name
264c2aa550 Rewrote or refactored many interfaces, fixing many small bugs 2025-07-15 21:56:19 +10:00
Tom Vanlaer
7cf5049687 Corrected wizard projectiles and cast height 2025-06-18 23:47:04 +10:00
Player Name
c1d932a6f1 Mithril dragons now only use their range attack when outside melee range 2025-06-18 23:43:53 +10:00
Player Name
0c425033f3 Shooting stars now authentically award the discovery bonus XP in a single chunk (players with unclaimed XP prior to this change will still be able to claim it by mining the star) 2025-06-18 23:38:46 +10:00
Syndromeramo
e8c3f31786 Farming improvements
White Berry Bushes can now be protected
Giant Ent properly increases Belladonna yield
Mushrooms now disease properly
Fixed various bush bugs
Fruit Trees can now be chopped
Fixed Scarecrow needing to grow to work
Mushrooms should now visually update as each mushroom is picked from the patch
Poison Ivy Bushes are now disease immune
Poison Ivy Berries picked in the Champion's Guild Patch now finishes a Varrock Diary task
2025-06-18 23:35:50 +10:00
Syndromeramo
91f3a70f75 The Ancient Cavern Canoe can now be used without the screen permanently fading to black until logging out 2025-06-18 23:29:12 +10:00
Player Name
eebbebe772 Corrected Sumona's red dragon assignment
Removed inauthentic aviansie assignments
Fixed GWD beacon not being repairable
Surprise exam is no longer optional
Fixed level checks for All Fired Up beacon repair
2025-06-18 23:28:21 +10:00
F V
5a1c7cb141 Fixed bug where the front door to Lord Handlemort's mansion in Ardougne remains locked even after obtaining totem 2025-05-24 13:38:14 +10:00
Syndromeramo
4fb3ae45d8 Fixed dark beast dropping big bones
Fixed too high health for leech
2025-05-24 13:37:34 +10:00
Syndromeramo
eafa5f42ab Implemented Lletya Fruit Tree Patch
Implemented Harmony Island Allotment Patch. Patch is still unreachable without The Great Brain Robbery
2025-05-24 13:36:23 +10:00
Moon
fc00509b9d Fixed Goblin Diplomacy quest log text 2025-05-24 13:01:18 +10:00
Daarth Cammie
711ef542fa Fixed charging orbs to check magic level instead of crafting 2025-05-24 12:50:40 +10:00
Lucid Enigma
c296e34b50 Corrected Gunslik's shop items 2025-04-12 21:43:57 +10:00
Tom Vanlaer
1bdf1ae204 Corrected spider HP to 2 points 2025-04-12 10:21:11 +10:00
Oven Bread
53c90ad6d6 Fixed maze reward chest amount
Fixed ToG quest point requirements
2025-04-06 19:17:16 +10:00
Oven Bread
3a7dfab628 Crumble undead now more effective against zogres and skogres 2025-04-06 19:01:29 +10:00
Ceikry
02c1835016 Fixed bots not picking up loot 2025-04-06 18:29:06 +10:00
Oven Bread
7c74bfcb71 Fixed the bug where an NPC would show up on an item dialogue
Refactored both item and double item dialogues
2025-04-06 18:18:17 +10:00
Player Name
300b714048 Huge refactor improving the handling of players being given items, or situations where items are exchanged 2025-04-06 18:17:21 +10:00
Player Name
3d7f1689f3 Reverted Lumbridge random event teleport fix due to trapping players in random event
Spam clicking maze shrine now handled
2025-04-03 08:48:11 +11:00
Lucid Enigma
bcc3bc069e Potentially fixed bank visuals when opening bank 2025-03-25 20:58:27 +11:00
Player Name
48bc0ffb28 Fixed requirement check issue with PoH portals checking for Plague City completion 2025-03-25 20:55:37 +11:00
DeadlyGenga
7b1ebd4608 Added melee attack animation to Mystic Mud staff 2025-03-25 20:52:15 +11:00
Alex Page
1b0a7d5fca Fixed random events returning players to Lumbridge 2025-03-25 20:51:47 +11:00
sirdabalot
fc2247f457 Fixed teleport on logout for pest control landers 2025-03-25 20:49:09 +11:00
Alex Page
47ac5e93d6 Fixed issues causing pie crafting to stop or consume additional ingredients 2025-03-25 20:48:27 +11:00
Lucid Enigma
63f8ec3cbf Fixed facial expressions in dialogue for Tree Gnome Village NPCs 2025-03-25 20:37:27 +11:00
Player Name
0622aed00c Fixed incorrect items in circulation
Corrected incorrect rune kite (h)
Corrected incorrect adamant kite (h)
Corrected incorrect lamps
Corrected incorrect blurberry specials
2025-03-25 20:28:15 +11:00
Player Name
dda80d535b Fixed a pet growth bug that could cause an error logging in 2025-03-10 14:18:27 +11:00
Kennynes
448f970c10 Fixed wrong door used in heroes' quest 2025-02-23 13:13:47 +00:00
Oven Bread
83b8689b86 Corrected quizmaster lamp reward 2025-02-23 04:02:11 +00:00
Oven Bread
6362eee753 Can now recover your digsite trowel from the examiner 2025-02-20 10:53:59 +00:00
Oven Bread
f0ee476e42 Fixed pyramid spawns not despawning
Relaxed getting thrown out of the pyramid to rates that appear more authentic
2025-02-19 07:33:42 +00:00
Player Name
0e65f20223 Fixed another softlock in The Fremennik Trials 2025-02-19 07:31:29 +00:00
Player Name
af58fae1fc Corrected Biohazard requirements check when using West Ardougne's eastern gates 2025-02-19 07:30:51 +00:00
Oven Bread
74ed5e1bee Fixed bug where swamp tar interactions could steal an entire stack 2025-02-19 07:29:26 +00:00
461 changed files with 22182 additions and 19789 deletions

30
.dockerignore Normal file
View file

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

12
.gitignore vendored
View file

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

0
.gitlab/.gitkeep Normal file
View file

View file

View file

@ -0,0 +1,17 @@
What I did:
What I expected to happen:
What actually happened:
IDs of related NPCs/items:
2009-era source (if relevant):
Screenshots or video:
LIVE SERVER username affected by this issue:
**Bug reports are not accepted by SP users. SP is often out of date and results in invalid bug reports.**
**If the bug is exploitable make sure you tick the confidential checkbox below**

View file

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

View file

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

View file

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

View file

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

View file

@ -31660,7 +31660,7 @@
{ {
"minAmount": "1", "minAmount": "1",
"weight": "100.0", "weight": "100.0",
"id": "532", "id": "526",
"maxAmount": "1" "maxAmount": "1"
} }
], ],
@ -31696,26 +31696,6 @@
"maxAmount": "1" "maxAmount": "1"
} }
], ],
"tertiary": [
{
"minAmount": "1",
"weight": "9973.0",
"id": "0",
"maxAmount": "1"
},
{
"minAmount": "1",
"weight": "25.0",
"id": "10976",
"maxAmount": "1"
},
{
"minAmount": "1",
"weight": "2.0",
"id": "10977",
"maxAmount": "1"
}
],
"ids": "2783", "ids": "2783",
"description": "", "description": "",
"main": [ "main": [
@ -36478,12 +36458,6 @@
"weight": "100.0", "weight": "100.0",
"id": "532", "id": "532",
"maxAmount": "1" "maxAmount": "1"
},
{
"minAmount": "3",
"weight": "100.0",
"id": "526",
"maxAmount": "3"
} }
], ],
"charm": [], "charm": [],

View file

@ -207,6 +207,10 @@
"item_id": "590", "item_id": "590",
"loc_data": "{1,2368,3135,0,140}-{1,2431,3072,0,140}-{1,3112,3369,2,140}-{1,3209,3734,0,100}-" "loc_data": "{1,2368,3135,0,140}-{1,2431,3072,0,140}-{1,3112,3369,2,140}-{1,3209,3734,0,100}-"
}, },
{
"item_id": "600",
"loc_data": "{1,2438,3187,0,200}-"
},
{ {
"item_id": "677", "item_id": "677",
"loc_data": "{1,3369,3378,0,150}-" "loc_data": "{1,3369,3378,0,150}-"
@ -233,7 +237,7 @@
}, },
{ {
"item_id": "946", "item_id": "946",
"loc_data": "{1,2903,3148,0,80}-{1,3205,3212,0,80}-{1,3224,3202,0,80}-{1,3218,3416,1,90}-{1,2820,3450,0,90}-{1,3106,3956,0,60}-{1,2566,9526,0,30}-{1,3215,9625,0,80}-{1,3218,9887,0,33}-{1,2700,3407,0,100}-" "loc_data": "{1,2903,3148,0,80}-{1,3205,3212,0,80}-{1,3224,3202,0,80}-{1,3218,3416,1,90}-{1,2820,3450,0,90}-{1,2700,3407,0,100}-{1,3106,3956,0,60}-{1,2566,9526,0,30}-{1,3215,9625,0,80}-{1,3218,9887,0,33}-"
}, },
{ {
"item_id": "952", "item_id": "952",
@ -415,6 +419,14 @@
"item_id": "1785", "item_id": "1785",
"loc_data": "{1,2822,3355,0,150}-" "loc_data": "{1,2822,3355,0,150}-"
}, },
{
"item_id": "1812",
"loc_data": "{1,2747,3579,0,100}"
},
{
"item_id": "1813",
"loc_data": "{1,2746,3578,0,100}"
},
{ {
"item_id": "1856", "item_id": "1856",
"loc_data": "{1,2638,3292,0,150}-" "loc_data": "{1,2638,3292,0,150}-"
@ -597,7 +609,7 @@
}, },
{ {
"item_id": "3138", "item_id": "3138",
"loc_data": "{1,3463,9478,2,45}-{1,3461,9480,2,45}-{1,3461,9482,2,45}-{1,3461,9484,2,45}-" "loc_data": "{1,3461,9480,2,30}-{1,3460,9484,2,30}-{1,3465,9477,2,30}-{1,3467,9493,0,30}-{1,3486,9517,0,30}-{1,3474,9509,0,30}-{1,3470,9502,0,30}-{1,3480,9483,0,30}-"
}, },
{ {
"item_id": "3711", "item_id": "3711",
@ -663,6 +675,10 @@
"item_id": "11065", "item_id": "11065",
"loc_data": "{1,2928,3289,0,90}-" "loc_data": "{1,2928,3289,0,90}-"
}, },
{
"item_id": "11656",
"loc_data": "{1,2438,3185,0,200}-"
},
{ {
"item_id": "12494", "item_id": "12494",
"loc_data": "{1,2762,2973,0,60}-" "loc_data": "{1,2762,2973,0,60}-"

View file

@ -5575,7 +5575,7 @@
"id": "601" "id": "601"
}, },
{ {
"destroy_message": "You'll have to get another down in the Dungeon", "destroy_message": "You'll have to get another down in the dungeon.",
"examine": "An unusual clay mould in the shape of a disc.", "examine": "An unusual clay mould in the shape of a disc.",
"durability": null, "durability": null,
"name": "Lens mould", "name": "Lens mould",
@ -18946,7 +18946,7 @@
"equipment_slot": "2" "equipment_slot": "2"
}, },
{ {
"examine": "Anna's shiny silver coated necklace.", "examine": "Anna's shiny silver coated necklace coated with a thin layer of flour.",
"durability": null, "durability": null,
"name": "Silver necklace", "name": "Silver necklace",
"weight": "1", "weight": "1",
@ -18964,7 +18964,7 @@
"id": "1798" "id": "1798"
}, },
{ {
"examine": "Bob's shiny silver coated tea cup.", "examine": "Bob's shiny silver coated tea cup coated with a thin layer of flour.",
"durability": null, "durability": null,
"name": "Silver cup", "name": "Silver cup",
"tradeable": "false", "tradeable": "false",
@ -18982,7 +18982,7 @@
"id": "1800" "id": "1800"
}, },
{ {
"examine": "Carol's shiny silver coated bottle.", "examine": "Carol's shiny silver coated bottle coated with a thin layer of flour.",
"durability": null, "durability": null,
"name": "Silver bottle", "name": "Silver bottle",
"tradeable": "false", "tradeable": "false",
@ -19000,7 +19000,7 @@
"id": "1802" "id": "1802"
}, },
{ {
"examine": "David's shiny silver coated book.", "examine": "David's shiny silver coated book coated with a thin layer of flour.",
"durability": null, "durability": null,
"name": "Silver book", "name": "Silver book",
"tradeable": "false", "tradeable": "false",
@ -19018,7 +19018,7 @@
"id": "1804" "id": "1804"
}, },
{ {
"examine": "Elizabeth's shiny silver coated needle.", "examine": "Elizabeth's shiny silver coated needle coated with a thin layer of flour.",
"durability": null, "durability": null,
"name": "Silver needle", "name": "Silver needle",
"tradeable": "false", "tradeable": "false",
@ -19036,7 +19036,7 @@
"id": "1806" "id": "1806"
}, },
{ {
"examine": "Frank's shiny silver coated pot.", "examine": "Frank's shiny silver coated pot coated with a thin layer of flour.",
"durability": null, "durability": null,
"name": "Silver pot", "name": "Silver pot",
"tradeable": "false", "tradeable": "false",
@ -19045,7 +19045,7 @@
"id": "1807" "id": "1807"
}, },
{ {
"examine": "Some (colour) thread found at the murder scene.", "examine": "Some red thread found at the murder scene.",
"durability": null, "durability": null,
"name": "Criminal's thread", "name": "Criminal's thread",
"tradeable": "false", "tradeable": "false",
@ -19054,7 +19054,7 @@
"id": "1808" "id": "1808"
}, },
{ {
"examine": "Some (colour) thread found at the murder scene.", "examine": "Some green thread found at the murder scene.",
"durability": null, "durability": null,
"name": "Criminal's thread", "name": "Criminal's thread",
"tradeable": "false", "tradeable": "false",
@ -19063,7 +19063,7 @@
"id": "1809" "id": "1809"
}, },
{ {
"examine": "Some (colour) thread found at the murder scene.", "examine": "Some blue thread found at the murder scene.",
"durability": null, "durability": null,
"name": "Criminal's thread", "name": "Criminal's thread",
"tradeable": "false", "tradeable": "false",
@ -19090,7 +19090,7 @@
"id": "1812" "id": "1812"
}, },
{ {
"examine": "A flimsy-looking dagger found at the crime scene./A flimsy looking dagger found at the crime scene coated with a thin layer of flour.", "examine": "A flimsy-looking dagger found at the crime scene.",
"attack_audios": "2517,2517,2500,2517", "attack_audios": "2517,2517,2500,2517",
"durability": null, "durability": null,
"name": "Criminal's dagger", "name": "Criminal's dagger",
@ -19098,7 +19098,7 @@
"id": "1813" "id": "1813"
}, },
{ {
"examine": "A flimsy-looking dagger found at the crime scene./A flimsy looking dagger found at the crime scene coated with a thin layer of flour.", "examine": "A flimsy looking dagger found at the crime scene coated with a thin layer of flour.",
"attack_audios": "2517,2517,2500,2517", "attack_audios": "2517,2517,2500,2517",
"durability": null, "durability": null,
"name": "Criminal's dagger", "name": "Criminal's dagger",
@ -51573,6 +51573,7 @@
"equipment_slot": "3", "equipment_slot": "3",
"grand_exchange_price": "483", "grand_exchange_price": "483",
"attack_audios": "2517,2517,2500,2517", "attack_audios": "2517,2517,2500,2517",
"attack_anims": "400,400,401,400",
"name": "Iron dagger(p+)", "name": "Iron dagger(p+)",
"tradeable": "true", "tradeable": "true",
"archery_ticket_price": "0", "archery_ticket_price": "0",
@ -51601,6 +51602,7 @@
"equipment_slot": "3", "equipment_slot": "3",
"grand_exchange_price": "350", "grand_exchange_price": "350",
"attack_audios": "2517,2517,2500,2517", "attack_audios": "2517,2517,2500,2517",
"attack_anims": "400,400,401,400",
"name": "Bronze dagger(p+)", "name": "Bronze dagger(p+)",
"tradeable": "true", "tradeable": "true",
"archery_ticket_price": "0", "archery_ticket_price": "0",
@ -51630,6 +51632,7 @@
"equipment_slot": "3", "equipment_slot": "3",
"grand_exchange_price": "575", "grand_exchange_price": "575",
"attack_audios": "2517,2517,2500,2517", "attack_audios": "2517,2517,2500,2517",
"attack_anims": "400,400,401,400",
"name": "Steel dagger(p+)", "name": "Steel dagger(p+)",
"tradeable": "true", "tradeable": "true",
"archery_ticket_price": "0", "archery_ticket_price": "0",
@ -51659,6 +51662,7 @@
"equipment_slot": "3", "equipment_slot": "3",
"grand_exchange_price": "538", "grand_exchange_price": "538",
"attack_audios": "2517,2517,2500,2517", "attack_audios": "2517,2517,2500,2517",
"attack_anims": "400,400,401,400",
"name": "Mithril dagger(p+)", "name": "Mithril dagger(p+)",
"tradeable": "true", "tradeable": "true",
"archery_ticket_price": "0", "archery_ticket_price": "0",
@ -51684,6 +51688,7 @@
"equipment_slot": "3", "equipment_slot": "3",
"grand_exchange_price": "800", "grand_exchange_price": "800",
"attack_audios": "2517,2517,2500,2517", "attack_audios": "2517,2517,2500,2517",
"attack_anims": "400,400,401,400",
"name": "Adamant dagger(p+)", "name": "Adamant dagger(p+)",
"tradeable": "true", "tradeable": "true",
"archery_ticket_price": "0", "archery_ticket_price": "0",
@ -51711,6 +51716,7 @@
"equip_audio": "2248", "equip_audio": "2248",
"render_anim": "2584", "render_anim": "2584",
"equipment_slot": "3", "equipment_slot": "3",
"attack_anims": "400,400,401,400",
"lendable": "true", "lendable": "true",
"grand_exchange_price": "4538", "grand_exchange_price": "4538",
"attack_audios": "2517,2517,2500,2517", "attack_audios": "2517,2517,2500,2517",
@ -51779,6 +51785,7 @@
"equipment_slot": "3", "equipment_slot": "3",
"grand_exchange_price": "664", "grand_exchange_price": "664",
"attack_audios": "2517,2517,2500,2517", "attack_audios": "2517,2517,2500,2517",
"attack_anims": "400,400,401,400",
"name": "Black dagger(p+)", "name": "Black dagger(p+)",
"tradeable": "true", "tradeable": "true",
"archery_ticket_price": "0", "archery_ticket_price": "0",
@ -51826,6 +51833,7 @@
"equipment_slot": "3", "equipment_slot": "3",
"grand_exchange_price": "4128", "grand_exchange_price": "4128",
"attack_audios": "2517,2517,2500,2517", "attack_audios": "2517,2517,2500,2517",
"attack_anims": "400,400,401,400",
"name": "Iron dagger(p++)", "name": "Iron dagger(p++)",
"tradeable": "true", "tradeable": "true",
"archery_ticket_price": "0", "archery_ticket_price": "0",
@ -51854,6 +51862,7 @@
"equipment_slot": "3", "equipment_slot": "3",
"grand_exchange_price": "5088", "grand_exchange_price": "5088",
"attack_audios": "2517,2517,2500,2517", "attack_audios": "2517,2517,2500,2517",
"attack_anims": "400,400,401,400",
"name": "Br'ze dagger(p++)", "name": "Br'ze dagger(p++)",
"tradeable": "true", "tradeable": "true",
"archery_ticket_price": "0", "archery_ticket_price": "0",
@ -51883,6 +51892,7 @@
"equipment_slot": "3", "equipment_slot": "3",
"grand_exchange_price": "4729", "grand_exchange_price": "4729",
"attack_audios": "2517,2517,2500,2517", "attack_audios": "2517,2517,2500,2517",
"attack_anims": "400,400,401,400",
"name": "Steel dagger(p++)", "name": "Steel dagger(p++)",
"tradeable": "true", "tradeable": "true",
"archery_ticket_price": "0", "archery_ticket_price": "0",
@ -51912,6 +51922,7 @@
"equipment_slot": "3", "equipment_slot": "3",
"grand_exchange_price": "3476", "grand_exchange_price": "3476",
"attack_audios": "2517,2517,2500,2517", "attack_audios": "2517,2517,2500,2517",
"attack_anims": "400,400,401,400",
"name": "Mithril dagger(p++)", "name": "Mithril dagger(p++)",
"tradeable": "true", "tradeable": "true",
"archery_ticket_price": "0", "archery_ticket_price": "0",
@ -51937,6 +51948,7 @@
"equipment_slot": "3", "equipment_slot": "3",
"grand_exchange_price": "4612", "grand_exchange_price": "4612",
"attack_audios": "2517,2517,2500,2517", "attack_audios": "2517,2517,2500,2517",
"attack_anims": "400,400,401,400",
"name": "Adamant dagger(p++)", "name": "Adamant dagger(p++)",
"tradeable": "true", "tradeable": "true",
"archery_ticket_price": "0", "archery_ticket_price": "0",
@ -51967,6 +51979,7 @@
"lendable": "true", "lendable": "true",
"grand_exchange_price": "5061", "grand_exchange_price": "5061",
"attack_audios": "2517,2517,2500,2517", "attack_audios": "2517,2517,2500,2517",
"attack_anims": "400,400,401,400",
"name": "Rune dagger(p++)", "name": "Rune dagger(p++)",
"tradeable": "true", "tradeable": "true",
"archery_ticket_price": "0", "archery_ticket_price": "0",
@ -52032,6 +52045,7 @@
"equipment_slot": "3", "equipment_slot": "3",
"grand_exchange_price": "4921", "grand_exchange_price": "4921",
"attack_audios": "2517,2517,2500,2517", "attack_audios": "2517,2517,2500,2517",
"attack_anims": "400,400,401,400",
"name": "Black dagger(p++)", "name": "Black dagger(p++)",
"tradeable": "true", "tradeable": "true",
"archery_ticket_price": "0", "archery_ticket_price": "0",
@ -59959,6 +59973,7 @@
"attack_speed": "5", "attack_speed": "5",
"turn180_anim": "1206", "turn180_anim": "1206",
"equipment_slot": "3", "equipment_slot": "3",
"attack_anims": "419,419,419,419",
"grand_exchange_price": "423100", "grand_exchange_price": "423100",
"stand_anim": "813", "stand_anim": "813",
"tradeable": "true", "tradeable": "true",
@ -60305,6 +60320,7 @@
"equipment_slot": "3", "equipment_slot": "3",
"grand_exchange_price": "497", "grand_exchange_price": "497",
"attack_audios": "2517,2517,2500,2517", "attack_audios": "2517,2517,2500,2517",
"attack_anims": "400,400,401,400",
"name": "White dagger(p)", "name": "White dagger(p)",
"tradeable": "true", "tradeable": "true",
"archery_ticket_price": "0", "archery_ticket_price": "0",
@ -60334,6 +60350,7 @@
"equipment_slot": "3", "equipment_slot": "3",
"grand_exchange_price": "982", "grand_exchange_price": "982",
"attack_audios": "2517,2517,2500,2517", "attack_audios": "2517,2517,2500,2517",
"attack_anims": "400,400,401,400",
"name": "White dagger(p+)", "name": "White dagger(p+)",
"tradeable": "true", "tradeable": "true",
"archery_ticket_price": "0", "archery_ticket_price": "0",
@ -60363,6 +60380,7 @@
"equipment_slot": "3", "equipment_slot": "3",
"grand_exchange_price": "8422", "grand_exchange_price": "8422",
"attack_audios": "2517,2517,2500,2517", "attack_audios": "2517,2517,2500,2517",
"attack_anims": "400,400,401,400",
"name": "White dagger(p++)", "name": "White dagger(p++)",
"tradeable": "true", "tradeable": "true",
"archery_ticket_price": "0", "archery_ticket_price": "0",
@ -89018,7 +89036,7 @@
"id": "10383" "id": "10383"
}, },
{ {
"requirements": "{1,70}-{4,40}", "requirements": "{1,40}-{4,70}",
"ge_buy_limit": "2", "ge_buy_limit": "2",
"examine": "Saradomin blessed dragonhide vambraces.", "examine": "Saradomin blessed dragonhide vambraces.",
"durability": null, "durability": null,
@ -90177,9 +90195,13 @@
"weight": "1.1", "weight": "1.1",
"attack_speed": "5", "attack_speed": "5",
"weapon_interface": "2", "weapon_interface": "2",
"equip_audio": "2229",
"render_anim": "2586", "render_anim": "2586",
"defence_anim": "397",
"equipment_slot": "3", "equipment_slot": "3",
"attack_anims": "395,395,401,395",
"destroy_message": "I can obtain a replacement axe from the Burthorpe Slayer Master.", "destroy_message": "I can obtain a replacement axe from the Burthorpe Slayer Master.",
"attack_audios": "2498,2498,2497,2498",
"name": "Blessed axe", "name": "Blessed axe",
"tradeable": "false", "tradeable": "false",
"archery_ticket_price": "0", "archery_ticket_price": "0",
@ -119757,18 +119779,18 @@
}, },
{ {
"requirements": "{11,79}", "requirements": "{11,79}",
"destroy_message": "To get another pair of Flame Gloves, you need to keep ten beacons alight simultaneously and then talk to King Roald.",
"shop_price": "200", "shop_price": "200",
"examine": "The hottest gloves in town.", "examine": "The hottest gloves in town.",
"durability": null, "durability": null,
"name": "Flame gloves",
"destroy": "true", "destroy": "true",
"archery_ticket_price": "0",
"attack_speed": "4", "attack_speed": "4",
"id": "13660",
"absorb": "0,0,0", "absorb": "0,0,0",
"bonuses": "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0", "equipment_slot": "9",
"equipment_slot": "9" "destroy_message": "To get another pair of Flame Gloves, you need to keep ten beacons alight simultaneously and then talk to King Roald.",
"name": "Flame gloves",
"archery_ticket_price": "0",
"id": "13660",
"bonuses": "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0"
}, },
{ {
"requirements": "{11,92}", "requirements": "{11,92}",
@ -130462,7 +130484,7 @@
"tradeable": "true", "tradeable": "true",
"archery_ticket_price": "0", "archery_ticket_price": "0",
"id": "14497", "id": "14497",
"bonuses": "0,0,0,20,0,0,0,0,20,0,20,0,0,2,0" "bonuses": "0,0,0,20,0,0,0,0,20,0,20,0,2,0,0"
}, },
{ {
"shop_price": "120000", "shop_price": "120000",
@ -130518,7 +130540,7 @@
"tradeable": "true", "tradeable": "true",
"archery_ticket_price": "0", "archery_ticket_price": "0",
"id": "14501", "id": "14501",
"bonuses": "0,0,0,15,0,0,0,0,15,0,15,0,0,2,0" "bonuses": "0,0,0,15,0,0,0,0,15,0,15,0,2,0,0"
}, },
{ {
"shop_price": "80000", "shop_price": "80000",

View file

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

File diff suppressed because it is too large Load diff

View file

@ -157,7 +157,7 @@
}, },
{ {
"npc_id": "47", "npc_id": "47",
"loc_data": "{2821,3170,0,1,1}-{3341,3267,0,1,5}-{3076,3282,0,1,5}-{3089,3266,0,1,4}-{3091,3266,0,1,4}-{3097,3364,0,1,3}-{3102,3363,0,1,5}-{3127,3487,0,1,4}-{3125,3486,0,1,6}-{3127,3486,0,1,4}-{2603,9480,0,1,1}-{2600,9477,0,1,0}-{2579,9496,0,1,4}-{2580,9508,0,1,0}-{2571,9522,0,1,4}-{2565,9505,0,1,1}-{2566,9510,0,1,6}-{2594,9497,0,1,4}-{2852,9642,0,1,6}-{2858,9632,0,1,3}-{2568,9620,0,1,0}-{2573,9612,0,1,0}-{2579,9631,0,1,0}-{2580,9600,0,1,0}-{2580,9614,0,1,0}-{2580,9620,0,1,0}-{2580,9626,0,1,0}-{2583,9632,0,1,0}-{2584,9625,0,1,0}-{2584,9637,0,1,0}-{2589,9644,0,1,0}-{2590,9601,0,1,0}-{2590,9638,0,1,0}-{2591,9601,0,1,0}-{2591,9621,0,1,0}-{2594,9636,0,1,0}-{2594,9644,0,1,0}-{2597,9604,0,1,0}-{2607,9615,0,1,0}-{2608,9628,0,1,0}-{2614,9651,0,1,0}-{2614,9656,0,1,0}-{2615,9647,0,1,0}-{2615,9661,0,1,0}-{2616,9633,0,1,0}-{2618,9630,0,1,0}-{3108,9754,0,1,5}-{3110,9754,0,1,5}-{3108,9750,0,1,5}-{2592,9831,0,1,3}-{2588,9825,0,1,6}-{2583,9829,0,1,4}-{2581,9841,0,1,0}-{2597,9823,0,1,2}-{2579,9805,0,1,3}-{2576,9804,0,1,0}-{2573,9805,0,1,5}-{2571,9808,0,1,3}-{2576,9810,0,1,2}-{2587,9802,0,1,2}-{2592,9800,0,1,4}-{2596,9805,0,1,6}-{2601,9802,0,1,5}-{2585,9801,0,1,7}-{2594,9803,0,1,0}-{2590,9806,0,1,3}-{2612,9808,0,1,6}-{2604,9810,0,1,6}-{2579,9821,0,1,2}-{2576,9812,0,1,6}-{2580,9813,0,1,6}-{2600,9813,0,1,4}-{2599,9809,0,1,4}-{3158,3226,0,1,5}-{3160,3202,0,1,4}-{3192,3203,0,1,0}-{3194,3204,0,1,0}-{3196,3206,0,1,0}-{3197,3204,0,1,0}-{2654,9640,0,1,6}-{2655,9637,0,1,4}-{2656,9639,0,1,7}-{2651,9636,0,1,5}-{2648,9637,0,1,4}-{2651,9642,0,1,1}-{2654,9640,0,1,0}-{2654,9635,0,1,6}-{2655,9635,0,1,3}-{2664,9626,0,1,6}-{2664,9624,0,1,1}-{2661,9623,0,1,1}-{2663,9623,0,1,3}-{2664,9626,0,1,6}-{2930,9699,0,1,0}-{2933,9697,0,1,0}-{2932,9685,0,1,0}-{2930,9693,0,1,0}-{3235,3224,0,1,3}-{3229,3220,0,1,4}-{3211,3211,0,1,3}-{3225,3220,0,1,1}-{3237,3215,0,1,5}-{3211,3210,0,1,7}-{3227,3220,0,1,7}-{3233,3227,0,1,5}-{3227,3210,0,1,6}-{3228,3222,0,1,4}-{3229,3226,0,1,0}-{3236,3217,0,1,4}-{3259,3230,0,1,4}-{3233,3237,0,1,7}-{3205,3204,0,1,0}-{3206,3204,0,1,0}-{3205,3203,0,1,0}-{3206,3202,0,1,0}-{3207,3202,0,1,0}-{3208,3203,0,1,0}-{3001,3202,0,1,5}-{3243,3687,0,1,5}-{3249,3669,0,1,3}-{3252,3675,0,1,4}-{3252,3680,0,1,3}-{3259,3683,0,1,0}-{3475,9840,0,1,6}-{3481,9842,0,1,1}-{3486,9843,0,1,7}-{3483,9824,0,1,4}-{3496,9808,0,0,5}-{3490,9815,0,1,1}-{3478,9834,0,0,3}-{3490,9824,0,1,4}-{3225,9862,0,1,4}-{3222,9861,0,1,6}-{3220,9860,0,1,6}-{3219,9865,0,1,6}-{3237,9862,0,1,4}-{2536,2982,0,1,3}-{2531,2980,0,1,0}-{2522,2981,0,1,4}-{2545,2989,0,1,4}-{2523,2970,0,1,2}-{3026,3174,0,1,5}-{3019,3176,0,1,7}-{2801,3158,0,1,2}-{2514,3193,0,1,6}-{2518,3192,0,1,3}-{2507,3181,0,1,3}-{2508,3178,0,1,6}-{2511,3183,0,1,3}-{2515,3182,0,1,1}-{3021,3205,0,1,6}-{3019,3292,0,1,7}-{3018,3295,0,1,7}-{2531,3325,0,1,3}-{2530,3327,0,1,5}-{2521,3331,0,1,3}-{2526,3328,0,1,3}-{2523,3331,0,1,4}-{2523,3334,0,1,1}-{2531,3329,0,1,5}-{2532,3333,0,1,5}-{3276,9871,0,1,1}-{3277,9871,0,1,3}-" "loc_data": "{2821,3170,0,1,1}-{3341,3267,0,1,5}-{3076,3282,0,1,5}-{3089,3266,0,1,4}-{3091,3266,0,1,4}-{3097,3364,0,1,3}-{3102,3363,0,1,5}-{3127,3487,0,1,4}-{3125,3486,0,1,6}-{3127,3486,0,1,4}-{2339,9356,0,1,0}-{2354,9390,0,1,0}-{2361,9403,0,1,0}-{2362,9347,0,1,0}-{2603,9480,0,1,1}-{2600,9477,0,1,0}-{2579,9496,0,1,4}-{2580,9508,0,1,0}-{2571,9522,0,1,4}-{2565,9505,0,1,1}-{2566,9510,0,1,6}-{2594,9497,0,1,4}-{2852,9642,0,1,6}-{2858,9632,0,1,3}-{2568,9620,0,1,0}-{2573,9612,0,1,0}-{2579,9631,0,1,0}-{2580,9600,0,1,0}-{2580,9614,0,1,0}-{2580,9620,0,1,0}-{2580,9626,0,1,0}-{2583,9632,0,1,0}-{2584,9625,0,1,0}-{2584,9637,0,1,0}-{2589,9644,0,1,0}-{2590,9601,0,1,0}-{2590,9638,0,1,0}-{2591,9601,0,1,0}-{2591,9621,0,1,0}-{2594,9636,0,1,0}-{2594,9644,0,1,0}-{2597,9604,0,1,0}-{2607,9615,0,1,0}-{2608,9628,0,1,0}-{2614,9651,0,1,0}-{2614,9656,0,1,0}-{2615,9647,0,1,0}-{2615,9661,0,1,0}-{2616,9633,0,1,0}-{2618,9630,0,1,0}-{3108,9754,0,1,5}-{3110,9754,0,1,5}-{3108,9750,0,1,5}-{2592,9831,0,1,3}-{2588,9825,0,1,6}-{2583,9829,0,1,4}-{2581,9841,0,1,0}-{2597,9823,0,1,2}-{2579,9805,0,1,3}-{2576,9804,0,1,0}-{2573,9805,0,1,5}-{2571,9808,0,1,3}-{2576,9810,0,1,2}-{2587,9802,0,1,2}-{2592,9800,0,1,4}-{2596,9805,0,1,6}-{2601,9802,0,1,5}-{2585,9801,0,1,7}-{2594,9803,0,1,0}-{2590,9806,0,1,3}-{2612,9808,0,1,6}-{2604,9810,0,1,6}-{2579,9821,0,1,2}-{2576,9812,0,1,6}-{2580,9813,0,1,6}-{2600,9813,0,1,4}-{2599,9809,0,1,4}-{3158,3226,0,1,5}-{3160,3202,0,1,4}-{3192,3203,0,1,0}-{3194,3204,0,1,0}-{3196,3206,0,1,0}-{3197,3204,0,1,0}-{2654,9640,0,1,6}-{2655,9637,0,1,4}-{2656,9639,0,1,7}-{2651,9636,0,1,5}-{2648,9637,0,1,4}-{2651,9642,0,1,1}-{2654,9640,0,1,0}-{2654,9635,0,1,6}-{2655,9635,0,1,3}-{2664,9626,0,1,6}-{2664,9624,0,1,1}-{2661,9623,0,1,1}-{2663,9623,0,1,3}-{2664,9626,0,1,6}-{2930,9699,0,1,0}-{2933,9697,0,1,0}-{2932,9685,0,1,0}-{2930,9693,0,1,0}-{3235,3224,0,1,3}-{3229,3220,0,1,4}-{3211,3211,0,1,3}-{3225,3220,0,1,1}-{3237,3215,0,1,5}-{3211,3210,0,1,7}-{3227,3220,0,1,7}-{3233,3227,0,1,5}-{3227,3210,0,1,6}-{3228,3222,0,1,4}-{3229,3226,0,1,0}-{3236,3217,0,1,4}-{3259,3230,0,1,4}-{3233,3237,0,1,7}-{3205,3204,0,1,0}-{3206,3204,0,1,0}-{3205,3203,0,1,0}-{3206,3202,0,1,0}-{3207,3202,0,1,0}-{3208,3203,0,1,0}-{3001,3202,0,1,5}-{3243,3687,0,1,5}-{3249,3669,0,1,3}-{3252,3675,0,1,4}-{3252,3680,0,1,3}-{3259,3683,0,1,0}-{3475,9840,0,1,6}-{3481,9842,0,1,1}-{3486,9843,0,1,7}-{3483,9824,0,1,4}-{3496,9808,0,0,5}-{3490,9815,0,1,1}-{3478,9834,0,0,3}-{3490,9824,0,1,4}-{3225,9862,0,1,4}-{3222,9861,0,1,6}-{3220,9860,0,1,6}-{3219,9865,0,1,6}-{3237,9862,0,1,4}-{2536,2982,0,1,3}-{2531,2980,0,1,0}-{2522,2981,0,1,4}-{2545,2989,0,1,4}-{2523,2970,0,1,2}-{3026,3174,0,1,5}-{3019,3176,0,1,7}-{2801,3158,0,1,2}-{2514,3193,0,1,6}-{2518,3192,0,1,3}-{2507,3181,0,1,3}-{2508,3178,0,1,6}-{2511,3183,0,1,3}-{2515,3182,0,1,1}-{3021,3205,0,1,6}-{3019,3292,0,1,7}-{3018,3295,0,1,7}-{2531,3325,0,1,3}-{2530,3327,0,1,5}-{2521,3331,0,1,3}-{2526,3328,0,1,3}-{2523,3331,0,1,4}-{2523,3334,0,1,1}-{2531,3329,0,1,5}-{2532,3333,0,1,5}-{3276,9871,0,1,1}-{3277,9871,0,1,3}-"
}, },
{ {
"npc_id": "48", "npc_id": "48",
@ -193,7 +193,7 @@
}, },
{ {
"npc_id": "59", "npc_id": "59",
"loc_data": "{3082,3362,0,1,4}-{2602,9640,0,1,0}-{2603,9635,0,1,0}-{2603,9638,0,1,0}-{2605,9637,0,1,0}-{2605,9639,0,1,0}-{2606,9635,0,1,0}-{2606,9646,0,1,0}-{2607,9637,0,1,0}-{2607,9641,0,1,0}-{2607,9644,0,1,0}-{2607,9648,0,1,0}-{2608,9635,0,1,0}-{2608,9642,0,1,0}-{2609,9639,0,1,0}-{2609,9643,0,1,0}-{3102,9881,0,1,3}-{3095,9883,0,1,2}-{3182,3244,0,1,1}-{3162,3223,0,1,7}-{3164,3242,0,1,0}-{3169,3246,0,1,0}-{3170,3250,0,1,0}-{3166,3247,0,1,0}-{3164,3249,0,1,0}-{3157,3226,0,1,0}-{3163,3227,0,1,0}-{3165,3223,0,1,0}-{3194,3236,0,1,0}-{3146,3347,0,1,3}-{2648,9766,0,1,4}-{2653,9761,0,1,3}-{2483,2877,0,1,3}-{2481,2876,0,1,4}-{2457,2867,0,1,4}-{2481,2847,0,1,0}-{2475,2854,0,1,3}-{2482,2873,0,1,3}-{2485,2876,0,1,2}-{2449,2865,0,1,1}-{2461,2880,0,1,5}-{2489,2935,0,1,7}-{2492,2907,0,1,1}-{2487,2894,0,1,2}-{2487,2888,0,1,7}-{2478,2916,0,1,5}-{2485,2902,0,1,3}-{2487,2902,0,1,2}-{2489,2894,0,1,2}-{2490,2905,0,1,7}-{2490,2917,0,1,5}-{2484,2890,0,1,1}-{2491,2927,0,1,1}-{3250,3239,0,1,1}-{3241,3241,0,1,1}-{3249,3249,0,1,1}-{3218,9890,0,1,3}-{3220,9887,0,1,0}-{3218,9887,0,1,1}-{3218,9889,0,1,5}-{3213,9890,0,1,1}-{2496,2890,0,1,4}-{2503,2889,0,1,1}-{2497,2939,0,1,2}-{2369,3374,0,1,0}-{2372,3379,0,1,0}-{2378,3366,0,1,0}-{2379,3378,0,1,0}-{2387,3370,0,1,0}-{2394,3365,0,1,0}-{2402,3386,0,1,0}-{2405,3381,0,1,0}-{2407,3387,0,1,0}-{2412,3384,0,1,0}-" "loc_data": "{3082,3362,0,1,4}-{2602,9640,0,1,0}-{2603,9635,0,1,0}-{2603,9638,0,1,0}-{2605,9637,0,1,0}-{2605,9639,0,1,0}-{2606,9635,0,1,0}-{2606,9646,0,1,0}-{2607,9637,0,1,0}-{2607,9641,0,1,0}-{2607,9644,0,1,0}-{2607,9648,0,1,0}-{2608,9635,0,1,0}-{2608,9642,0,1,0}-{2609,9639,0,1,0}-{2609,9643,0,1,0}-{3102,9881,0,1,3}-{3095,9883,0,1,2}-{3182,3244,0,1,1}-{3162,3223,0,1,7}-{3164,3242,0,1,0}-{3169,3246,0,1,0}-{3170,3250,0,1,0}-{3166,3247,0,1,0}-{3164,3249,0,1,0}-{3157,3226,0,1,0}-{3163,3227,0,1,0}-{3165,3223,0,1,0}-{3194,3236,0,1,0}-{3146,3347,0,1,3}-{2369,3374,0,1,0}-{2372,3379,0,1,0}-{2378,3366,0,1,0}-{2379,3378,0,1,0}-{2387,3370,0,1,0}-{2394,3365,0,1,0}-{2402,3386,0,1,0}-{2405,3381,0,1,0}-{2407,3387,0,1,0}-{2412,3384,0,1,0}-{2648,9766,0,1,4}-{2653,9761,0,1,3}-{2483,2877,0,1,3}-{2481,2876,0,1,4}-{2457,2867,0,1,4}-{2481,2847,0,1,0}-{2475,2854,0,1,3}-{2482,2873,0,1,3}-{2485,2876,0,1,2}-{2449,2865,0,1,1}-{2461,2880,0,1,5}-{2489,2935,0,1,7}-{2492,2907,0,1,1}-{2487,2894,0,1,2}-{2487,2888,0,1,7}-{2478,2916,0,1,5}-{2485,2902,0,1,3}-{2487,2902,0,1,2}-{2489,2894,0,1,2}-{2490,2905,0,1,7}-{2490,2917,0,1,5}-{2484,2890,0,1,1}-{2491,2927,0,1,1}-{3250,3239,0,1,1}-{3241,3241,0,1,1}-{3249,3249,0,1,1}-{3218,9890,0,1,3}-{3220,9887,0,1,0}-{3218,9887,0,1,1}-{3218,9889,0,1,5}-{3213,9890,0,1,1}-{2496,2890,0,1,4}-{2503,2889,0,1,1}-{2497,2939,0,1,2}-"
}, },
{ {
"npc_id": "60", "npc_id": "60",
@ -217,15 +217,15 @@
}, },
{ {
"npc_id": "66", "npc_id": "66",
"loc_data": "{2417,3493,1,1,0}-{2418,3495,1,1,0}-{2383,3452,0,1,0}-{2401,3417,0,1,0}-{2402,3422,0,1,0}-{2402,3441,0,1,0}-{2403,3430,0,1,0}-{2408,3441,0,1,0}-{2409,3430,0,1,0}-{2423,3426,0,1,0}-{2427,3428,0,1,0}-{2427,3440,0,1,0}-{2526,3168,0,1,0}-{2529,3163,0,1,0}-{2530,3172,0,1,0}-{2536,3169,0,1,0}-{2435,3460,0,1,0}-{2440,3470,0,1,0}-{2447,3502,0,1,0}-{2457,3462,0,1,0}-{2478,3502,0,1,0}-{2449,3492,1,1,0}-{2450,3490,1,1,0}-{2474,3490,1,1,0}-{2482,3492,1,1,0}-{2482,3498,1,1,0}-{2399,3356,0,1,0}-" "loc_data": "{2399,3356,0,1,0}-{2383,3452,0,1,0}-{2401,3417,0,1,0}-{2402,3422,0,1,0}-{2402,3441,0,1,0}-{2403,3430,0,1,0}-{2408,3441,0,1,0}-{2409,3430,0,1,0}-{2423,3426,0,1,0}-{2427,3428,0,1,0}-{2427,3440,0,1,0}-{2417,3493,1,1,0}-{2418,3495,1,1,0}-{2435,3460,0,1,0}-{2440,3470,0,1,0}-{2447,3502,0,1,0}-{2457,3462,0,1,0}-{2478,3502,0,1,0}-{2449,3492,1,1,0}-{2450,3490,1,1,0}-{2474,3490,1,1,0}-{2482,3492,1,1,0}-{2482,3498,1,1,0}-{2526,3168,0,1,0}-{2529,3163,0,1,0}-{2530,3172,0,1,0}-{2536,3169,0,1,0}-"
}, },
{ {
"npc_id": "67", "npc_id": "67",
"loc_data": "{2556,3226,0,1,0}-{2456,3425,0,1,0}-{2459,3421,0,1,0}-{2462,3431,0,1,0}-{2394,3500,1,1,0}-{2417,3483,1,1,0}-{2377,3442,0,1,0}-{2380,3425,0,1,0}-{2383,3433,0,1,0}-{2405,3447,0,1,0}-{2406,3440,0,1,0}-{2393,3451,1,1,0}-{2408,3437,1,1,0}-{2521,3169,0,1,0}-{2521,3171,0,1,0}-{2033,5530,1,1,0}-{2437,3478,0,1,0}-{2442,3465,0,1,0}-{2456,3467,0,1,0}-{2471,3496,0,1,0}-{2474,3508,0,1,0}-{2475,3471,0,1,0}-{2479,3468,0,1,0}-{2486,3470,0,1,0}-{2492,3474,0,1,0}-{2443,3464,1,1,0}-{2443,3502,1,1,0}-{2448,3496,1,1,0}-{2449,3506,1,1,0}-{2457,3498,1,1,0}-{2474,3498,1,1,0}-{2480,3502,1,1,0}-{2481,3482,1,1,0}-{2490,3503,1,1,0}-{2400,3356,0,1,0}-" "loc_data": "{2400,3356,0,1,0}-{2377,3442,0,1,0}-{2380,3425,0,1,0}-{2383,3433,0,1,0}-{2405,3447,0,1,0}-{2406,3440,0,1,0}-{2393,3451,1,1,0}-{2408,3437,1,1,0}-{2394,3500,1,1,0}-{2417,3483,1,1,0}-{2456,3425,0,1,0}-{2459,3421,0,1,0}-{2462,3431,0,1,0}-{2437,3478,0,1,0}-{2442,3465,0,1,0}-{2456,3467,0,1,0}-{2471,3496,0,1,0}-{2474,3508,0,1,0}-{2475,3471,0,1,0}-{2479,3468,0,1,0}-{2486,3470,0,1,0}-{2492,3474,0,1,0}-{2443,3464,1,1,0}-{2443,3502,1,1,0}-{2448,3496,1,1,0}-{2449,3506,1,1,0}-{2457,3498,1,1,0}-{2474,3498,1,1,0}-{2480,3502,1,1,0}-{2481,3482,1,1,0}-{2490,3503,1,1,0}-{2521,3169,0,1,0}-{2521,3171,0,1,0}-{2556,3226,0,1,0}-{2033,5530,1,1,0}-"
}, },
{ {
"npc_id": "68", "npc_id": "68",
"loc_data": "{2400,3514,1,1,0}-{2418,3485,1,1,0}-{2378,3423,0,1,0}-{2393,3435,0,1,0}-{2394,3425,0,1,0}-{2395,3449,0,1,0}-{2403,3433,0,1,0}-{2420,3429,0,1,0}-{2420,3438,0,1,0}-{2522,3172,0,1,0}-{2433,3474,0,1,0}-{2433,3492,0,1,0}-{2458,3497,0,1,0}-{2464,3505,0,1,0}-{2476,3458,0,1,0}-{2445,3502,1,1,0}-{2453,3488,1,1,0}-{2475,3502,1,1,0}-{2465,3490,2,1,0}-{2401,3357,0,1,0}-" "loc_data": "{2401,3357,0,1,0}-{2378,3423,0,1,0}-{2393,3435,0,1,0}-{2394,3425,0,1,0}-{2395,3449,0,1,0}-{2403,3433,0,1,0}-{2420,3429,0,1,0}-{2420,3438,0,1,0}-{2400,3514,1,1,0}-{2418,3485,1,1,0}-{2433,3474,0,1,0}-{2433,3492,0,1,0}-{2458,3497,0,1,0}-{2464,3505,0,1,0}-{2476,3458,0,1,0}-{2445,3502,1,1,0}-{2453,3488,1,1,0}-{2475,3502,1,1,0}-{2465,3490,2,1,0}-{2522,3172,0,1,0}-"
}, },
{ {
"npc_id": "73", "npc_id": "73",
@ -325,11 +325,11 @@
}, },
{ {
"npc_id": "100", "npc_id": "100",
"loc_data": "{2567,3440,0,1,3}-{2564,9653,0,1,0}-{2565,9655,0,1,0}-{2566,9626,0,1,0}-{2567,9653,0,1,0}-{2569,9633,0,1,0}-{2607,9621,0,1,0}-{2551,3408,0,1,6}-{2553,3405,0,1,3}-{2559,3452,0,1,3}-" "loc_data": "{2567,3440,0,1,3}-{2316,9392,0,1,0}-{2319,9367,0,1,0}-{2321,9402,0,1,0}-{2322,9387,0,1,0}-{2325,9360,0,1,0}-{2333,9346,0,1,0}-{2335,9382,0,1,0}-{2337,9387,0,1,0}-{2343,9360,0,1,0}-{2344,9369,0,1,0}-{2348,9390,0,1,0}-{2349,9380,0,1,0}-{2349,9402,0,1,0}-{2359,9345,0,1,0}-{2359,9359,0,1,0}-{2359,9374,0,1,0}-{2359,9382,0,1,0}-{2363,9403,0,1,0}-{2564,9653,0,1,0}-{2565,9655,0,1,0}-{2566,9626,0,1,0}-{2567,9653,0,1,0}-{2569,9633,0,1,0}-{2607,9621,0,1,0}-{2551,3408,0,1,6}-{2553,3405,0,1,3}-{2559,3452,0,1,3}-"
}, },
{ {
"npc_id": "101", "npc_id": "101",
"loc_data": "{2622,3389,0,1,4}-{2619,3390,0,1,4}-{2573,3437,0,1,3}-{2562,9659,0,1,0}-{2563,9661,0,1,0}-{2599,9626,0,1,0}-{2601,9627,0,1,0}-{2605,9621,0,1,0}-{2610,9620,0,1,0}-{2624,3391,0,1,1}-{2555,3407,0,1,3}-{2553,3457,0,1,3}-" "loc_data": "{2622,3389,0,1,4}-{2619,3390,0,1,4}-{2573,3437,0,1,3}-{2305,9385,0,1,0}-{2307,9359,0,1,0}-{2307,9403,0,1,0}-{2310,9396,0,1,0}-{2317,9371,0,1,0}-{2317,9383,0,1,0}-{2324,9404,0,1,0}-{2333,9366,0,1,0}-{2335,9393,0,1,0}-{2339,9403,0,1,0}-{2342,9347,0,1,0}-{2351,9359,0,1,0}-{2359,9392,0,1,0}-{2562,9659,0,1,0}-{2563,9661,0,1,0}-{2599,9626,0,1,0}-{2601,9627,0,1,0}-{2605,9621,0,1,0}-{2610,9620,0,1,0}-{2624,3391,0,1,1}-{2555,3407,0,1,3}-{2553,3457,0,1,3}-"
}, },
{ {
"npc_id": "102", "npc_id": "102",
@ -345,7 +345,7 @@
}, },
{ {
"npc_id": "105", "npc_id": "105",
"loc_data": "{3100,3594,0,1,6}-{3107,3608,0,1,2}-{3099,3602,0,1,0}-{2632,3280,0,1,1}-{2633,3274,0,1,3}-{2696,3329,0,1,4}-{2708,3336,0,1,4}-{3230,3500,0,1,5}-{2988,3671,0,1,0}-{3001,3674,0,1,0}-{2497,3164,0,1,2}-{2387,3376,0,1,0}-{2398,3366,0,1,0}-{2412,3378,0,1,0}-{2419,3372,0,1,0}-" "loc_data": "{3100,3594,0,1,6}-{3107,3608,0,1,2}-{3099,3602,0,1,0}-{2632,3280,0,1,1}-{2633,3274,0,1,3}-{2387,3376,0,1,0}-{2398,3366,0,1,0}-{2412,3378,0,1,0}-{2419,3372,0,1,0}-{2696,3329,0,1,4}-{2708,3336,0,1,4}-{3230,3500,0,1,5}-{2988,3671,0,1,0}-{3001,3674,0,1,0}-{2497,3164,0,1,2}-"
}, },
{ {
"npc_id": "106", "npc_id": "106",
@ -365,7 +365,7 @@
}, },
{ {
"npc_id": "110", "npc_id": "110",
"loc_data": "{2564,9887,0,1,4}-{2581,9897,0,1,1}-{2577,9888,0,1,1}-{3234,5497,0,1,1}-{3305,9400,0,1,1}-{3244,9356,0,1,1}-{3252,9370,0,1,1}-{3294,9375,0,1,3}-{3050,10337,0,1,4}-{3047,10340,0,1,4}-{3048,10346,0,1,4}-{3048,10346,0,1,3}-" "loc_data": "{2564,9887,0,1,4}-{2581,9897,0,1,1}-{2577,9888,0,1,1}-{3234,5497,0,1,1}-{3244,9356,0,1,1}-{3252,9370,0,1,1}-{3305,9400,0,1,1}-{3294,9375,0,1,3}-{3050,10337,0,1,4}-{3047,10340,0,1,4}-{3048,10346,0,1,4}-{3048,10346,0,1,3}-"
}, },
{ {
"npc_id": "111", "npc_id": "111",
@ -389,7 +389,7 @@
}, },
{ {
"npc_id": "117", "npc_id": "117",
"loc_data": "{2369,3404,0,1,0}-{3118,9845,0,1,4}-{3111,9844,0,1,6}-{3123,9845,0,1,3}-{3114,9833,0,1,3}-{3110,9841,0,1,1}-{3119,9839,0,1,1}-{3097,9832,0,1,0}-{3101,9832,0,1,1}-{3107,9829,0,1,3}-{3115,9831,0,1,4}-{3109,9835,0,1,4}-{2904,9734,0,1,0}-{2548,3146,0,1,1}-{2542,3145,0,1,4}-{2503,3150,0,1,4}-{3300,3649,0,1,0}-{3044,10321,0,1,2}-{3044,10316,0,1,4}-{3045,10308,0,1,4}-{3048,10317,0,1,2}-" "loc_data": "{3118,9845,0,1,4}-{3111,9844,0,1,6}-{3123,9845,0,1,3}-{3114,9833,0,1,3}-{3110,9841,0,1,1}-{3119,9839,0,1,1}-{3097,9832,0,1,0}-{3101,9832,0,1,1}-{3107,9829,0,1,3}-{3115,9831,0,1,4}-{3109,9835,0,1,4}-{2369,3404,0,1,0}-{2904,9734,0,1,0}-{2548,3146,0,1,1}-{2542,3145,0,1,4}-{2503,3150,0,1,4}-{3300,3649,0,1,0}-{3044,10321,0,1,2}-{3044,10316,0,1,4}-{3045,10308,0,1,4}-{3048,10317,0,1,2}-"
}, },
{ {
"npc_id": "118", "npc_id": "118",
@ -489,23 +489,23 @@
}, },
{ {
"npc_id": "153", "npc_id": "153",
"loc_data": "{2540,9820,0,1,0}-{2543,9813,0,1,0}-{2546,9817,0,1,0}-{2464,4421,0,1,0}-{2466,4423,0,1,0}-{2486,4464,0,1,0}-{2556,3444,0,1,0}-{3082,3077,0,1,0}-{3092,3082,0,1,0}-{3109,3090,0,1,0}-{3112,3093,0,1,0}-{2249,3260,0,1,0}-{2250,3257,0,1,0}-{2250,3259,0,1,0}-{2252,3261,0,1,0}-{2253,3256,0,1,0}-{2262,3226,0,1,0}-{2264,3225,0,1,0}-{2266,3229,0,1,0}-{2268,3227,0,1,0}-{2269,3222,0,1,0}-{2269,3224,0,1,0}-{2270,3223,0,1,0}-{2270,3226,0,1,0}-{3200,5954,0,1,0}-{3202,5958,0,1,0}-{3204,5955,0,1,0}-{3204,5959,0,1,0}-{3231,5967,0,1,0}-{3236,5974,0,1,0}-{3237,5968,0,1,0}-{3240,5992,0,1,0}-{3240,5994,0,1,0}-{3242,5990,0,1,0}-{3242,5993,0,1,0}-{3244,5994,0,1,0}-{3246,5989,0,1,0}-{2196,3191,0,1,0}-{2197,3189,0,1,0}-{2198,3181,0,1,0}-{2198,3187,0,1,0}-{2199,3183,0,1,0}-{2199,3187,0,1,0}-{2200,3185,0,1,0}-{2201,3185,0,1,0}-{2204,3180,0,1,0}-{2324,4599,0,1,0}-{2325,4597,0,1,0}-{2326,4589,0,1,0}-{2326,4595,0,1,0}-{2327,4591,0,1,0}-{2327,4595,0,1,0}-{2328,4593,0,1,0}-{2329,4593,0,1,0}-{2332,4588,0,1,0}-{2176,3202,0,1,0}-{2178,3206,0,1,0}-{2180,3203,0,1,0}-{2180,3207,0,1,0}-{2207,3215,0,1,0}-{2212,3222,0,1,0}-{2213,3216,0,1,0}-{2216,3240,0,1,0}-{2216,3242,0,1,0}-{2218,3238,0,1,0}-{2218,3241,0,1,0}-{2220,3242,0,1,0}-{2222,3237,0,1,0}-{2437,3425,0,1,0}-{2438,3422,0,1,0}-{2450,3419,0,1,0}-{2415,4466,0,1,0}-{2419,4427,0,1,0}-{2421,4468,0,1,0}-{2426,4431,0,1,0}-{3175,3226,0,1,0}-{3178,3228,0,1,0}-{3179,3226,0,1,0}-{3182,3251,0,1,0}-{3183,3254,0,1,0}-{2697,6204,0,1,0}-{2698,6201,0,1,0}-{2698,6203,0,1,0}-{2700,6205,0,1,0}-{2701,6200,0,1,0}-{2710,6170,0,1,0}-{2712,6169,0,1,0}-{2714,6173,0,1,0}-{2716,6171,0,1,0}-{2717,6166,0,1,0}-{2717,6168,0,1,0}-{2718,6167,0,1,0}-{2718,6170,0,1,0}-{2478,3373,0,1,0}-{2479,3381,0,1,0}-{2481,3384,0,1,0}-{2490,3371,0,1,0}-{2689,6083,0,1,0}-{2689,6088,0,1,0}-{2690,6094,0,1,0}-{2691,6084,0,1,0}-{2692,6081,0,1,0}-{2692,6090,0,1,0}-{2693,6083,0,1,0}-{2693,6085,0,1,0}-{2693,6090,0,1,0}-{2694,6083,0,1,0}-{2694,6086,0,1,0}-{2695,6082,0,1,0}-{2695,6085,0,1,0}-{2695,6088,0,1,0}-{2695,6091,0,1,0}-{2695,6121,0,1,0}-{2698,6121,0,1,0}-{2699,6082,0,1,0}-{2699,6085,0,1,0}-{2700,6084,0,1,0}-{2701,6085,0,1,0}-{2702,6081,0,1,0}-{2702,6083,0,1,0}-{2703,6119,0,1,0}-{2704,6117,0,1,0}-{2705,6121,0,1,0}-{2730,6091,0,1,0}-{2732,6095,0,1,0}-{2734,6090,0,1,0}-{2735,6094,0,1,0}-{2735,6097,0,1,0}-{2738,6098,0,1,0}-{2416,3404,0,1,0}-{2424,3410,0,1,0}-{2430,3405,0,1,0}-{1906,5223,0,1,0}-{1907,5221,0,1,0}-{3273,6012,0,1,0}-{3274,6009,0,1,0}-{3274,6011,0,1,0}-{3276,6013,0,1,0}-{3277,6008,0,1,0}-{3286,5978,0,1,0}-{3288,5977,0,1,0}-{3290,5981,0,1,0}-{3292,5979,0,1,0}-{3293,5974,0,1,0}-{3293,5976,0,1,0}-{3294,5975,0,1,0}-{3294,5978,0,1,0}-{2828,5091,0,1,0}-{2832,5108,0,1,0}-{2835,5079,0,1,0}-{2846,5067,0,1,0}-{2850,5111,0,1,0}-{2853,5086,0,1,0}-{2864,5071,0,1,0}-{2549,3139,0,1,0}-{2241,3139,0,1,0}-{2241,3144,0,1,0}-{2242,3150,0,1,0}-{2243,3140,0,1,0}-{2244,3137,0,1,0}-{2244,3146,0,1,0}-{2245,3139,0,1,0}-{2245,3141,0,1,0}-{2245,3146,0,1,0}-{2246,3139,0,1,0}-{2246,3142,0,1,0}-{2247,3138,0,1,0}-{2247,3141,0,1,0}-{2247,3144,0,1,0}-{2247,3147,0,1,0}-{2247,3177,0,1,0}-{2250,3177,0,1,0}-{2251,3138,0,1,0}-{2251,3141,0,1,0}-{2252,3140,0,1,0}-{2253,3141,0,1,0}-{2254,3137,0,1,0}-{2254,3139,0,1,0}-{2255,3175,0,1,0}-{2256,3173,0,1,0}-{2257,3177,0,1,0}-{2282,3147,0,1,0}-{2284,3151,0,1,0}-{2286,3146,0,1,0}-{2287,3150,0,1,0}-{2287,3153,0,1,0}-{2290,3154,0,1,0}-" "loc_data": "{3082,3077,0,1,0}-{3092,3082,0,1,0}-{3109,3090,0,1,0}-{3112,3093,0,1,0}-{2324,4599,0,1,0}-{2325,4597,0,1,0}-{2326,4589,0,1,0}-{2326,4595,0,1,0}-{2327,4591,0,1,0}-{2327,4595,0,1,0}-{2328,4593,0,1,0}-{2329,4593,0,1,0}-{2332,4588,0,1,0}-{2828,5091,0,1,0}-{2832,5108,0,1,0}-{2835,5079,0,1,0}-{2846,5067,0,1,0}-{2850,5111,0,1,0}-{2853,5086,0,1,0}-{2864,5071,0,1,0}-{3175,3226,0,1,0}-{3178,3228,0,1,0}-{3179,3226,0,1,0}-{3182,3251,0,1,0}-{3183,3254,0,1,0}-{2416,3404,0,1,0}-{2424,3410,0,1,0}-{2430,3405,0,1,0}-{2415,4466,0,1,0}-{2419,4427,0,1,0}-{2421,4468,0,1,0}-{2426,4431,0,1,0}-{1906,5223,0,1,0}-{1907,5221,0,1,0}-{2196,3191,0,1,0}-{2197,3189,0,1,0}-{2198,3181,0,1,0}-{2198,3187,0,1,0}-{2199,3183,0,1,0}-{2199,3187,0,1,0}-{2200,3185,0,1,0}-{2201,3185,0,1,0}-{2204,3180,0,1,0}-{2176,3202,0,1,0}-{2178,3206,0,1,0}-{2180,3203,0,1,0}-{2180,3207,0,1,0}-{2207,3215,0,1,0}-{2212,3222,0,1,0}-{2213,3216,0,1,0}-{2216,3240,0,1,0}-{2216,3242,0,1,0}-{2218,3238,0,1,0}-{2218,3241,0,1,0}-{2220,3242,0,1,0}-{2222,3237,0,1,0}-{2478,3373,0,1,0}-{2479,3381,0,1,0}-{2481,3384,0,1,0}-{2490,3371,0,1,0}-{2437,3425,0,1,0}-{2438,3422,0,1,0}-{2450,3419,0,1,0}-{2464,4421,0,1,0}-{2466,4423,0,1,0}-{2486,4464,0,1,0}-{3200,5954,0,1,0}-{3202,5958,0,1,0}-{3204,5955,0,1,0}-{3204,5959,0,1,0}-{3231,5967,0,1,0}-{3236,5974,0,1,0}-{3237,5968,0,1,0}-{3240,5992,0,1,0}-{3240,5994,0,1,0}-{3242,5990,0,1,0}-{3242,5993,0,1,0}-{3244,5994,0,1,0}-{3246,5989,0,1,0}-{2689,6083,0,1,0}-{2689,6088,0,1,0}-{2690,6094,0,1,0}-{2691,6084,0,1,0}-{2692,6081,0,1,0}-{2692,6090,0,1,0}-{2693,6083,0,1,0}-{2693,6085,0,1,0}-{2693,6090,0,1,0}-{2694,6083,0,1,0}-{2694,6086,0,1,0}-{2695,6082,0,1,0}-{2695,6085,0,1,0}-{2695,6088,0,1,0}-{2695,6091,0,1,0}-{2695,6121,0,1,0}-{2698,6121,0,1,0}-{2699,6082,0,1,0}-{2699,6085,0,1,0}-{2700,6084,0,1,0}-{2701,6085,0,1,0}-{2702,6081,0,1,0}-{2702,6083,0,1,0}-{2703,6119,0,1,0}-{2704,6117,0,1,0}-{2705,6121,0,1,0}-{2730,6091,0,1,0}-{2732,6095,0,1,0}-{2734,6090,0,1,0}-{2735,6094,0,1,0}-{2735,6097,0,1,0}-{2738,6098,0,1,0}-{2697,6204,0,1,0}-{2698,6201,0,1,0}-{2698,6203,0,1,0}-{2700,6205,0,1,0}-{2701,6200,0,1,0}-{2710,6170,0,1,0}-{2712,6169,0,1,0}-{2714,6173,0,1,0}-{2716,6171,0,1,0}-{2717,6166,0,1,0}-{2717,6168,0,1,0}-{2718,6167,0,1,0}-{2718,6170,0,1,0}-{2549,3139,0,1,0}-{2241,3139,0,1,0}-{2241,3144,0,1,0}-{2242,3150,0,1,0}-{2243,3140,0,1,0}-{2244,3137,0,1,0}-{2244,3146,0,1,0}-{2245,3139,0,1,0}-{2245,3141,0,1,0}-{2245,3146,0,1,0}-{2246,3139,0,1,0}-{2246,3142,0,1,0}-{2247,3138,0,1,0}-{2247,3141,0,1,0}-{2247,3144,0,1,0}-{2247,3147,0,1,0}-{2247,3177,0,1,0}-{2250,3177,0,1,0}-{2251,3138,0,1,0}-{2251,3141,0,1,0}-{2252,3140,0,1,0}-{2253,3141,0,1,0}-{2254,3137,0,1,0}-{2254,3139,0,1,0}-{2255,3175,0,1,0}-{2256,3173,0,1,0}-{2257,3177,0,1,0}-{2282,3147,0,1,0}-{2284,3151,0,1,0}-{2286,3146,0,1,0}-{2287,3150,0,1,0}-{2287,3153,0,1,0}-{2290,3154,0,1,0}-{2249,3260,0,1,0}-{2250,3257,0,1,0}-{2250,3259,0,1,0}-{2252,3261,0,1,0}-{2253,3256,0,1,0}-{2262,3226,0,1,0}-{2264,3225,0,1,0}-{2266,3229,0,1,0}-{2268,3227,0,1,0}-{2269,3222,0,1,0}-{2269,3224,0,1,0}-{2270,3223,0,1,0}-{2270,3226,0,1,0}-{2556,3444,0,1,0}-{3273,6012,0,1,0}-{3274,6009,0,1,0}-{3274,6011,0,1,0}-{3276,6013,0,1,0}-{3277,6008,0,1,0}-{3286,5978,0,1,0}-{3288,5977,0,1,0}-{3290,5981,0,1,0}-{3292,5979,0,1,0}-{3293,5974,0,1,0}-{3293,5976,0,1,0}-{3294,5975,0,1,0}-{3294,5978,0,1,0}-{2540,9820,0,1,0}-{2543,9813,0,1,0}-{2546,9817,0,1,0}-"
}, },
{ {
"npc_id": "154", "npc_id": "154",
"loc_data": "{2475,4459,0,1,0}-{2480,4458,0,1,0}-{2481,4454,0,1,0}-{2488,4465,0,1,0}-{3125,3084,0,1,0}-{2268,3228,0,1,0}-{3202,5955,0,1,0}-{3206,5953,0,1,0}-{3231,5976,0,1,0}-{3233,5974,0,1,0}-{3235,5970,0,1,0}-{3241,5996,0,1,0}-{3242,5988,0,1,0}-{3244,5992,0,1,0}-{2180,3173,0,1,0}-{2193,3187,0,1,0}-{2196,3184,0,1,0}-{2200,3181,0,1,0}-{2200,3188,0,1,0}-{2203,3189,0,1,0}-{2308,4581,0,1,0}-{2321,4595,0,1,0}-{2324,4592,0,1,0}-{2328,4589,0,1,0}-{2328,4596,0,1,0}-{2331,4597,0,1,0}-{2178,3203,0,1,0}-{2182,3201,0,1,0}-{2207,3224,0,1,0}-{2209,3222,0,1,0}-{2211,3218,0,1,0}-{2217,3244,0,1,0}-{2218,3236,0,1,0}-{2220,3240,0,1,0}-{2446,3396,0,1,0}-{2470,3397,0,1,0}-{2394,4453,0,1,0}-{2394,4457,0,1,0}-{2406,4447,0,1,0}-{2422,3489,0,1,0}-{2716,6172,0,1,0}-{2688,6092,0,1,0}-{2690,6087,0,1,0}-{2690,6095,0,1,0}-{2692,6082,0,1,0}-{2692,6088,0,1,0}-{2692,6123,0,1,0}-{2693,6081,0,1,0}-{2694,6125,0,1,0}-{2695,6087,0,1,0}-{2697,6086,0,1,0}-{2697,6087,0,1,0}-{2698,6081,0,1,0}-{2698,6124,0,1,0}-{2700,6083,0,1,0}-{2702,6084,0,1,0}-{2726,6085,0,1,0}-{2727,6081,0,1,0}-{2729,6083,0,1,0}-{2732,6084,0,1,0}-{2378,3418,0,1,0}-{2380,3422,0,1,0}-{2393,3442,0,1,0}-{2397,3440,0,1,0}-{2423,3399,0,1,0}-{2425,3406,0,1,0}-{2427,3402,0,1,0}-{1908,5222,0,1,0}-{3292,5980,0,1,0}-{2831,5070,0,1,0}-{2843,5106,0,1,0}-{2844,5080,0,1,0}-{2860,5079,0,1,0}-{2866,5104,0,1,0}-{2868,5096,0,1,0}-{2240,3148,0,1,0}-{2242,3143,0,1,0}-{2242,3151,0,1,0}-{2244,3138,0,1,0}-{2244,3144,0,1,0}-{2244,3179,0,1,0}-{2245,3137,0,1,0}-{2246,3181,0,1,0}-{2247,3143,0,1,0}-{2249,3142,0,1,0}-{2249,3143,0,1,0}-{2250,3137,0,1,0}-{2250,3180,0,1,0}-{2252,3139,0,1,0}-{2254,3140,0,1,0}-{2278,3141,0,1,0}-{2279,3137,0,1,0}-{2281,3139,0,1,0}-{2284,3140,0,1,0}-" "loc_data": "{3125,3084,0,1,0}-{2308,4581,0,1,0}-{2321,4595,0,1,0}-{2324,4592,0,1,0}-{2328,4589,0,1,0}-{2328,4596,0,1,0}-{2331,4597,0,1,0}-{2831,5070,0,1,0}-{2843,5106,0,1,0}-{2844,5080,0,1,0}-{2860,5079,0,1,0}-{2866,5104,0,1,0}-{2868,5096,0,1,0}-{2378,3418,0,1,0}-{2380,3422,0,1,0}-{2393,3442,0,1,0}-{2397,3440,0,1,0}-{2423,3399,0,1,0}-{2425,3406,0,1,0}-{2427,3402,0,1,0}-{2422,3489,0,1,0}-{2394,4453,0,1,0}-{2394,4457,0,1,0}-{2406,4447,0,1,0}-{1908,5222,0,1,0}-{2180,3173,0,1,0}-{2193,3187,0,1,0}-{2196,3184,0,1,0}-{2200,3181,0,1,0}-{2200,3188,0,1,0}-{2203,3189,0,1,0}-{2178,3203,0,1,0}-{2182,3201,0,1,0}-{2207,3224,0,1,0}-{2209,3222,0,1,0}-{2211,3218,0,1,0}-{2217,3244,0,1,0}-{2218,3236,0,1,0}-{2220,3240,0,1,0}-{2446,3396,0,1,0}-{2470,3397,0,1,0}-{2475,4459,0,1,0}-{2480,4458,0,1,0}-{2481,4454,0,1,0}-{2488,4465,0,1,0}-{3202,5955,0,1,0}-{3206,5953,0,1,0}-{3231,5976,0,1,0}-{3233,5974,0,1,0}-{3235,5970,0,1,0}-{3241,5996,0,1,0}-{3242,5988,0,1,0}-{3244,5992,0,1,0}-{2688,6092,0,1,0}-{2690,6087,0,1,0}-{2690,6095,0,1,0}-{2692,6082,0,1,0}-{2692,6088,0,1,0}-{2692,6123,0,1,0}-{2693,6081,0,1,0}-{2694,6125,0,1,0}-{2695,6087,0,1,0}-{2697,6086,0,1,0}-{2697,6087,0,1,0}-{2698,6081,0,1,0}-{2698,6124,0,1,0}-{2700,6083,0,1,0}-{2702,6084,0,1,0}-{2726,6085,0,1,0}-{2727,6081,0,1,0}-{2729,6083,0,1,0}-{2732,6084,0,1,0}-{2716,6172,0,1,0}-{2240,3148,0,1,0}-{2242,3143,0,1,0}-{2242,3151,0,1,0}-{2244,3138,0,1,0}-{2244,3144,0,1,0}-{2244,3179,0,1,0}-{2245,3137,0,1,0}-{2246,3181,0,1,0}-{2247,3143,0,1,0}-{2249,3142,0,1,0}-{2249,3143,0,1,0}-{2250,3137,0,1,0}-{2250,3180,0,1,0}-{2252,3139,0,1,0}-{2254,3140,0,1,0}-{2278,3141,0,1,0}-{2279,3137,0,1,0}-{2281,3139,0,1,0}-{2284,3140,0,1,0}-{2268,3228,0,1,0}-{3292,5980,0,1,0}-"
}, },
{ {
"npc_id": "155", "npc_id": "155",
"loc_data": "{3093,3086,0,1,0}-{3097,3085,0,1,0}-{3129,3091,0,1,0}-{3135,3084,0,1,0}-{2190,3180,0,1,0}-{2318,4588,0,1,0}-{2374,3469,0,1,0}-{2376,3466,0,1,0}-{3254,3230,0,1,0}-{1986,5564,0,1,0}-{2434,3516,0,1,0}-{2479,3501,0,1,0}-" "loc_data": "{3093,3086,0,1,0}-{3097,3085,0,1,0}-{3129,3091,0,1,0}-{3135,3084,0,1,0}-{2318,4588,0,1,0}-{2374,3469,0,1,0}-{2376,3466,0,1,0}-{2190,3180,0,1,0}-{3254,3230,0,1,0}-{2434,3516,0,1,0}-{2479,3501,0,1,0}-{1986,5564,0,1,0}-"
}, },
{ {
"npc_id": "156", "npc_id": "156",
"loc_data": "{2371,3460,0,1,0}-{2372,3456,0,1,0}-{2422,3467,0,1,0}-{2725,6127,0,1,0}-{2444,3491,0,1,0}-{2277,3183,0,1,0}-" "loc_data": "{2371,3460,0,1,0}-{2372,3456,0,1,0}-{2422,3467,0,1,0}-{2444,3491,0,1,0}-{2725,6127,0,1,0}-{2277,3183,0,1,0}-"
}, },
{ {
"npc_id": "157", "npc_id": "157",
"loc_data": "{2180,2798,0,1,0}-{2209,2812,0,1,0}-{2217,2780,0,1,0}-{1921,5931,0,1,0}-{1947,5908,0,1,0}-{1955,5949,0,1,0}-{1973,5888,0,1,0}-{1975,5918,0,1,0}-{1988,5870,0,1,0}-{2017,5884,0,1,0}-{2025,5852,0,1,0}-{2182,2979,0,1,0}-{2211,2963,0,1,0}-{1931,6038,0,1,0}-{1983,6037,0,1,0}-{2153,2810,0,1,0}-{2172,2806,0,1,0}-{1961,5882,0,1,0}-{1980,5878,0,1,0}-{2242,2788,0,1,0}-{2248,2858,0,1,0}-{2256,2828,0,1,0}-{2284,2874,0,1,0}-{2255,3216,0,1,0}-{2262,3210,0,1,0}-{2271,3204,0,1,0}-{2294,3219,0,1,0}-{2296,3206,0,1,0}-{2298,3201,0,1,0}-{2056,5930,0,1,0}-{2064,5900,0,1,0}-{2092,5946,0,1,0}-{2050,5860,0,1,0}-{3201,5986,0,1,0}-{3254,5972,0,1,0}-{3255,5986,0,1,0}-{3256,6008,0,1,0}-{3257,5973,0,1,0}-{3257,5975,0,1,0}-{3260,5974,0,1,0}-{3261,5977,0,1,0}-{3262,5957,0,1,0}-{2194,3158,0,1,0}-{2216,3188,0,1,0}-{2217,3190,0,1,0}-{2220,3158,0,1,0}-{2222,3141,0,1,0}-{2229,3138,0,1,0}-{2231,3181,0,1,0}-{2236,3155,0,1,0}-{2278,2956,0,1,0}-{2322,4566,0,1,0}-{2344,4596,0,1,0}-{2345,4598,0,1,0}-{2348,4566,0,1,0}-{2350,4549,0,1,0}-{2357,4546,0,1,0}-{2359,4589,0,1,0}-{2364,4563,0,1,0}-{2177,3234,0,1,0}-{2230,3220,0,1,0}-{2231,3234,0,1,0}-{2232,3256,0,1,0}-{2233,3221,0,1,0}-{2233,3223,0,1,0}-{2236,3222,0,1,0}-{2237,3225,0,1,0}-{2238,3205,0,1,0}-{2479,3396,0,1,0}-{2102,2942,0,1,0}-{2108,2919,0,1,0}-{2104,2873,0,1,0}-{2122,6032,0,1,0}-{1912,5945,0,1,0}-{3143,3210,0,1,0}-{3155,3253,0,1,0}-{3163,3261,0,1,0}-{3168,3258,0,1,0}-{2086,6028,0,1,0}-{2703,6160,0,1,0}-{2710,6154,0,1,0}-{2719,6148,0,1,0}-{2742,6163,0,1,0}-{2744,6150,0,1,0}-{2746,6145,0,1,0}-{2314,2960,0,1,0}-{2723,6105,0,1,0}-{2739,6123,0,1,0}-{2744,6108,0,1,0}-{2326,2894,0,1,0}-{2333,2920,0,1,0}-{3279,5968,0,1,0}-{3286,5962,0,1,0}-{3295,5956,0,1,0}-{3318,5971,0,1,0}-{3320,5958,0,1,0}-{3322,5953,0,1,0}-{2134,5966,0,1,0}-{2141,5992,0,1,0}-{2123,2966,0,1,0}-{2175,2965,0,1,0}-{1910,6014,0,1,0}-{1916,5991,0,1,0}-{2540,3167,0,1,0}-{2110,2955,0,1,0}-{1990,6051,0,1,0}-{2019,6035,0,1,0}-{2447,3467,0,1,0}-{2448,3469,0,1,0}-{1918,6027,0,1,0}-{2275,3161,0,1,0}-{2291,3179,0,1,0}-{2296,3164,0,1,0}-{2113,2859,0,1,0}-{2139,2836,0,1,0}-{2147,2877,0,1,0}-{2165,2816,0,1,0}-{2167,2846,0,1,0}-" "loc_data": "{2104,2873,0,1,0}-{2102,2942,0,1,0}-{2108,2919,0,1,0}-{2326,2894,0,1,0}-{2333,2920,0,1,0}-{2314,2960,0,1,0}-{2110,2955,0,1,0}-{2322,4566,0,1,0}-{2344,4596,0,1,0}-{2345,4598,0,1,0}-{2348,4566,0,1,0}-{2350,4549,0,1,0}-{2357,4546,0,1,0}-{2359,4589,0,1,0}-{2364,4563,0,1,0}-{2050,5860,0,1,0}-{2056,5930,0,1,0}-{2064,5900,0,1,0}-{2092,5946,0,1,0}-{2086,6028,0,1,0}-{2153,2810,0,1,0}-{2172,2806,0,1,0}-{2113,2859,0,1,0}-{2139,2836,0,1,0}-{2147,2877,0,1,0}-{2165,2816,0,1,0}-{2167,2846,0,1,0}-{2123,2966,0,1,0}-{2175,2965,0,1,0}-{3143,3210,0,1,0}-{3155,3253,0,1,0}-{3163,3261,0,1,0}-{3168,3258,0,1,0}-{1912,5945,0,1,0}-{2134,5966,0,1,0}-{2141,5992,0,1,0}-{1910,6014,0,1,0}-{1916,5991,0,1,0}-{2122,6032,0,1,0}-{1918,6027,0,1,0}-{2180,2798,0,1,0}-{2209,2812,0,1,0}-{2217,2780,0,1,0}-{2182,2979,0,1,0}-{2211,2963,0,1,0}-{2194,3158,0,1,0}-{2216,3188,0,1,0}-{2217,3190,0,1,0}-{2220,3158,0,1,0}-{2222,3141,0,1,0}-{2229,3138,0,1,0}-{2231,3181,0,1,0}-{2236,3155,0,1,0}-{2177,3234,0,1,0}-{2230,3220,0,1,0}-{2231,3234,0,1,0}-{2232,3256,0,1,0}-{2233,3221,0,1,0}-{2233,3223,0,1,0}-{2236,3222,0,1,0}-{2237,3225,0,1,0}-{2238,3205,0,1,0}-{2479,3396,0,1,0}-{2447,3467,0,1,0}-{2448,3469,0,1,0}-{1961,5882,0,1,0}-{1980,5878,0,1,0}-{1921,5931,0,1,0}-{1947,5908,0,1,0}-{1955,5949,0,1,0}-{1973,5888,0,1,0}-{1975,5918,0,1,0}-{3201,5986,0,1,0}-{3254,5972,0,1,0}-{3255,5986,0,1,0}-{3256,6008,0,1,0}-{3257,5973,0,1,0}-{3257,5975,0,1,0}-{3260,5974,0,1,0}-{3261,5977,0,1,0}-{3262,5957,0,1,0}-{1931,6038,0,1,0}-{1983,6037,0,1,0}-{2723,6105,0,1,0}-{2739,6123,0,1,0}-{2744,6108,0,1,0}-{2703,6160,0,1,0}-{2710,6154,0,1,0}-{2719,6148,0,1,0}-{2742,6163,0,1,0}-{2744,6150,0,1,0}-{2746,6145,0,1,0}-{2242,2788,0,1,0}-{2248,2858,0,1,0}-{2256,2828,0,1,0}-{2284,2874,0,1,0}-{2278,2956,0,1,0}-{2540,3167,0,1,0}-{2275,3161,0,1,0}-{2291,3179,0,1,0}-{2296,3164,0,1,0}-{2255,3216,0,1,0}-{2262,3210,0,1,0}-{2271,3204,0,1,0}-{2294,3219,0,1,0}-{2296,3206,0,1,0}-{2298,3201,0,1,0}-{1988,5870,0,1,0}-{2017,5884,0,1,0}-{2025,5852,0,1,0}-{3279,5968,0,1,0}-{3286,5962,0,1,0}-{3295,5956,0,1,0}-{3318,5971,0,1,0}-{3320,5958,0,1,0}-{3322,5953,0,1,0}-{1990,6051,0,1,0}-{2019,6035,0,1,0}-"
}, },
{ {
"npc_id": "158", "npc_id": "158",
@ -513,7 +513,7 @@
}, },
{ {
"npc_id": "159", "npc_id": "159",
"loc_data": "{2392,3475,0,1,0}-{2394,3506,0,1,0}-{2396,3471,0,1,0}-{2405,3499,0,1,0}-{2416,3487,0,1,0}-{2413,3445,1,1,0}-{2415,3435,1,1,0}-{2416,3416,1,1,0}-{2424,3434,1,1,0}-{2483,3500,1,1,0}-" "loc_data": "{2413,3445,1,1,0}-{2415,3435,1,1,0}-{2416,3416,1,1,0}-{2424,3434,1,1,0}-{2392,3475,0,1,0}-{2394,3506,0,1,0}-{2396,3471,0,1,0}-{2405,3499,0,1,0}-{2416,3487,0,1,0}-{2483,3500,1,1,0}-"
}, },
{ {
"npc_id": "160", "npc_id": "160",
@ -529,11 +529,11 @@
}, },
{ {
"npc_id": "163", "npc_id": "163",
"loc_data": "{2451,3414,0,1,0}-{2459,3395,0,1,0}-{2459,3438,0,1,0}-{2462,3395,0,1,0}-{2445,3429,1,1,0}-{2409,3470,1,1,0}-{2416,3466,1,1,0}-{2420,3466,1,1,0}-{2461,9895,0,1,0}-{2465,9894,0,1,0}-{2465,9899,0,1,0}-{2459,3385,0,1,0}-{2463,3385,0,1,0}-{2392,3454,0,1,0}-{2394,3436,0,1,0}-{2408,3452,0,1,0}-{2421,3413,0,1,0}-{2442,3489,0,1,0}-{2450,3485,0,1,0}-{2451,3507,0,1,0}-{2453,3490,0,1,0}-{2459,3503,0,1,0}-{2461,3509,0,1,0}-{2464,3465,0,1,0}-{2464,3468,0,1,0}-{2468,3465,0,1,0}-{2468,3468,0,1,0}-{2468,3506,0,1,0}-{2472,3484,0,1,0}-{2475,3490,0,1,0}-{2475,3502,0,1,0}-{2477,3512,0,1,0}-{2481,3485,0,1,0}-{2482,3501,0,1,0}-{2467,3495,1,1,0}-{2473,3495,1,1,0}-{2448,3497,2,1,0}-{2463,3480,2,1,0}-{2465,3497,2,1,0}-{2465,3510,2,1,0}-{2466,3480,2,1,0}-" "loc_data": "{2392,3454,0,1,0}-{2394,3436,0,1,0}-{2408,3452,0,1,0}-{2421,3413,0,1,0}-{2409,3470,1,1,0}-{2416,3466,1,1,0}-{2420,3466,1,1,0}-{2459,3385,0,1,0}-{2463,3385,0,1,0}-{2451,3414,0,1,0}-{2459,3395,0,1,0}-{2459,3438,0,1,0}-{2462,3395,0,1,0}-{2445,3429,1,1,0}-{2442,3489,0,1,0}-{2450,3485,0,1,0}-{2451,3507,0,1,0}-{2453,3490,0,1,0}-{2459,3503,0,1,0}-{2461,3509,0,1,0}-{2464,3465,0,1,0}-{2464,3468,0,1,0}-{2468,3465,0,1,0}-{2468,3468,0,1,0}-{2468,3506,0,1,0}-{2472,3484,0,1,0}-{2475,3490,0,1,0}-{2475,3502,0,1,0}-{2477,3512,0,1,0}-{2481,3485,0,1,0}-{2482,3501,0,1,0}-{2467,3495,1,1,0}-{2473,3495,1,1,0}-{2448,3497,2,1,0}-{2463,3480,2,1,0}-{2465,3497,2,1,0}-{2465,3510,2,1,0}-{2466,3480,2,1,0}-{2461,9895,0,1,0}-{2465,9894,0,1,0}-{2465,9899,0,1,0}-"
}, },
{ {
"npc_id": "164", "npc_id": "164",
"loc_data": "{2459,3392,0,1,0}-{2461,3422,0,1,0}-{2462,3392,0,1,0}-{2460,3382,0,1,0}-{2462,3382,0,1,0}-{2410,3416,0,1,0}-{2420,3435,0,1,0}-{2420,3447,0,1,0}-{2427,3410,0,1,0}-{2012,5535,2,1,0}-{2023,5544,2,1,0}-{2441,3497,0,1,0}-{2447,3510,0,1,0}-{2461,3487,0,1,0}-{2464,3472,0,1,0}-{2464,3489,0,1,0}-{2467,3489,0,1,0}-{2468,3472,0,1,0}-{2473,3503,0,1,0}-{2478,3497,0,1,0}-{2464,3496,1,1,0}-{2448,3495,2,1,0}-{2460,3487,2,1,0}-{2467,3494,2,1,0}-{2467,3510,2,1,0}-{2471,3496,2,1,0}-{2483,3495,2,1,0}-{2483,3497,2,1,0}-" "loc_data": "{2410,3416,0,1,0}-{2420,3435,0,1,0}-{2420,3447,0,1,0}-{2427,3410,0,1,0}-{2460,3382,0,1,0}-{2462,3382,0,1,0}-{2459,3392,0,1,0}-{2461,3422,0,1,0}-{2462,3392,0,1,0}-{2441,3497,0,1,0}-{2447,3510,0,1,0}-{2461,3487,0,1,0}-{2464,3472,0,1,0}-{2464,3489,0,1,0}-{2467,3489,0,1,0}-{2468,3472,0,1,0}-{2473,3503,0,1,0}-{2478,3497,0,1,0}-{2464,3496,1,1,0}-{2448,3495,2,1,0}-{2460,3487,2,1,0}-{2467,3494,2,1,0}-{2467,3510,2,1,0}-{2471,3496,2,1,0}-{2483,3495,2,1,0}-{2483,3497,2,1,0}-{2012,5535,2,1,0}-{2023,5544,2,1,0}-"
}, },
{ {
"npc_id": "166", "npc_id": "166",
@ -541,11 +541,11 @@
}, },
{ {
"npc_id": "168", "npc_id": "168",
"loc_data": "{2434,3436,0,1,0}-{2437,3451,0,1,0}-{2438,3427,0,1,0}-{2441,3411,0,1,0}-{2466,3449,0,1,0}-{2470,3399,0,1,0}-{2472,3400,0,1,0}-{2473,3412,0,1,0}-{2476,3454,0,1,0}-{2482,3397,0,1,0}-{2489,3401,0,1,0}-{2479,3407,1,1,0}-{2379,3482,0,1,0}-{2381,3496,0,1,0}-{2384,3497,0,1,0}-{2391,3476,0,1,0}-{2410,3496,0,1,0}-{2421,3481,0,1,0}-{2397,3514,1,1,0}-{2398,3451,1,1,0}-{2414,3447,1,1,0}-{2438,3465,0,1,0}-{2442,3505,0,1,0}-{2448,3486,0,1,0}-{2449,3487,0,1,0}-{2450,3489,0,1,0}-{2450,3505,0,1,0}-{2454,3465,0,1,0}-{2449,3486,1,1,0}-{2457,3488,1,1,0}-{2476,3488,1,1,0}-{2450,3496,2,1,0}-{2467,3488,2,1,0}-{2470,3503,2,1,0}-{2481,3498,2,1,0}-" "loc_data": "{2398,3451,1,1,0}-{2414,3447,1,1,0}-{2379,3482,0,1,0}-{2381,3496,0,1,0}-{2384,3497,0,1,0}-{2391,3476,0,1,0}-{2410,3496,0,1,0}-{2421,3481,0,1,0}-{2397,3514,1,1,0}-{2434,3436,0,1,0}-{2437,3451,0,1,0}-{2438,3427,0,1,0}-{2441,3411,0,1,0}-{2466,3449,0,1,0}-{2470,3399,0,1,0}-{2472,3400,0,1,0}-{2473,3412,0,1,0}-{2476,3454,0,1,0}-{2482,3397,0,1,0}-{2489,3401,0,1,0}-{2479,3407,1,1,0}-{2438,3465,0,1,0}-{2442,3505,0,1,0}-{2448,3486,0,1,0}-{2449,3487,0,1,0}-{2450,3489,0,1,0}-{2450,3505,0,1,0}-{2454,3465,0,1,0}-{2449,3486,1,1,0}-{2457,3488,1,1,0}-{2476,3488,1,1,0}-{2450,3496,2,1,0}-{2467,3488,2,1,0}-{2470,3503,2,1,0}-{2481,3498,2,1,0}-"
}, },
{ {
"npc_id": "169", "npc_id": "169",
"loc_data": "{2439,3433,0,1,0}-{2441,3449,0,1,0}-{2442,3428,0,1,0}-{2446,3403,0,1,0}-{2450,3416,0,1,0}-{2468,3441,0,1,0}-{2480,3408,0,1,0}-{2480,3406,1,1,0}-{2486,3400,1,1,0}-{2378,3482,0,1,0}-{2383,3496,0,1,0}-{2402,3507,0,1,0}-{2406,3476,0,1,0}-{2422,3485,0,1,0}-{2382,3506,1,1,0}-{2418,3472,1,1,0}-{2392,3450,1,1,0}-{2415,3415,1,1,0}-{2416,3434,1,1,0}-{2423,3425,1,1,0}-{2424,3442,1,1,0}-{2448,3489,0,1,0}-{2450,3488,0,1,0}-{2463,3508,0,1,0}-{2473,3489,0,1,0}-{2474,3457,0,1,0}-{2479,3503,0,1,0}-{2486,3467,0,1,0}-{2437,3463,1,1,0}-{2448,3489,1,1,0}-{2482,3508,1,1,0}-" "loc_data": "{2392,3450,1,1,0}-{2415,3415,1,1,0}-{2416,3434,1,1,0}-{2423,3425,1,1,0}-{2424,3442,1,1,0}-{2378,3482,0,1,0}-{2383,3496,0,1,0}-{2402,3507,0,1,0}-{2406,3476,0,1,0}-{2422,3485,0,1,0}-{2382,3506,1,1,0}-{2418,3472,1,1,0}-{2439,3433,0,1,0}-{2441,3449,0,1,0}-{2442,3428,0,1,0}-{2446,3403,0,1,0}-{2450,3416,0,1,0}-{2468,3441,0,1,0}-{2480,3408,0,1,0}-{2480,3406,1,1,0}-{2486,3400,1,1,0}-{2448,3489,0,1,0}-{2450,3488,0,1,0}-{2463,3508,0,1,0}-{2473,3489,0,1,0}-{2474,3457,0,1,0}-{2479,3503,0,1,0}-{2486,3467,0,1,0}-{2437,3463,1,1,0}-{2448,3489,1,1,0}-{2482,3508,1,1,0}-"
}, },
{ {
"npc_id": "170", "npc_id": "170",
@ -1357,11 +1357,11 @@
}, },
{ {
"npc_id": "479", "npc_id": "479",
"loc_data": "{1970,5522,3,1,0}-{2384,3481,0,1,0}-{2388,3473,0,1,0}-{2418,3474,3,1,0}-{2415,3433,3,1,0}-{2466,3500,2,1,0}-" "loc_data": "{2415,3433,3,1,0}-{2384,3481,0,1,0}-{2388,3473,0,1,0}-{2418,3474,3,1,0}-{2466,3500,2,1,0}-{1970,5522,3,1,0}-"
}, },
{ {
"npc_id": "480", "npc_id": "480",
"loc_data": "{1964,5522,3,1,0}-{2458,3417,1,1,0}-{2460,3417,1,1,0}-{2409,3507,0,1,0}-{2412,3474,3,1,0}-{2463,3504,2,1,0}-" "loc_data": "{2409,3507,0,1,0}-{2412,3474,3,1,0}-{2458,3417,1,1,0}-{2460,3417,1,1,0}-{2463,3504,2,1,0}-{1964,5522,3,1,0}-"
}, },
{ {
"npc_id": "481", "npc_id": "481",
@ -1387,6 +1387,10 @@
"npc_id": "490", "npc_id": "490",
"loc_data": "{1887,5026,0,0,6}-" "loc_data": "{1887,5026,0,0,6}-"
}, },
{
"npc_id": "492",
"loc_data": "{2464,3227,0,1,0}-"
},
{ {
"npc_id": "494", "npc_id": "494",
"loc_data": "{2615,3094,0,0,3}-{2615,3092,0,0,3}-{2615,3092,0,0,3}-{2615,3094,0,0,3}-{3122,3125,0,0,6}-{3120,3125,0,0,6}-{3090,3242,0,0,4}-{3090,3245,0,0,4}-{3090,3243,0,0,4}-{2618,3330,0,0,0}-{2619,3330,0,0,0}-{2584,3422,0,0,4}-{2584,3419,0,0,4}-{2584,3418,0,0,4}-{2657,3283,0,0,3}-{2657,3286,0,0,3}-{2807,3443,0,0,6}-{2810,3443,0,0,6}-" "loc_data": "{2615,3094,0,0,3}-{2615,3092,0,0,3}-{2615,3092,0,0,3}-{2615,3094,0,0,3}-{3122,3125,0,0,6}-{3120,3125,0,0,6}-{3090,3242,0,0,4}-{3090,3245,0,0,4}-{3090,3243,0,0,4}-{2618,3330,0,0,0}-{2619,3330,0,0,0}-{2584,3422,0,0,4}-{2584,3419,0,0,4}-{2584,3418,0,0,4}-{2657,3283,0,0,3}-{2657,3286,0,0,3}-{2807,3443,0,0,6}-{2810,3443,0,0,6}-"
@ -2351,14 +2355,46 @@
"npc_id": "805", "npc_id": "805",
"loc_data": "{2936,3288,0,1,4}-" "loc_data": "{2936,3288,0,1,4}-"
}, },
{
"npc_id": "806",
"loc_data": "{2745,3576,1,0,4}-"
},
{
"npc_id": "807",
"loc_data": "{2750,3576,0,0,4}-"
},
{
"npc_id": "808",
"loc_data": "{2736,3575,0,1,1}-"
},
{
"npc_id": "809",
"loc_data": "{2734,3581,0,1,1}-"
},
{
"npc_id": "810",
"loc_data": "{2736,3576,1,1,1}-"
},
{
"npc_id": "811",
"loc_data": "{2731,3579,0,1,4}-"
},
{ {
"npc_id": "812", "npc_id": "812",
"loc_data": "{2738,3473,0,0,1}-{2733,3473,0,0,1}-" "loc_data": "{2741,3562,0,1,0}-"
},
{
"npc_id": "813",
"loc_data": "{2741,3552,0,1,1}-"
}, },
{ {
"npc_id": "820", "npc_id": "820",
"loc_data": "{2697,3496,0,0,0}-" "loc_data": "{2697,3496,0,0,0}-"
}, },
{
"npc_id": "821",
"loc_data": "{2750,3580,0,1,0}-"
},
{ {
"npc_id": "822", "npc_id": "822",
"loc_data": "{3302,9466,0,1,6}-" "loc_data": "{3302,9466,0,1,6}-"
@ -2401,11 +2437,11 @@
}, },
{ {
"npc_id": "839", "npc_id": "839",
"loc_data": "{3265,3066,0,1,0}-{3267,3066,0,1,0}-{3310,3068,0,1,0}-{3322,3011,0,1,0}-{3322,3052,0,1,0}-{3324,3030,0,1,0}-{3150,3044,0,1,0}-{3172,3009,0,1,0}-{3197,3012,0,1,0}-{3198,3040,0,1,0}-{3217,3092,0,1,0}-{3235,3074,0,1,0}-{3252,3125,0,1,0}-{3258,3078,0,1,0}-{3237,2968,0,1,0}-{3224,3013,0,1,0}-{3225,3034,0,1,0}-{3226,3060,0,1,0}-{3250,3057,0,1,0}-{3283,3108,0,1,0}-{3323,3094,0,1,0}-" "loc_data": "{3150,3044,0,1,0}-{3172,3009,0,1,0}-{3197,3012,0,1,0}-{3198,3040,0,1,0}-{3237,2968,0,1,0}-{3224,3013,0,1,0}-{3225,3034,0,1,0}-{3226,3060,0,1,0}-{3250,3057,0,1,0}-{3217,3092,0,1,0}-{3235,3074,0,1,0}-{3252,3125,0,1,0}-{3258,3078,0,1,0}-{3265,3066,0,1,0}-{3267,3066,0,1,0}-{3310,3068,0,1,0}-{3322,3011,0,1,0}-{3322,3052,0,1,0}-{3324,3030,0,1,0}-{3283,3108,0,1,0}-{3323,3094,0,1,0}-"
}, },
{ {
"npc_id": "840", "npc_id": "840",
"loc_data": "{3268,3052,0,1,0}-{3281,3056,0,1,0}-{3307,3055,0,1,0}-{3318,3020,0,1,0}-{3318,3040,0,1,0}-{3190,3054,0,1,0}-{3192,3016,0,1,0}-{3217,3111,0,1,0}-{3222,3086,0,1,0}-{3238,3101,0,1,0}-{3244,3080,0,1,0}-{3253,3116,0,1,0}-{3255,3095,0,1,0}-{3237,3000,0,1,0}-{3245,2960,0,1,0}-{3208,3032,0,1,0}-{3217,3064,0,1,0}-{3238,3015,0,1,0}-{3258,3063,0,1,0}-{3267,3077,0,1,0}-{3269,3110,0,1,0}-{3275,3094,0,1,0}-{3291,3078,0,1,0}-{3291,3100,0,1,0}-{3305,3089,0,1,0}-{3318,3078,0,1,0}-{3321,3104,0,1,0}-" "loc_data": "{3190,3054,0,1,0}-{3192,3016,0,1,0}-{3237,3000,0,1,0}-{3245,2960,0,1,0}-{3208,3032,0,1,0}-{3217,3064,0,1,0}-{3238,3015,0,1,0}-{3258,3063,0,1,0}-{3217,3111,0,1,0}-{3222,3086,0,1,0}-{3238,3101,0,1,0}-{3244,3080,0,1,0}-{3253,3116,0,1,0}-{3255,3095,0,1,0}-{3268,3052,0,1,0}-{3281,3056,0,1,0}-{3307,3055,0,1,0}-{3318,3020,0,1,0}-{3318,3040,0,1,0}-{3267,3077,0,1,0}-{3269,3110,0,1,0}-{3275,3094,0,1,0}-{3291,3078,0,1,0}-{3291,3100,0,1,0}-{3305,3089,0,1,0}-{3318,3078,0,1,0}-{3321,3104,0,1,0}-"
}, },
{ {
"npc_id": "841", "npc_id": "841",
@ -2749,7 +2785,7 @@
}, },
{ {
"npc_id": "1019", "npc_id": "1019",
"loc_data": "{3187,5555,0,1,4}-{3190,5563,0,1,1}-{3193,5555,0,1,3} -{3213,9377,0,1,3}-{3209,9397,0,1,4}-{3245,9401,0,1,6}- {3237,9402,0,1,2}-{3207,9349,0,1,3}-{3220,9347,0,1,6} -{3233,9359,0,1,4}-{3235,9354,0,0,6}-{3259,9370,0,1,1}- {3258,9387,0,1,6}-{2707,9880,0,1,0}-{2711,9876,0,1,0}- {2712,9871,0,1,0}-{2715,9874,0,1,0}-{2720,9871,0,1,0} -{2717,9880,0,1,0}-{2722,9879,0,1,0}-{2723,9875,0,1,0}- {3278,9368,0,1,5}-{3271,9359,0,1,3}-{3287,9359,0,1,5}- {3301,9394,0,1,5}-{3318,9352,0,1,5}-" "loc_data": "{3187,5555,0,1,4}-{3190,5563,0,1,1}-{3193,5555,0,1,3}-{3213,9377,0,1,3}-{3209,9397,0,1,4}-{3245,9401,0,1,6}-{3237,9402,0,1,2}-{3207,9349,0,1,3}-{3220,9347,0,1,6}-{3233,9359,0,1,4}-{3235,9354,0,0,6}-{3259,9370,0,1,1}-{3258,9387,0,1,6}-{2707,9880,0,1,0}-{2711,9876,0,1,0}-{2712,9871,0,1,0}-{2715,9874,0,1,0}-{2720,9871,0,1,0}-{2717,9880,0,1,0}-{2722,9879,0,1,0}-{2723,9875,0,1,0}-{3278,9368,0,1,5}-{3271,9359,0,1,3}-{3287,9359,0,1,5}-{3301,9394,0,1,5}-{3318,9352,0,1,5}-"
}, },
{ {
"npc_id": "1020", "npc_id": "1020",
@ -2797,7 +2833,7 @@
}, },
{ {
"npc_id": "1043", "npc_id": "1043",
"loc_data": "{3726,3381,0,0,0}-{3745,3359,0,0,0}-{3749,3365,0,0,0}-{3750,3354,0,0,0}-{3757,3363,0,0,0}-{3763,3337,0,0,0}-{3459,3457,0,0,0}-{3460,3462,0,0,0}-{3462,3459,0,0,0}-{3463,3490,0,0,0}-{3464,3511,0,0,0}-{3465,3466,0,0,0}-{3466,3495,0,0,0}-{3466,3497,0,0,0}-{3467,3485,0,0,0}-{3467,3497,0,0,0}-{3467,3509,0,0,0}-{3469,3470,0,0,0}-{3470,3469,0,0,0}-{3471,3477,0,0,0}-{3474,3505,0,0,0}-{3476,3507,0,0,0}-{3479,3511,0,0,0}-{3480,3468,0,0,0}-{3480,3470,0,0,0}-{3482,3469,0,0,0}-{3483,3511,0,0,0}-{3484,3464,0,0,0}-{3485,3509,0,0,0}-{3490,3461,0,0,0}-{3491,3460,0,0,0}-{3494,3461,0,0,0}-{3494,3512,0,0,0}-{3498,3461,0,0,0}-{3499,3513,0,0,0}-{3501,3513,0,0,0}-{3502,3464,0,0,0}-{3504,3463,0,0,0}-{3506,3512,0,0,0}-{3506,3515,0,0,0}-{3507,3515,0,0,0}-{3509,3512,0,0,0}-{3511,3488,0,0,0}-{3513,3467,0,0,0}-{3513,3487,0,0,0}-{3513,3489,0,0,0}-{3513,3503,0,0,0}-{3514,3490,0,0,0}-{3515,3495,0,0,0}-{3515,3499,0,0,0}-{3516,3469,0,0,0}-{3409,3369,0,0,0}-{3420,3349,0,0,0}-{3430,3340,0,0,0}-{3435,3330,0,0,0}-{3435,3359,0,0,0}-{3437,3374,0,0,0}-{3446,3385,0,0,0}-{3447,3388,0,0,0}-{3450,3370,0,0,0}-{3450,3387,0,0,0}-{3451,3336,0,0,0}-{3452,3355,0,0,0}-{3726,3289,0,0,0}-{3732,3291,0,0,0}-{3737,3280,0,0,0}-{3745,3285,0,0,0}-{3418,3420,0,0,0}-{3424,3452,0,0,0}-{3428,3409,0,0,0}-{3433,3416,0,0,0}-{3434,3394,0,0,0}-{3436,3407,0,0,0}-{3438,3414,0,0,0}-{3439,3449,0,0,0}-{3446,3439,0,0,0}-{3454,3410,0,0,0}-{3454,3423,0,0,0}-{2852,4561,0,0,0}-{2853,4566,0,0,0}-{2856,4568,0,0,0}-{2864,4561,0,0,0}-{2864,4563,0,0,0}-" "loc_data": "{2852,4561,0,0,0}-{2853,4566,0,0,0}-{2856,4568,0,0,0}-{2864,4561,0,0,0}-{2864,4563,0,0,0}-{3409,3369,0,0,0}-{3420,3349,0,0,0}-{3430,3340,0,0,0}-{3435,3330,0,0,0}-{3435,3359,0,0,0}-{3437,3374,0,0,0}-{3446,3385,0,0,0}-{3447,3388,0,0,0}-{3450,3370,0,0,0}-{3450,3387,0,0,0}-{3451,3336,0,0,0}-{3452,3355,0,0,0}-{3418,3420,0,0,0}-{3424,3452,0,0,0}-{3428,3409,0,0,0}-{3433,3416,0,0,0}-{3434,3394,0,0,0}-{3436,3407,0,0,0}-{3438,3414,0,0,0}-{3439,3449,0,0,0}-{3446,3439,0,0,0}-{3454,3410,0,0,0}-{3454,3423,0,0,0}-{3726,3289,0,0,0}-{3732,3291,0,0,0}-{3737,3280,0,0,0}-{3745,3285,0,0,0}-{3726,3381,0,0,0}-{3745,3359,0,0,0}-{3749,3365,0,0,0}-{3750,3354,0,0,0}-{3757,3363,0,0,0}-{3763,3337,0,0,0}-{3459,3457,0,0,0}-{3460,3462,0,0,0}-{3462,3459,0,0,0}-{3463,3490,0,0,0}-{3464,3511,0,0,0}-{3465,3466,0,0,0}-{3466,3495,0,0,0}-{3466,3497,0,0,0}-{3467,3485,0,0,0}-{3467,3497,0,0,0}-{3467,3509,0,0,0}-{3469,3470,0,0,0}-{3470,3469,0,0,0}-{3471,3477,0,0,0}-{3474,3505,0,0,0}-{3476,3507,0,0,0}-{3479,3511,0,0,0}-{3480,3468,0,0,0}-{3480,3470,0,0,0}-{3482,3469,0,0,0}-{3483,3511,0,0,0}-{3484,3464,0,0,0}-{3485,3509,0,0,0}-{3490,3461,0,0,0}-{3491,3460,0,0,0}-{3494,3461,0,0,0}-{3494,3512,0,0,0}-{3498,3461,0,0,0}-{3499,3513,0,0,0}-{3501,3513,0,0,0}-{3502,3464,0,0,0}-{3504,3463,0,0,0}-{3506,3512,0,0,0}-{3506,3515,0,0,0}-{3507,3515,0,0,0}-{3509,3512,0,0,0}-{3511,3488,0,0,0}-{3513,3467,0,0,0}-{3513,3487,0,0,0}-{3513,3489,0,0,0}-{3513,3503,0,0,0}-{3514,3490,0,0,0}-{3515,3495,0,0,0}-{3515,3499,0,0,0}-{3516,3469,0,0,0}-"
}, },
{ {
"npc_id": "1044", "npc_id": "1044",
@ -3313,11 +3349,11 @@
}, },
{ {
"npc_id": "1212", "npc_id": "1212",
"loc_data": "{2247,3226,0,0,0}-{2249,3227,0,0,0}-{2249,3258,0,0,0}-{2251,3260,0,0,0}-{2259,3211,0,0,0}-{2267,3223,0,0,0}-{2267,3225,0,0,0}-{2298,3262,0,0,0}-{3202,5990,0,0,0}-{3232,5977,0,0,0}-{3234,5969,0,0,0}-{3237,5995,0,0,0}-{3242,5997,0,0,0}-{3244,5995,0,0,0}-{3245,5995,0,0,0}-{2194,3189,0,0,0}-{2196,3187,0,0,0}-{2196,3189,0,0,0}-{2206,3164,0,0,0}-{2209,3164,0,0,0}-{2216,3142,0,0,0}-{2218,3139,0,0,0}-{2178,3238,0,0,0}-{2208,3225,0,0,0}-{2210,3217,0,0,0}-{2213,3243,0,0,0}-{2218,3245,0,0,0}-{2220,3243,0,0,0}-{2221,3243,0,0,0}-{2695,6170,0,0,0}-{2697,6171,0,0,0}-{2697,6202,0,0,0}-{2699,6204,0,0,0}-{2707,6155,0,0,0}-{2715,6167,0,0,0}-{2715,6169,0,0,0}-{2746,6206,0,0,0}-{2729,6086,0,0,0}-{2731,6080,0,0,0}-{2731,6089,0,0,0}-{2744,6139,0,0,0}-{3271,5978,0,0,0}-{3273,5979,0,0,0}-{3273,6010,0,0,0}-{3275,6012,0,0,0}-{3283,5963,0,0,0}-{3291,5975,0,0,0}-{3291,5977,0,0,0}-{3322,6014,0,0,0}-{2281,3142,0,0,0}-{2283,3136,0,0,0}-{2283,3145,0,0,0}-{2296,3195,0,0,0}-" "loc_data": "{2194,3189,0,0,0}-{2196,3187,0,0,0}-{2196,3189,0,0,0}-{2206,3164,0,0,0}-{2209,3164,0,0,0}-{2216,3142,0,0,0}-{2218,3139,0,0,0}-{2178,3238,0,0,0}-{2208,3225,0,0,0}-{2210,3217,0,0,0}-{2213,3243,0,0,0}-{2218,3245,0,0,0}-{2220,3243,0,0,0}-{2221,3243,0,0,0}-{3202,5990,0,0,0}-{3232,5977,0,0,0}-{3234,5969,0,0,0}-{3237,5995,0,0,0}-{3242,5997,0,0,0}-{3244,5995,0,0,0}-{3245,5995,0,0,0}-{2729,6086,0,0,0}-{2731,6080,0,0,0}-{2731,6089,0,0,0}-{2744,6139,0,0,0}-{2695,6170,0,0,0}-{2697,6171,0,0,0}-{2697,6202,0,0,0}-{2699,6204,0,0,0}-{2707,6155,0,0,0}-{2715,6167,0,0,0}-{2715,6169,0,0,0}-{2746,6206,0,0,0}-{2281,3142,0,0,0}-{2283,3136,0,0,0}-{2283,3145,0,0,0}-{2296,3195,0,0,0}-{2247,3226,0,0,0}-{2249,3227,0,0,0}-{2249,3258,0,0,0}-{2251,3260,0,0,0}-{2259,3211,0,0,0}-{2267,3223,0,0,0}-{2267,3225,0,0,0}-{2298,3262,0,0,0}-{3271,5978,0,0,0}-{3273,5979,0,0,0}-{3273,6010,0,0,0}-{3275,6012,0,0,0}-{3283,5963,0,0,0}-{3291,5975,0,0,0}-{3291,5977,0,0,0}-{3322,6014,0,0,0}-"
}, },
{ {
"npc_id": "1213", "npc_id": "1213",
"loc_data": "{2248,3225,0,0,0}-{2248,3227,0,0,0}-{2251,3257,0,0,0}-{2253,3259,0,0,0}-{2268,3224,0,0,0}-{2291,3262,0,0,0}-{3204,5988,0,0,0}-{3232,5979,0,0,0}-{3234,5967,0,0,0}-{3234,5976,0,0,0}-{3238,5996,0,0,0}-{3239,5997,0,0,0}-{3243,5996,0,0,0}-{2192,3188,0,0,0}-{2192,3191,0,0,0}-{2194,3190,0,0,0}-{2208,3163,0,0,0}-{2209,3163,0,0,0}-{2216,3136,0,0,0}-{2216,3140,0,0,0}-{2180,3236,0,0,0}-{2208,3227,0,0,0}-{2210,3215,0,0,0}-{2210,3224,0,0,0}-{2214,3244,0,0,0}-{2215,3245,0,0,0}-{2219,3244,0,0,0}-{2696,6169,0,0,0}-{2696,6171,0,0,0}-{2699,6201,0,0,0}-{2701,6203,0,0,0}-{2716,6168,0,0,0}-{2739,6206,0,0,0}-{2730,6084,0,0,0}-{3272,5977,0,0,0}-{3272,5979,0,0,0}-{3275,6009,0,0,0}-{3277,6011,0,0,0}-{3292,5976,0,0,0}-{3315,6014,0,0,0}-{2282,3140,0,0,0}-" "loc_data": "{2192,3188,0,0,0}-{2192,3191,0,0,0}-{2194,3190,0,0,0}-{2208,3163,0,0,0}-{2209,3163,0,0,0}-{2216,3136,0,0,0}-{2216,3140,0,0,0}-{2180,3236,0,0,0}-{2208,3227,0,0,0}-{2210,3215,0,0,0}-{2210,3224,0,0,0}-{2214,3244,0,0,0}-{2215,3245,0,0,0}-{2219,3244,0,0,0}-{3204,5988,0,0,0}-{3232,5979,0,0,0}-{3234,5967,0,0,0}-{3234,5976,0,0,0}-{3238,5996,0,0,0}-{3239,5997,0,0,0}-{3243,5996,0,0,0}-{2730,6084,0,0,0}-{2696,6169,0,0,0}-{2696,6171,0,0,0}-{2699,6201,0,0,0}-{2701,6203,0,0,0}-{2716,6168,0,0,0}-{2739,6206,0,0,0}-{2282,3140,0,0,0}-{2248,3225,0,0,0}-{2248,3227,0,0,0}-{2251,3257,0,0,0}-{2253,3259,0,0,0}-{2268,3224,0,0,0}-{2291,3262,0,0,0}-{3272,5977,0,0,0}-{3272,5979,0,0,0}-{3275,6009,0,0,0}-{3277,6011,0,0,0}-{3292,5976,0,0,0}-{3315,6014,0,0,0}-"
}, },
{ {
"npc_id": "1214", "npc_id": "1214",
@ -3739,6 +3775,10 @@
"npc_id": "1427", "npc_id": "1427",
"loc_data": "{2957,3025,0,0,0}-" "loc_data": "{2957,3025,0,0,0}-"
}, },
{
"npc_id": "1433",
"loc_data": "{2770,2789,0,1,6}-"
},
{ {
"npc_id": "1434", "npc_id": "1434",
"loc_data": "{2753,2770,0,1,6}-" "loc_data": "{2753,2770,0,1,6}-"
@ -4025,7 +4065,7 @@
}, },
{ {
"npc_id": "1633", "npc_id": "1633",
"loc_data": "{1837,3244,0,1,0}-{1836,3250,0,1,0}-{1845,3251,0,1,0}-{1845,3247,0,1,0}-{1849,3241,0,1,0}-{1853,3247,0,1,0}-{1848,3254,0,1,0}-{1858,3251,0,1,0}-{1935,3217,0,1,0}-{1933,3209,0,1,0}-{1930,3208,0,1,0}-{1929,3217,0,1,0}-{1927,3219,0,1,0}-{1924,3211,0,1,0}-{1920,3216,0,1,0}-{1925,3213,0,1,0}-{3263,9399,0,1,3}-{3274,9397,0,1,1}-{3275,9393,0,1,6}-{3271,9384,0,1,0}-{3270,9380,0,1,2}-{3283,9378,0,1,6}-{3285,9386,0,1,5}-{3284,9401,0,1,4}-{3278,9353,0,1,1}-{3299,9380,0,1,1}-{3319,9402,0,1,1}-{3305,9350,0,1,4}-{3248,9374,0,1,3}-{3253,9363,0,1,3}-{3249,9355,0,1,3}-{2761,10007,0,1,0}-{2757,10010,0,1,3}-{2763,10000,0,1,5}-{2760,10011,0,1,0}-{2761,9997,0,1,4}-" "loc_data": "{1837,3244,0,1,0}-{1836,3250,0,1,0}-{1845,3251,0,1,0}-{1845,3247,0,1,0}-{1849,3241,0,1,0}-{1853,3247,0,1,0}-{1848,3254,0,1,0}-{1858,3251,0,1,0}-{1935,3217,0,1,0}-{1933,3209,0,1,0}-{1930,3208,0,1,0}-{1929,3217,0,1,0}-{1927,3219,0,1,0}-{1924,3211,0,1,0}-{1920,3216,0,1,0}-{1925,3213,0,1,0}-{3263,9399,0,1,3}-{3248,9374,0,1,3}-{3253,9363,0,1,3}-{3249,9355,0,1,3}-{3274,9397,0,1,1}-{3275,9393,0,1,6}-{3271,9384,0,1,0}-{3270,9380,0,1,2}-{3283,9378,0,1,6}-{3285,9386,0,1,5}-{3284,9401,0,1,4}-{3278,9353,0,1,1}-{3299,9380,0,1,1}-{3319,9402,0,1,1}-{3305,9350,0,1,4}-{2761,10007,0,1,0}-{2757,10010,0,1,3}-{2763,10000,0,1,5}-{2760,10011,0,1,0}-{2761,9997,0,1,4}-"
}, },
{ {
"npc_id": "1634", "npc_id": "1634",
@ -4225,7 +4265,7 @@
}, },
{ {
"npc_id": "1752", "npc_id": "1752",
"loc_data": "{2437,3442,0,1,0}-{2449,3421,0,1,0}-{2457,3394,0,1,0}-{2464,3394,0,1,0}-{2480,3406,0,1,0}-{2432,3387,0,1,0}-{2442,3388,0,1,0}-{2453,3363,0,1,0}-{2463,3375,0,1,0}-{2381,3428,0,1,0}-{2392,3405,0,1,0}-{2413,3397,0,1,0}-{2415,3408,0,1,0}-{2463,3456,0,1,0}-{2468,3456,0,1,0}-" "loc_data": "{2381,3428,0,1,0}-{2392,3405,0,1,0}-{2413,3397,0,1,0}-{2415,3408,0,1,0}-{2432,3387,0,1,0}-{2442,3388,0,1,0}-{2453,3363,0,1,0}-{2463,3375,0,1,0}-{2437,3442,0,1,0}-{2449,3421,0,1,0}-{2457,3394,0,1,0}-{2464,3394,0,1,0}-{2480,3406,0,1,0}-{2463,3456,0,1,0}-{2468,3456,0,1,0}-"
}, },
{ {
"npc_id": "1754", "npc_id": "1754",
@ -4509,7 +4549,7 @@
}, },
{ {
"npc_id": "1874", "npc_id": "1874",
"loc_data": "{3371,9301,0,1,0}-{3371,9303,0,1,0}-{3371,9305,0,1,0}-{3371,9307,0,1,0}-{3371,9309,0,1,0}-{3373,9301,0,1,0}-{3373,9303,0,1,0}-{3373,9306,0,1,0}-{3373,9308,0,1,0}-{3375,9301,0,1,0}-{3375,9303,0,1,0}-{3375,9305,0,1,0}-{3375,9307,0,1,0}-{3375,9309,0,1,0}-{3403,2963,0,1,0}-{3429,2976,0,1,0}-{3328,2952,0,1,0}-{3328,2957,0,1,0}-{3331,2955,0,1,0}-{3331,2961,0,1,0}-{3266,2955,0,1,0}-{3271,2967,0,1,0}-{3279,2957,0,1,0}-{3280,2975,0,1,0}-{3284,2959,0,1,0}-{3294,2964,0,1,0}-{3295,2978,0,1,0}-{3305,2966,0,1,0}-{3307,2959,0,1,0}-{3309,2973,0,1,0}-{3396,3029,0,1,0}-{3397,3044,0,1,0}-{3398,3038,0,1,0}-" "loc_data": "{3328,2952,0,1,0}-{3328,2957,0,1,0}-{3331,2955,0,1,0}-{3331,2961,0,1,0}-{3371,9301,0,1,0}-{3371,9303,0,1,0}-{3371,9305,0,1,0}-{3371,9307,0,1,0}-{3371,9309,0,1,0}-{3373,9301,0,1,0}-{3373,9303,0,1,0}-{3373,9306,0,1,0}-{3373,9308,0,1,0}-{3375,9301,0,1,0}-{3375,9303,0,1,0}-{3375,9305,0,1,0}-{3375,9307,0,1,0}-{3375,9309,0,1,0}-{3403,2963,0,1,0}-{3429,2976,0,1,0}-{3396,3029,0,1,0}-{3397,3044,0,1,0}-{3398,3038,0,1,0}-{3266,2955,0,1,0}-{3271,2967,0,1,0}-{3279,2957,0,1,0}-{3280,2975,0,1,0}-{3284,2959,0,1,0}-{3294,2964,0,1,0}-{3295,2978,0,1,0}-{3305,2966,0,1,0}-{3307,2959,0,1,0}-{3309,2973,0,1,0}-"
}, },
{ {
"npc_id": "1875", "npc_id": "1875",
@ -4669,19 +4709,19 @@
}, },
{ {
"npc_id": "1961", "npc_id": "1961",
"loc_data": "{3156,5477,0,1,5}-{3162,5479,0,1,4}-{3159,5477,0,1,6}-{3150,5474,0,1,3}-{3147,5480,0,1,1}-{3159,5484,0,1,3}-{2764,4944,1,1,0}-{2796,4976,1,1,0}-{2798,4950,1,1,0}-{2806,4939,1,1,0}-{2832,4959,2,1,0}-{3201,9293,0,1,0}-{3205,9303,0,1,0}-{3206,9328,0,1,0}-{3207,9310,0,1,0}-{3211,9284,0,1,0}-{3220,9289,0,1,0}-{3224,9334,0,1,0}-{3249,9286,0,1,0}-{3251,9303,0,1,0}-{3252,9327,0,1,0}-{3252,9332,0,1,0}-{3255,9315,0,1,0}-{3261,9296,0,1,0}-{3261,9306,0,1,0}-" "loc_data": "{2832,4959,2,1,0}-{3156,5477,0,1,5}-{3162,5479,0,1,4}-{3159,5477,0,1,6}-{3150,5474,0,1,3}-{3147,5480,0,1,1}-{3159,5484,0,1,3}-{3201,9293,0,1,0}-{3205,9303,0,1,0}-{3206,9328,0,1,0}-{3207,9310,0,1,0}-{3211,9284,0,1,0}-{3220,9289,0,1,0}-{3224,9334,0,1,0}-{3249,9286,0,1,0}-{3251,9303,0,1,0}-{3252,9327,0,1,0}-{3252,9332,0,1,0}-{3255,9315,0,1,0}-{3261,9296,0,1,0}-{3261,9306,0,1,0}-{2764,4944,1,1,0}-{2796,4976,1,1,0}-{2798,4950,1,1,0}-{2806,4939,1,1,0}-"
}, },
{ {
"npc_id": "1962", "npc_id": "1962",
"loc_data": "{3168,5458,0,1,2}-{2900,4948,3,1,0}-{2762,4962,1,1,0}-{2763,4973,1,1,0}-{2780,4977,1,1,0}-{2787,4967,1,1,0}-{2796,4959,1,1,0}-{2838,4948,2,1,0}-{3205,9329,0,1,0}-{3210,9292,0,1,0}-{3221,9310,0,1,0}-{3225,9323,0,1,0}-{3243,9310,0,1,0}-{3246,9290,0,1,0}-{3255,9301,0,1,0}-{3255,9321,0,1,0}-{3261,9331,0,1,0}-" "loc_data": "{2838,4948,2,1,0}-{2900,4948,3,1,0}-{3168,5458,0,1,2}-{3205,9329,0,1,0}-{3210,9292,0,1,0}-{3221,9310,0,1,0}-{3225,9323,0,1,0}-{3243,9310,0,1,0}-{3246,9290,0,1,0}-{3255,9301,0,1,0}-{3255,9321,0,1,0}-{3261,9331,0,1,0}-{2762,4962,1,1,0}-{2763,4973,1,1,0}-{2780,4977,1,1,0}-{2787,4967,1,1,0}-{2796,4959,1,1,0}-"
}, },
{ {
"npc_id": "1963", "npc_id": "1963",
"loc_data": "{3166,5465,0,1,7}-{3168,5462,0,1,0}-{3167,5467,0,1,1}-{3167,5467,0,1,7}-{2926,4965,3,1,0}-{2771,4947,1,1,0}-{2775,4963,1,1,0}-{2781,4948,1,1,0}-{2792,4942,1,1,0}-{2798,4954,1,1,0}-{2858,4964,2,1,0}-{3204,9309,0,1,0}-{3214,9333,0,1,0}-{3219,9297,0,1,0}-{3239,9300,0,1,0}-{3240,9286,0,1,0}-{3240,9330,0,1,0}-{3245,9306,0,1,0}-{3250,9316,0,1,0}-{3250,9317,0,1,0}-{3257,9290,0,1,0}-" "loc_data": "{2858,4964,2,1,0}-{2926,4965,3,1,0}-{3166,5465,0,1,7}-{3168,5462,0,1,0}-{3167,5467,0,1,1}-{3167,5467,0,1,7}-{3204,9309,0,1,0}-{3214,9333,0,1,0}-{3219,9297,0,1,0}-{3239,9300,0,1,0}-{3240,9286,0,1,0}-{3240,9330,0,1,0}-{3245,9306,0,1,0}-{3250,9316,0,1,0}-{3250,9317,0,1,0}-{3257,9290,0,1,0}-{2771,4947,1,1,0}-{2775,4963,1,1,0}-{2781,4948,1,1,0}-{2792,4942,1,1,0}-{2798,4954,1,1,0}-"
}, },
{ {
"npc_id": "1964", "npc_id": "1964",
"loc_data": "{2761,4950,1,1,0}-{2765,4938,1,1,0}-{2770,4955,1,1,0}-{2772,4940,1,1,0}-{2777,4943,1,1,0}-{2782,4967,1,1,0}-{2797,4965,1,1,0}-{2799,4937,1,1,0}-{2799,4941,1,1,0}-{2807,4968,1,1,0}-{2808,4975,1,1,0}-{2809,4953,1,1,0}-{2864,4946,2,1,0}-{3202,9283,0,1,0}-{3206,9333,0,1,0}-{3209,9299,0,1,0}-{3219,9301,0,1,0}-{3226,9285,0,1,0}-{3227,9303,0,1,0}-{3228,9293,0,1,0}-{3229,9333,0,1,0}-{3237,9293,0,1,0}-{3246,9321,0,1,0}-{3256,9296,0,1,0}-{3260,9285,0,1,0}-{3262,9317,0,1,0}-" "loc_data": "{2864,4946,2,1,0}-{3202,9283,0,1,0}-{3206,9333,0,1,0}-{3209,9299,0,1,0}-{3219,9301,0,1,0}-{3226,9285,0,1,0}-{3227,9303,0,1,0}-{3228,9293,0,1,0}-{3229,9333,0,1,0}-{3237,9293,0,1,0}-{3246,9321,0,1,0}-{3256,9296,0,1,0}-{3260,9285,0,1,0}-{3262,9317,0,1,0}-{2761,4950,1,1,0}-{2765,4938,1,1,0}-{2770,4955,1,1,0}-{2772,4940,1,1,0}-{2777,4943,1,1,0}-{2782,4967,1,1,0}-{2797,4965,1,1,0}-{2799,4937,1,1,0}-{2799,4941,1,1,0}-{2807,4968,1,1,0}-{2808,4975,1,1,0}-{2809,4953,1,1,0}-"
}, },
{ {
"npc_id": "1970", "npc_id": "1970",
@ -4693,7 +4733,7 @@
}, },
{ {
"npc_id": "1973", "npc_id": "1973",
"loc_data": "{2693,5075,0,1,0}-{2695,5089,0,1,0}-{2697,5096,0,1,0}-{2703,5064,0,1,0}-{2710,5105,0,1,0}-{2719,5078,0,1,0}-{2719,5112,0,1,0}-{2720,5096,0,1,0}-{2726,5086,0,1,0}-{2729,5096,0,1,0}-{2735,5061,0,1,0}-{2740,5069,0,1,0}-{2740,5085,0,1,0}-{2746,5092,0,1,0}-{2746,5114,0,1,0}-{2626,5065,0,1,0}-{2637,5099,0,1,0}-{2638,5058,0,1,0}-{2644,5090,0,1,0}-{2658,5082,0,1,0}-{2666,5097,0,1,0}-{2680,5074,0,1,0}-" "loc_data": "{2626,5065,0,1,0}-{2637,5099,0,1,0}-{2638,5058,0,1,0}-{2644,5090,0,1,0}-{2658,5082,0,1,0}-{2666,5097,0,1,0}-{2680,5074,0,1,0}-{2693,5075,0,1,0}-{2695,5089,0,1,0}-{2697,5096,0,1,0}-{2703,5064,0,1,0}-{2710,5105,0,1,0}-{2719,5078,0,1,0}-{2719,5112,0,1,0}-{2720,5096,0,1,0}-{2726,5086,0,1,0}-{2729,5096,0,1,0}-{2735,5061,0,1,0}-{2740,5069,0,1,0}-{2740,5085,0,1,0}-{2746,5092,0,1,0}-{2746,5114,0,1,0}-"
}, },
{ {
"npc_id": "1976", "npc_id": "1976",
@ -4705,11 +4745,11 @@
}, },
{ {
"npc_id": "1993", "npc_id": "1993",
"loc_data": "{3264,2886,0,1,0}-{3267,2891,0,1,0}-{3268,2881,0,1,0}-{3269,2885,0,1,0}-{3296,2912,0,1,0}-{3297,2919,0,1,0}-{3301,2920,0,1,0}-{3308,2916,0,1,0}-{3258,2868,0,1,0}-{3259,2823,0,1,0}-{3259,2845,0,1,0}-{3260,2830,0,1,0}-{3260,2859,0,1,0}-{3261,2819,0,1,0}-{3261,2851,0,1,0}-{3337,2922,0,1,0}-{3343,2931,0,1,0}-{3349,2922,0,1,0}-{3351,2927,0,1,0}-{3357,2922,0,1,0}-{3359,2927,0,1,0}-{3364,2937,0,1,0}-{3268,2854,0,1,0}-{3269,2827,0,1,0}-{3269,2866,0,1,0}-{3269,2875,0,1,0}-{3270,2818,0,1,0}-{3272,2841,0,1,0}-{3276,2842,0,1,0}-{3282,2839,0,1,0}-{3290,2847,0,1,0}-" "loc_data": "{3337,2922,0,1,0}-{3343,2931,0,1,0}-{3349,2922,0,1,0}-{3351,2927,0,1,0}-{3357,2922,0,1,0}-{3359,2927,0,1,0}-{3364,2937,0,1,0}-{3258,2868,0,1,0}-{3259,2823,0,1,0}-{3259,2845,0,1,0}-{3260,2830,0,1,0}-{3260,2859,0,1,0}-{3261,2819,0,1,0}-{3261,2851,0,1,0}-{3268,2854,0,1,0}-{3269,2827,0,1,0}-{3269,2866,0,1,0}-{3269,2875,0,1,0}-{3270,2818,0,1,0}-{3272,2841,0,1,0}-{3276,2842,0,1,0}-{3282,2839,0,1,0}-{3290,2847,0,1,0}-{3264,2886,0,1,0}-{3267,2891,0,1,0}-{3268,2881,0,1,0}-{3269,2885,0,1,0}-{3296,2912,0,1,0}-{3297,2919,0,1,0}-{3301,2920,0,1,0}-{3308,2916,0,1,0}-"
}, },
{ {
"npc_id": "1994", "npc_id": "1994",
"loc_data": "{3265,2931,0,1,0}-{3265,2935,0,1,0}-{3268,2932,0,1,0}-{3268,2935,0,1,0}-{3316,2900,0,1,0}-{3319,2897,0,1,0}-{3320,2901,0,1,0}-{3321,2899,0,1,0}-{3212,2863,0,1,0}-{3213,2866,0,1,0}-{3215,2863,0,1,0}-{3216,2865,0,1,0}-{3216,2868,0,1,0}-{3218,2831,0,1,0}-{3220,2830,0,1,0}-{3220,2833,0,1,0}-{3221,2831,0,1,0}-{3238,2845,0,1,0}-{3240,2845,0,1,0}-{3241,2843,0,1,0}-{3241,2847,0,1,0}-{3400,2997,0,1,0}-{3402,2999,0,1,0}-{3403,2997,0,1,0}-{3445,2993,0,1,0}-{3446,2992,0,1,0}-{3448,2991,0,1,0}-{3448,2994,0,1,0}-{3329,2933,0,1,0}-{3330,2931,0,1,0}-{3331,2933,0,1,0}-{3343,2895,0,1,0}-{3345,2896,0,1,0}-{3346,2894,0,1,0}-{3348,2894,0,1,0}-{3376,2934,0,1,0}-{3378,2933,0,1,0}-{3378,2935,0,1,0}-{3381,2907,0,1,0}-{3383,2905,0,1,0}-{3383,2908,0,1,0}-{3384,2907,0,1,0}-{3306,2817,0,1,0}-{3308,2818,0,1,0}-{3309,2816,0,1,0}-{3312,2817,0,1,0}-{3314,2861,0,1,0}-{3319,2873,0,1,0}-{3321,2871,0,1,0}-{3324,2870,0,1,0}-{3327,2858,0,1,0}-{3406,3014,0,1,0}-{3408,3013,0,1,0}-{3408,3016,0,1,0}-{3410,3015,0,1,0}-" "loc_data": "{3329,2933,0,1,0}-{3330,2931,0,1,0}-{3331,2933,0,1,0}-{3343,2895,0,1,0}-{3345,2896,0,1,0}-{3346,2894,0,1,0}-{3348,2894,0,1,0}-{3376,2934,0,1,0}-{3378,2933,0,1,0}-{3378,2935,0,1,0}-{3381,2907,0,1,0}-{3383,2905,0,1,0}-{3383,2908,0,1,0}-{3384,2907,0,1,0}-{3400,2997,0,1,0}-{3402,2999,0,1,0}-{3403,2997,0,1,0}-{3445,2993,0,1,0}-{3446,2992,0,1,0}-{3448,2991,0,1,0}-{3448,2994,0,1,0}-{3406,3014,0,1,0}-{3408,3013,0,1,0}-{3408,3016,0,1,0}-{3410,3015,0,1,0}-{3212,2863,0,1,0}-{3213,2866,0,1,0}-{3215,2863,0,1,0}-{3216,2865,0,1,0}-{3216,2868,0,1,0}-{3218,2831,0,1,0}-{3220,2830,0,1,0}-{3220,2833,0,1,0}-{3221,2831,0,1,0}-{3238,2845,0,1,0}-{3240,2845,0,1,0}-{3241,2843,0,1,0}-{3241,2847,0,1,0}-{3306,2817,0,1,0}-{3308,2818,0,1,0}-{3309,2816,0,1,0}-{3312,2817,0,1,0}-{3314,2861,0,1,0}-{3319,2873,0,1,0}-{3321,2871,0,1,0}-{3324,2870,0,1,0}-{3327,2858,0,1,0}-{3265,2931,0,1,0}-{3265,2935,0,1,0}-{3268,2932,0,1,0}-{3268,2935,0,1,0}-{3316,2900,0,1,0}-{3319,2897,0,1,0}-{3320,2901,0,1,0}-{3321,2899,0,1,0}-"
}, },
{ {
"npc_id": "1995", "npc_id": "1995",
@ -4861,7 +4901,11 @@
}, },
{ {
"npc_id": "2057", "npc_id": "2057",
"loc_data": "{2442,9436,2,1,0}-{2458,9413,2,1,0}-{2470,9435,2,1,0}-{2472,9460,2,1,0}-{2483,9413,2,1,0}-{2485,9447,2,1,0}-{2480,3046,0,1,0}-{2453,9393,2,1,0}-{2461,9403,2,1,0}-{2464,9380,2,1,0}-" "loc_data": "{2480,3046,0,1,0}-{2453,9393,2,1,0}-{2461,9403,2,1,0}-{2464,9380,2,1,0}-{2442,9436,2,1,0}-{2458,9413,2,1,0}-{2470,9435,2,1,0}-{2472,9460,2,1,0}-{2483,9413,2,1,0}-{2485,9447,2,1,0}-"
},
{
"npc_id": "2058",
"loc_data": "{3161,9547,0,0,7}-{3164,9556,0,0,7}-{3162,9574,0,0,7}-{3198,9554,0,0,7}-{3198,9572,0,0,7}-{3215,9560,0,0,7}-{3216,9588,0,0,7}-"
}, },
{ {
"npc_id": "2059", "npc_id": "2059",
@ -6277,7 +6321,7 @@
}, },
{ {
"npc_id": "2803", "npc_id": "2803",
"loc_data": "{3387,3068,0,1,0}-{3387,3017,0,1,0}-{3404,3062,0,1,0}-{3441,3061,0,1,0}-{3445,3034,0,1,0}-{3338,2804,0,1,0}-{3339,2815,0,1,0}-{3342,2809,0,1,0}-{3344,2800,0,1,0}-{3348,2809,0,1,0}-{3349,2814,0,1,0}-{3357,2813,0,1,0}-{3357,2806,0,1,0}-{3365,2815,0,1,0}-" "loc_data": "{3338,2804,0,1,0}-{3339,2815,0,1,0}-{3342,2809,0,1,0}-{3344,2800,0,1,0}-{3348,2809,0,1,0}-{3349,2814,0,1,0}-{3357,2813,0,1,0}-{3357,2806,0,1,0}-{3365,2815,0,1,0}-{3387,3068,0,1,0}-{3387,3017,0,1,0}-{3404,3062,0,1,0}-{3441,3061,0,1,0}-{3445,3034,0,1,0}-"
}, },
{ {
"npc_id": "2804", "npc_id": "2804",
@ -6727,6 +6771,10 @@
"npc_id": "3205", "npc_id": "3205",
"loc_data": "{3139,3448,0,1,3}-" "loc_data": "{3139,3448,0,1,3}-"
}, },
{
"npc_id": "3207",
"loc_data": "{1970,5002,0,1,4}-"
},
{ {
"npc_id": "3213", "npc_id": "3213",
"loc_data": "{2568,3334,0,1,0}-" "loc_data": "{2568,3334,0,1,0}-"
@ -6987,6 +7035,10 @@
"npc_id": "3288", "npc_id": "3288",
"loc_data": "{2987,3446,0,1,7}-{3034,3437,0,1,0}-" "loc_data": "{2987,3446,0,1,7}-{3034,3437,0,1,0}-"
}, },
{
"npc_id": "3293",
"loc_data": "{3113,3369,1,0,0}-{3122,3353,0,0,3}-{3124,3360,0,0,2}-{3115,3362,0,0,1}-"
},
{ {
"npc_id": "3294", "npc_id": "3294",
"loc_data": "{3014,3339,0,1,2}-" "loc_data": "{3014,3339,0,1,2}-"
@ -7189,7 +7241,7 @@
}, },
{ {
"npc_id": "3675", "npc_id": "3675",
"loc_data": "{3333,2864,0,1,1}-{3335,2860,0,1,2}-{3338,2864,0,1,4}-{3215,2841,0,1,0}-{3217,2845,0,1,0}-{3220,2841,0,1,0}-{3295,2866,0,1,0}-{3297,2863,0,1,0}-{3301,2864,0,1,0}-{3336,2778,0,1,0}-{3343,2793,0,1,0}-{3367,2791,0,1,0}-" "loc_data": "{3336,2778,0,1,0}-{3343,2793,0,1,0}-{3367,2791,0,1,0}-{3333,2864,0,1,1}-{3335,2860,0,1,2}-{3338,2864,0,1,4}-{3215,2841,0,1,0}-{3217,2845,0,1,0}-{3220,2841,0,1,0}-{3295,2866,0,1,0}-{3297,2863,0,1,0}-{3301,2864,0,1,0}-"
}, },
{ {
"npc_id": "3677", "npc_id": "3677",
@ -8197,19 +8249,19 @@
}, },
{ {
"npc_id": "4690", "npc_id": "4690",
"loc_data": "{2372,3401,0,1,0}-{3104,3875,0,1,2}-{2912,9731,0,1,0}-{3256,3624,0,1,5}-{3308,3661,0,1,2}-" "loc_data": "{3104,3875,0,1,2}-{2372,3401,0,1,0}-{2912,9731,0,1,0}-{3256,3624,0,1,5}-{3308,3661,0,1,2}-"
}, },
{ {
"npc_id": "4691", "npc_id": "4691",
"loc_data": "{2371,3398,0,1,0}-{3110,3854,0,1,0}-" "loc_data": "{3110,3854,0,1,0}-{2371,3398,0,1,0}-"
}, },
{ {
"npc_id": "4692", "npc_id": "4692",
"loc_data": "{2372,3395,0,1,0}-{3116,3858,0,1,0}-" "loc_data": "{3116,3858,0,1,0}-{2372,3395,0,1,0}-"
}, },
{ {
"npc_id": "4693", "npc_id": "4693",
"loc_data": "{2369,3394,0,1,0}-{3094,3849,0,1,0}-{2912,9741,0,1,0}-{2906,9736,0,1,0}-" "loc_data": "{3094,3849,0,1,0}-{2369,3394,0,1,0}-{2912,9741,0,1,0}-{2906,9736,0,1,0}-"
}, },
{ {
"npc_id": "4694", "npc_id": "4694",
@ -8961,7 +9013,7 @@
}, },
{ {
"npc_id": "5359", "npc_id": "5359",
"loc_data": "{2693,5065,0,1,0}-{2693,5089,0,1,0}-{2704,5091,0,1,0}-{2710,5095,0,1,0}-{2712,5076,0,1,0}-{2714,5108,0,1,0}-{2716,5092,0,1,0}-{2719,5071,0,1,0}-{2722,5061,0,1,0}-{2732,5087,0,1,0}-{2739,5078,0,1,0}-{2740,5104,0,1,0}-{2747,5083,0,1,0}-{2627,5093,0,1,0}-{2629,5061,0,1,0}-{2638,5090,0,1,0}-{2651,5105,0,1,0}-{2654,5079,0,1,0}-{2663,5116,0,1,0}-{2683,5059,0,1,0}-{2685,5111,0,1,0}-" "loc_data": "{2627,5093,0,1,0}-{2629,5061,0,1,0}-{2638,5090,0,1,0}-{2651,5105,0,1,0}-{2654,5079,0,1,0}-{2663,5116,0,1,0}-{2683,5059,0,1,0}-{2685,5111,0,1,0}-{2693,5065,0,1,0}-{2693,5089,0,1,0}-{2704,5091,0,1,0}-{2710,5095,0,1,0}-{2712,5076,0,1,0}-{2714,5108,0,1,0}-{2716,5092,0,1,0}-{2719,5071,0,1,0}-{2722,5061,0,1,0}-{2732,5087,0,1,0}-{2739,5078,0,1,0}-{2740,5104,0,1,0}-{2747,5083,0,1,0}-"
}, },
{ {
"npc_id": "5361", "npc_id": "5361",
@ -10245,11 +10297,11 @@
}, },
{ {
"npc_id": "6050", "npc_id": "6050",
"loc_data": "{3264,3008,0,1,0}-{3266,3008,0,1,0}-{3285,3066,0,1,0}-{3322,3032,0,1,0}-{3323,3055,0,1,0}-{3325,3010,0,1,0}-{3174,3010,0,1,0}-{3198,3061,0,1,0}-{3199,3016,0,1,0}-{3219,3125,0,1,0}-{3233,3075,0,1,0}-{3250,3126,0,1,0}-{3223,3011,0,1,0}-{3228,3060,0,1,0}-{3251,3059,0,1,0}-{3310,3076,0,1,0}-" "loc_data": "{3174,3010,0,1,0}-{3198,3061,0,1,0}-{3199,3016,0,1,0}-{3223,3011,0,1,0}-{3228,3060,0,1,0}-{3251,3059,0,1,0}-{3219,3125,0,1,0}-{3233,3075,0,1,0}-{3250,3126,0,1,0}-{3264,3008,0,1,0}-{3266,3008,0,1,0}-{3285,3066,0,1,0}-{3322,3032,0,1,0}-{3323,3055,0,1,0}-{3325,3010,0,1,0}-{3310,3076,0,1,0}-"
}, },
{ {
"npc_id": "6051", "npc_id": "6051",
"loc_data": "{3266,3010,0,1,0}-{3267,3068,0,1,0}-{3287,3065,0,1,0}-{3287,3067,0,1,0}-{3310,3070,0,1,0}-{3312,3068,0,1,0}-{3320,3054,0,1,0}-{3324,3013,0,1,0}-{3325,3033,0,1,0}-{3153,3047,0,1,0}-{3196,3063,0,1,0}-{3199,3036,0,1,0}-{3215,3092,0,1,0}-{3217,3124,0,1,0}-{3260,3077,0,1,0}-{3223,3035,0,1,0}-{3225,3011,0,1,0}-{3283,3084,0,1,0}-" "loc_data": "{3153,3047,0,1,0}-{3196,3063,0,1,0}-{3199,3036,0,1,0}-{3223,3035,0,1,0}-{3225,3011,0,1,0}-{3215,3092,0,1,0}-{3217,3124,0,1,0}-{3260,3077,0,1,0}-{3266,3010,0,1,0}-{3267,3068,0,1,0}-{3287,3065,0,1,0}-{3287,3067,0,1,0}-{3310,3070,0,1,0}-{3312,3068,0,1,0}-{3320,3054,0,1,0}-{3324,3013,0,1,0}-{3325,3033,0,1,0}-{3283,3084,0,1,0}-"
}, },
{ {
"npc_id": "6052", "npc_id": "6052",
@ -10375,6 +10427,38 @@
"npc_id": "6117", "npc_id": "6117",
"loc_data": "{1884,5020,0,0,6}-" "loc_data": "{1884,5020,0,0,6}-"
}, },
{
"npc_id": "6118",
"loc_data": "{2443,3190,0,0,6}-"
},
{
"npc_id": "6119",
"loc_data": "{2439,3186,0,1,4}-"
},
{
"npc_id": "6120",
"loc_data": "{2437,3160,1,1,4}-"
},
{
"npc_id": "6122",
"loc_data": "{2327,9394,0,0,1}-"
},
{
"npc_id": "6123",
"loc_data": "{2364,9399,0,0,1}-"
},
{
"npc_id": "6124",
"loc_data": "{2364,9398,0,0,1}-"
},
{
"npc_id": "6125",
"loc_data": "{2323,9377,0,1,0}-"
},
{
"npc_id": "6126",
"loc_data": "{2351,9358,0,1,0}-"
},
{ {
"npc_id": "6127", "npc_id": "6127",
"loc_data": "{2467,3183,0,0,3}-" "loc_data": "{2467,3183,0,0,3}-"
@ -10455,6 +10539,38 @@
"npc_id": "6190", "npc_id": "6190",
"loc_data": "{1906,4270,0,1,0}-" "loc_data": "{1906,4270,0,1,0}-"
}, },
{
"npc_id": "6191",
"loc_data": "{2739,3577,0,1,0}-{2739,3579,1,1,0}-"
},
{
"npc_id": "6192",
"loc_data": "{2734,3575,0,1,0}-"
},
{
"npc_id": "6193",
"loc_data": "{2748,3559,0,1,0}-"
},
{
"npc_id": "6194",
"loc_data": "{2734,3581,1,1,0}-"
},
{
"npc_id": "6195",
"loc_data": "{2739,3581,0,1,0}-"
},
{
"npc_id": "6196",
"loc_data": "{2746,3581,1,1,0}-"
},
{
"npc_id": "6197",
"loc_data": "{2742,3577,0,1,0}-"
},
{
"npc_id": "6199",
"loc_data": "{2737,3466,0,1,0}-"
},
{ {
"npc_id": "6200", "npc_id": "6200",
"loc_data": "{2947,3366,0,0,1}-{2949,3366,0,0,1}-{2946,3366,0,0,1}-{2948,3366,0,0,1}-{2945,3366,0,0,1}-{3010,3353,0,0,1}-{3011,3353,0,0,1}-{3012,3353,0,0,1}-{3013,3353,0,0,1}-{3014,3353,0,0,1}-{3015,3353,0,0,1}-" "loc_data": "{2947,3366,0,0,1}-{2949,3366,0,0,1}-{2946,3366,0,0,1}-{2948,3366,0,0,1}-{2945,3366,0,0,1}-{3010,3353,0,0,1}-{3011,3353,0,0,1}-{3012,3353,0,0,1}-{3013,3353,0,0,1}-{3014,3353,0,0,1}-{3015,3353,0,0,1}-"
@ -12059,10 +12175,6 @@
"npc_id": "7804", "npc_id": "7804",
"loc_data": "{3279,4350,0,1,0}-{3294,4353,0,1,0}-{3294,4366,0,1,0}-" "loc_data": "{3279,4350,0,1,0}-{3294,4353,0,1,0}-{3294,4366,0,1,0}-"
}, },
{
"npc_id": "7823",
"loc_data": "{3161,9547,0,0,3}-{3164,9556,0,0,4}-{3162,9574,0,0,3}-{3198,9554,0,0,7}-{3198,9572,0,0,1}-{3215,9560,0,0,1}-{3216,9588,0,0,1}-"
},
{ {
"npc_id": "7891", "npc_id": "7891",
"loc_data": "{3207,3250,0,0,0}-{3208,3250,0,0,0}-{3209,3250,0,0,0}-" "loc_data": "{3207,3250,0,0,0}-{3208,3250,0,0,0}-{3209,3250,0,0,0}-"
@ -12225,7 +12337,7 @@
}, },
{ {
"npc_id": "8324", "npc_id": "8324",
"loc_data": "{2911,3811,0,1,0}-{2911,3812,0,1,0}-{2911,3813,0,1,0}-{2925,3821,0,1,0}-{2925,3822,0,1,0}-{2925,3823,0,1,0}-{2929,3798,0,1,0}-{2936,3790,0,1,0}-{2936,3810,0,1,0}-{2939,3823,0,1,0}-{2949,3819,1,1,0}-{2949,3822,1,1,0}-{2955,3822,1,1,0}-{2957,3822,1,1,0}-{3016,9977,1,1,0}-{3021,9939,1,1,0}-{3024,9954,1,1,0}-{3025,9943,1,1,0}-{3025,9954,1,1,0}-{3026,9966,1,1,0}-{3032,9952,1,1,0}-{3039,9954,1,1,0}-{3044,9967,1,1,0}-{3044,9971,1,1,0}-{3057,9936,1,1,0}-{3059,9953,1,1,0}-{3041,9975,2,1,0}-{3043,9975,2,1,0}-{3045,9975,2,1,0}-{3016,10022,2,1,0}-{3017,10039,2,1,0}-{3027,10028,2,1,0}-{3029,10013,2,1,0}-{3036,10038,2,1,0}-{3037,10006,2,1,0}-{3041,10024,2,1,0}-{3043,10032,2,1,0}-{3057,10002,2,1,0}-{3058,10021,2,1,0}-{3065,10006,2,1,0}-{3027,10092,1,1,0}-{3035,10097,1,1,0}-{3051,10099,1,1,0}-{3427,5102,0,1,0}-{3428,5099,0,1,0}-{3428,5102,0,1,0}-{3430,5099,0,1,0}-" "loc_data": "{2911,3811,0,1,0}-{2911,3812,0,1,0}-{2911,3813,0,1,0}-{2925,3821,0,1,0}-{2925,3822,0,1,0}-{2925,3823,0,1,0}-{2929,3798,0,1,0}-{2936,3790,0,1,0}-{2936,3810,0,1,0}-{2939,3823,0,1,0}-{3427,5102,0,1,0}-{3428,5099,0,1,0}-{3428,5102,0,1,0}-{3430,5099,0,1,0}-{2949,3819,1,1,0}-{2949,3822,1,1,0}-{2955,3822,1,1,0}-{2957,3822,1,1,0}-{3016,9977,1,1,0}-{3021,9939,1,1,0}-{3024,9954,1,1,0}-{3025,9943,1,1,0}-{3025,9954,1,1,0}-{3026,9966,1,1,0}-{3032,9952,1,1,0}-{3039,9954,1,1,0}-{3044,9967,1,1,0}-{3044,9971,1,1,0}-{3057,9936,1,1,0}-{3059,9953,1,1,0}-{3041,9975,2,1,0}-{3043,9975,2,1,0}-{3045,9975,2,1,0}-{3016,10022,2,1,0}-{3017,10039,2,1,0}-{3027,10028,2,1,0}-{3029,10013,2,1,0}-{3036,10038,2,1,0}-{3037,10006,2,1,0}-{3041,10024,2,1,0}-{3043,10032,2,1,0}-{3057,10002,2,1,0}-{3058,10021,2,1,0}-{3065,10006,2,1,0}-{3027,10092,1,1,0}-{3035,10097,1,1,0}-{3051,10099,1,1,0}-"
}, },
{ {
"npc_id": "8328", "npc_id": "8328",

View file

@ -20055,6 +20055,10 @@
"examine": "Home sweet home?", "examine": "Home sweet home?",
"ids": "15480" "ids": "15480"
}, },
{
"examine": "Baby bread.",
"ids": "15506,15507"
},
{ {
"examine": "Home sweet home?", "examine": "Home sweet home?",
"ids": "15748" "ids": "15748"
@ -20183,6 +20187,18 @@
"examine": "A short longboat!", "examine": "A short longboat!",
"ids": "21834" "ids": "21834"
}, },
{
"examine": "A place to sit and watch furniture grow.",
"ids": "28627"
},
{
"examine": "It's not rolling, but it seems to have gathered some moss.",
"ids": "28635"
},
{
"examine": "A thick metal gate.",
"ids": "28690,28691,28692,28693"
},
{ {
"examine": "Contains traces of summoning energy.", "examine": "Contains traces of summoning energy.",
"ids": "29939,29943,29944,29945,29947,29951,29952,29953,29954" "ids": "29939,29943,29944,29945,29947,29951,29952,29953,29954"

View file

@ -177,7 +177,7 @@
"general_store": "true", "general_store": "true",
"id": "21", "id": "21",
"title": "Gunslik's Assorted Items", "title": "Gunslik's Assorted Items",
"stock": "{1931,30,100}-{1935,30,100}-{1735,10,100}-{1925,10,100}-{1923,10,100}-{1887,10,100}-{590,10,100}-{1755,10,100}-{2347,10,100}-{550,10,100}-{9003,10,100}" "stock": "{1935,10,100}-{1925,30,100}-{590,10,100}-{1755,10,100}-{2347,10,100}-{36,10,100}-{596,10,100}-{973,10,100}-{1059,10,100}-{229,300,100}-{233,10,100}-{954,10,100}"
}, },
{ {
"npcs": "1334", "npcs": "1334",

View file

@ -20,7 +20,7 @@ import org.rs09.consts.Sounds
import java.util.* import java.util.*
/** /**
* Represents an enchanted jewellery. * Represents a piece of enchanted jewellery.
* @author Vexia, downthecrop, Player Name * @author Vexia, downthecrop, Player Name
*/ */
enum class EnchantedJewellery( enum class EnchantedJewellery(

View file

@ -1,87 +0,0 @@
package content.data;
import core.game.node.item.Item;
/**
* Represents the repair item type.
* @author Vexia
*/
public enum RepairItem {
BRONZE_HATCHET(new Item(494, 1), new Item(1351, 1), 0),
BRONZE_PICKAXE(new Item(468, 1), new Item(1265, 1), 0),
IRON_HATCHET(new Item(496, 1), new Item(1349, 1), 0),
IRON_PICKAXE(new Item(470, 1), new Item(1267, 1), 0),
STEEL_HATCHET(new Item(498, 1), new Item(1353, 1), 0),
STEEL_PICKAXE(new Item(472, 1), new Item(1269, 1), 14),
BLACK_HATCHET(new Item(500, 1), new Item(1361, 1), 10),
MITHRIL_HATCHET(new Item(502, 1), new Item(1355, 1), 18),
MITHRIL_PICKAXE(new Item(474, 1), new Item(1273, 1), 43),
ADAMANT_HATCHET(new Item(504, 1), new Item(1357, 1), 43),
ADAMANT_PICKAXE(new Item(476, 1), new Item(1271, 1), 107),
RUNE_HATCHET(new Item(506, 1), new Item(1359, 1), 427),
RUNE_PICKAXE(new Item(478, 1), new Item(1275, 1), 1100),
DRAGON_HATCHET(new Item(6741, 1), new Item(6739, 1), 1800);
/**
* The item id.
*/
private final Item item;
/**
* The product item.
*/
private final Item product;
/**
* The cost of the money to repair.
*/
private final int cost;
/**
* Constructs a new {@code BobRepairItem} {@code Object}.
* @param item the item.
* @param product the product.
* @param cost the cost.
*/
RepairItem(Item item, Item product, int cost) {
this.item = item;
this.product = product;
this.cost = cost;
}
/**
* Gets the item.
* @return The item.
*/
public Item getItem() {
return item;
}
/**
* Gets the product.
* @return The product.
*/
public Item getProduct() {
return product;
}
/**
* Gets the cost.
* @return The cost.
*/
public int getCost() {
return cost;
}
/**
* Gets the reapir item by the id.
* @param id the id.
* @return the repair item.
*/
public static RepairItem forId(int id) {
for (RepairItem item : RepairItem.values())
if (item.item.getId() == id)
return item;
return null;
}
}

View file

@ -0,0 +1,43 @@
package content.data
import core.game.node.item.Item
/**
* Represents the repair item type.
* @author Vexia
* @author Damighty - Kotlin conversion
*/
enum class RepairItem(
val item: Item,
val product: Item,
val cost: Int
) {
BRONZE_HATCHET(Item(494, 1), Item(1351, 1), 0),
BRONZE_PICKAXE(Item(468, 1), Item(1265, 1), 0),
IRON_HATCHET(Item(496, 1), Item(1349, 1), 0),
IRON_PICKAXE(Item(470, 1), Item(1267, 1), 0),
STEEL_HATCHET(Item(498, 1), Item(1353, 1), 0),
STEEL_PICKAXE(Item(472, 1), Item(1269, 1), 14),
BLACK_HATCHET(Item(500, 1), Item(1361, 1), 10),
MITHRIL_HATCHET(Item(502, 1), Item(1355, 1), 18),
MITHRIL_PICKAXE(Item(474, 1), Item(1273, 1), 43),
ADAMANT_HATCHET(Item(504, 1), Item(1357, 1), 43),
ADAMANT_PICKAXE(Item(476, 1), Item(1271, 1), 107),
RUNE_HATCHET(Item(506, 1), Item(1359, 1), 427),
RUNE_PICKAXE(Item(478, 1), Item(1275, 1), 1100),
DRAGON_HATCHET(Item(6741, 1), Item(6739, 1), 1800);
companion object {
/**
* List of all repairable item IDs.
*/
@JvmStatic
val repairableItemIds: List<Int> = values().map { it.item.id }
/**
* Gets the repair item by the broken items ID.
*/
@JvmStatic
fun forId(id: Int): RepairItem? = values().firstOrNull { it.item.id == id }
}
}

View file

@ -342,7 +342,7 @@ public enum Consumables {
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), new SkillEffect(Skills.ATTACK, 0, 0.25), new SkillEffect(Skills.STRENGTH, 0, 0.15), new SkillEffect(Skills.DEFENCE, 0, -0.1)))),
ANTIFIRE(new Potion(new int[] {2452, 2454, 2456, 2458}, new AddTimerEffect("dragonfire:immunity", 600, true))), ANTIFIRE(new Potion(new int[] {2452, 2454, 2456, 2458}, new AddTimerEffect("dragonfire:immunity", 600, true))),
GUTH_REST(new Potion(new int[] {4417, 4419, 4421, 4423}, new MultiEffect(new RemoveTimerEffect("poison"), new EnergyEffect(5), new HealingEffect(5)))), GUTH_REST(new Potion(new int[] {4417, 4419, 4421, 4423}, new MultiEffect(new RemoveTimerEffect("poison"), new EnergyEffect(5), new HealingEffect(5)))),
MAGIC_ESS(new Potion(new int[] {11491, 11489}, new SkillEffect(Skills.MAGIC,3,0))), MAGIC_ESS(new Potion(new int[] {9021, 9022, 9023, 9024}, new SkillEffect(Skills.MAGIC,3,0))),
SANFEW(new Potion(new int[] {10925, 10927, 10929, 10931}, new MultiEffect(new RestoreEffect(8,0.25, true), new AddTimerEffect("poison:immunity", secondsToTicks(90)), new RemoveTimerEffect("disease")))), SANFEW(new Potion(new int[] {10925, 10927, 10929, 10931}, new MultiEffect(new RestoreEffect(8,0.25, true), new AddTimerEffect("poison:immunity", secondsToTicks(90)), new RemoveTimerEffect("disease")))),
SUPER_ENERGY(new Potion(new int[] {3016, 3018, 3020, 3022}, new EnergyEffect(20))), SUPER_ENERGY(new Potion(new int[] {3016, 3018, 3020, 3022}, new EnergyEffect(20))),
BLAMISH_OIL(new FakeConsumable(1582, new String[] {"You know... I'd really rather not."})), BLAMISH_OIL(new FakeConsumable(1582, new String[] {"You know... I'd really rather not."})),
@ -365,9 +365,13 @@ public enum Consumables {
SUPER_ENERGY_MIX(new BarbarianMix(new int[] {11481, 11483}, new MultiEffect(new EnergyEffect(20), new HealingEffect(6)))), SUPER_ENERGY_MIX(new BarbarianMix(new int[] {11481, 11483}, new MultiEffect(new EnergyEffect(20), new HealingEffect(6)))),
HUNTING_MIX(new BarbarianMix(new int[] {11517, 11519}, new MultiEffect(new SkillEffect(Skills.HUNTER, 3, 0), new HealingEffect(6)))), HUNTING_MIX(new BarbarianMix(new int[] {11517, 11519}, new MultiEffect(new SkillEffect(Skills.HUNTER, 3, 0), new HealingEffect(6)))),
SUPER_STR_MIX(new BarbarianMix(new int[] {11485, 11487}, new MultiEffect(new SkillEffect(Skills.STRENGTH, 5, 0.15), new HealingEffect(6)))), SUPER_STR_MIX(new BarbarianMix(new int[] {11485, 11487}, new MultiEffect(new SkillEffect(Skills.STRENGTH, 5, 0.15), new HealingEffect(6)))),
ANTIDOTE_PLUS_MIX(new BarbarianMix(new int[] {11501, 11503}, new MultiEffect(new AddTimerEffect("poison:immunity", minutesToTicks(9)), new RandomHealthEffect(3, 7)))), ANTIDOTE_PLUS_MIX(new BarbarianMix(new int[] {11501, 11503}, new MultiEffect(new AddTimerEffect("poison:immunity", minutesToTicks(9)), new HealingEffect(6)))),
ANTIP_SUPERMIX(new BarbarianMix(new int[] {11473, 11475}, new MultiEffect(new AddTimerEffect("poison:immunity", minutesToTicks(6)), new RandomHealthEffect(3, 7)))), ANTIP_SUPERMIX(new BarbarianMix(new int[] {11473, 11475}, new MultiEffect(new AddTimerEffect("poison:immunity", minutesToTicks(6)), new HealingEffect(6)))),
ANTIFIRE_MIX(new BarbarianMix(new int[] {11505, 11507}, new MultiEffect(new AddTimerEffect("dragonfire:immunity", 600, true), new RandomHealthEffect(3, 7)))), ANTIFIRE_MIX(new BarbarianMix(new int[] {11505, 11507}, new MultiEffect(new AddTimerEffect("dragonfire:immunity", 600, true), new HealingEffect(6)))),
MAGIC_ESS_MIX(new BarbarianMix(new int[] {11489, 11491}, new MultiEffect(new SkillEffect(Skills.MAGIC, 3, 0), new HealingEffect(6)))),
SUPER_DEF_MIX(new BarbarianMix(new int[] {11497, 11499}, new MultiEffect(new SkillEffect(Skills.DEFENCE, 5, 0.15), new HealingEffect(6)))),
RANGING_MIX(new BarbarianMix(new int[] {11509, 11511}, new MultiEffect(new SkillEffect(Skills.RANGE, 4, 0.1), new HealingEffect(6)))),
MAGIC_MIX(new BarbarianMix(new int[] {11513, 11515}, new MultiEffect(new SkillEffect(Skills.MAGIC, 4, 0), new HealingEffect(6)))),
/** Stealing creation potions */ /** Stealing creation potions */
SC_PRAYER(new Potion(new int[] {14207, 14209, 14211, 14213, 14215}, new PrayerEffect(7, 0.25))), SC_PRAYER(new Potion(new int[] {14207, 14209, 14211, 14213, 14215}, new PrayerEffect(7, 0.25))),

View file

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

View file

@ -45,35 +45,35 @@ class ChampionChallengeListener : InteractionListener, MapArea {
private val IMP_SCROLL_TEXT = arrayOf( private val IMP_SCROLL_TEXT = arrayOf(
"How about picking on someone your own size? I'll", "How about picking on someone your own size? I'll",
"see you at the Champion's Guild.", "see you at the Champions' Guild.",
"", "",
"Champion of Imps" "Champion of Imps"
) )
private val GOBLIN_SCROLL_TEXT = arrayOf( private val GOBLIN_SCROLL_TEXT = arrayOf(
"Fight me if you think you can human, I'll wait", "Fight me if you think you can human, I'll wait",
"for you in the Champion's Guild.", "for you in the Champions' Guild.",
"", "",
"Champion of Goblins" "Champion of Goblins"
) )
private val SKELETON_SCROLL_TEXT = arrayOf( private val SKELETON_SCROLL_TEXT = arrayOf(
"I'll be waiting at the Champions' Guild to", "I'll be waiting at the Champions' Guild to collect",
"collect your bones.", "your bones.",
"", "",
"Champion of Skeletons" "Champion of Skeletons"
) )
private val ZOMBIE_SCROLL_TEXT = arrayOf( private val ZOMBIE_SCROLL_TEXT = arrayOf(
"You come to Champions' Guild, you fight me,", "You come to Champions' Guild, you fight me, I",
"I squish you, I get brains!", "squish you, I get brains!",
"", "",
"Champion of Zombies" "Champion of Zombies"
) )
private val GIANT_SCROLL_TEXT = arrayOf( private val GIANT_SCROLL_TEXT = arrayOf(
"Get yourself to the Champions' Guild, if you", "Get yourself to the Champions' Guild, if you dare",
"dare to face me puny human.", "to face me puny human.",
"", "",
"Champion of Giants" "Champion of Giants"
) )
@ -93,21 +93,22 @@ class ChampionChallengeListener : InteractionListener, MapArea {
) )
private val EARTH_WARRIOR_TEXT = arrayOf( private val EARTH_WARRIOR_TEXT = arrayOf(
"I challenge you to a duel, come to the arena beneath", "I challenge you to a duel, come to the arena",
"the Champion's Guild and fight me if you dare.", "beneath the Champions' Guild and fight me if you",
"dare.",
"", "",
"Champion of Earth Warriors" "Champion of Earth Warriors"
) )
private val JOGRE_SCROLL_TEXT = arrayOf( private val JOGRE_SCROLL_TEXT = arrayOf(
"You think you can defeat me? Come to the", "You think you can defeat me? Come to the",
"Champion's Guild and prove it!", "Champions' Guild and prove it!",
"", "",
"Champion of Jogres" "Champion of Jogres"
) )
private val LESSER_DEMON_SCROLL_TEXT = arrayOf( private val LESSER_DEMON_SCROLL_TEXT = arrayOf(
"Come to the Champion's Guild so I can banish", "Come to the Champions' Guild so I can banish",
"you mortal!", "you mortal!",
"", "",
"Champion of Lesser Demons" "Champion of Lesser Demons"

View file

@ -70,7 +70,7 @@ class ChampionScrollsDropHandler : ChampionScrollsEventHookBase() {
NPCs.CAVE_GOBLIN_GUARD_2073, NPCs.CAVE_GOBLIN_GUARD_2074, NPCs.CAVE_GOBLIN_GUARD_2073, NPCs.CAVE_GOBLIN_GUARD_2074,
NPCs.GOBLIN_GUARD_489, NPCs.GOBLIN_GUARD_6496, NPCs.GOBLIN_GUARD_6497, NPCs.GOBLIN_GUARD_6496, NPCs.GOBLIN_GUARD_6497,
NPCs.SERGEANT_GRIMSPIKE_6265, NPCs.SERGEANT_GRIMSPIKE_6265,
NPCs.SERGEANT_STEELWILL_6263, NPCs.SERGEANT_STEELWILL_6263,
NPCs.SERGEANT_STRONGSTACK_6261 NPCs.SERGEANT_STRONGSTACK_6261

View file

@ -27,24 +27,24 @@ class LarxusDialogue(val ChallengeStart: Boolean = false) : DialogueFile() {
0 -> { 0 -> {
face(findNPC(NPCs.LARXUS_3050)!!, player!!, 1) face(findNPC(NPCs.LARXUS_3050)!!, player!!, 1)
for (i in scrolls)when{ for (i in scrolls)when{
inInventory(player!!,Items.CHAMPION_SCROLL_6798) -> npcl("So you want to accept the challenge huh? Well there are some specific rules for these Champion fights. For this fight you're not allowed to use prayer's. Do you still want to proceed?").also { stage = 1 } inInventory(player!!,Items.CHAMPION_SCROLL_6798) -> npcl("So you want to accept the challenge huh? Well there are some specific rules for these Champion fights. For this fight you're not allowed to use any Prayers. Do you still want to proceed?").also { stage = 1 }
inInventory(player!!,Items.CHAMPION_SCROLL_6799) -> npcl("So you want to accept the challenge huh? Well there are some specific rules for these Champion fights. For this fight you're allowed to use only weapons. Do you still want to proceed?").also { stage = 1 } inInventory(player!!,Items.CHAMPION_SCROLL_6799) -> npcl("So you want to accept the challenge huh? Well there are some specific rules for these Champion fights. For this fight you're only allowed to take Weapons, no other items are allowed. Do you still want to proceed?").also { stage = 1 }
inInventory(player!!,Items.CHAMPION_SCROLL_6800) -> npcl("So you want to accept the challenge huh? Well there are some specific rules for these Champion fights. For this fight you're allowed to use only melee combat skill. Do you still want to proceed?").also { stage = 1 } inInventory(player!!,Items.CHAMPION_SCROLL_6800) -> npcl("So you want to accept the challenge huh? Well there are some specific rules for these Champion fights. For this fight you're only allowed to use Melee attacks, no Ranged or Magic. Do you still want to proceed?").also { stage = 1 }
inInventory(player!!,Items.CHAMPION_SCROLL_6801) -> npcl("So you want to accept the challenge huh? Well there are some specific rules for these Champion fights. For this fight you're allowed to use only magic skill. Do you still want to proceed?").also { stage = 1 } inInventory(player!!,Items.CHAMPION_SCROLL_6801) -> npcl("So you want to accept the challenge huh? Well there are some specific rules for these Champion fights. For this fight you're only allowed to use Magic attacks, no Melee or Ranged. Do you still want to proceed?").also { stage = 1 }
inInventory(player!!,Items.CHAMPION_SCROLL_6802) -> npcl("So you want to accept the challenge huh? Well there are some specific rules for these Champion fights. For this fight you're not allowed to use melee combat skills. Do you still want to proceed?").also { stage = 1 } inInventory(player!!,Items.CHAMPION_SCROLL_6802) -> npcl("So you want to accept the challenge huh? Well there are some specific rules for these Champion fights. For this fight you're not allowed to use any Melee attacks. Do you still want to proceed?").also { stage = 1 }
inInventory(player!!,Items.CHAMPION_SCROLL_6803) -> npcl("So you want to accept the challenge huh? Well there are some specific rules for these Champion fights. For this fight you're not allowed to use weapons with special attack. Do you still want to proceed?").also { stage = 1 } inInventory(player!!,Items.CHAMPION_SCROLL_6803) -> npcl("So you want to accept the challenge huh? Well there are some specific rules for these Champion fights. For this fight you're not allowed to use any Special Attacks. Do you still want to proceed?").also { stage = 1 }
inInventory(player!!,Items.CHAMPION_SCROLL_6804) -> npcl("So you want to accept the challenge huh? Well there are some specific rules for these Champion fights. For this fight you're not allowed to use ranged skill. Do you still want to proceed?").also { stage = 1 } inInventory(player!!,Items.CHAMPION_SCROLL_6804) -> npcl("So you want to accept the challenge huh? Well there are some specific rules for these Champion fights. For this fight you're not allowed to use any Ranged attacks. Do you still want to proceed?").also { stage = 1 }
inInventory(player!!,Items.CHAMPION_SCROLL_6805) -> npcl("So you want to accept the challenge huh? Well there are some specific rules for these Champion fights. For this fight you're allowed to use only equipment. Do you still want to proceed?").also { stage = 1 } inInventory(player!!,Items.CHAMPION_SCROLL_6805) -> npcl("So you want to accept the challenge huh? Well there are some specific rules for these Champion fights. For this fight you're not allowed any Weapons or Armour. Do you still want to proceed?").also { stage = 1 }
inInventory(player!!,Items.CHAMPION_SCROLL_6806) -> npcl("So you want to accept the challenge huh? Well there are some specific rules for these Champion fights. For this fight you're allowed to use only ranged skill. Do you still want to proceed?").also { stage = 1 } inInventory(player!!,Items.CHAMPION_SCROLL_6806) -> npcl("So you want to accept the challenge huh? Well there are some specific rules for these Champion fights. For this fight you're only allowed to use Ranged attacks, no Melee or Magic. Do you still want to proceed?").also { stage = 1 }
inInventory(player!!,Items.CHAMPION_SCROLL_6807) -> npcl("So you want to accept the challenge huh? Well there are some specific rules for these Champion fights. For this fight you're not allowed to use magic skill. Do you still want to proceed?").also { stage = 1 } inInventory(player!!,Items.CHAMPION_SCROLL_6807) -> npcl("So you want to accept the challenge huh? Well there are some specific rules for these Champion fights. For this fight you're not allowed to use any Magic attacks. Do you still want to proceed?").also { stage = 1 }
else -> { else -> {
sendMessage(player!!, "Nothing interesting happens.").also { stage = END_DIALOGUE } } sendMessage(player!!, "Nothing interesting happens.").also { stage = END_DIALOGUE } }
} }
} }
1 -> options("Yes, let me at him!", "No, thanks I'll pass.").also { stage = 2 } 1 -> options("Yes, let me at him!", "No thanks, I'll pass.").also { stage = 2 }
2 -> when (buttonID) { 2 -> when (buttonID) {
1 -> playerl("Yes, let me at him!").also { stage = 3 } 1 -> playerl("Yes, let me at him!").also { stage = 3 }
2 -> playerl("No, thanks I'll pass.").also { stage = END_DIALOGUE } 2 -> playerl("No thanks, I'll pass.").also { stage = END_DIALOGUE }
} }
3 -> npcl("Your challenger is ready, please go down through the trapdoor when you're ready.").also { stage = 4 } 3 -> npcl("Your challenger is ready, please go down through the trapdoor when you're ready.").also { stage = 4 }
4 -> { 4 -> {
@ -65,7 +65,7 @@ class LarxusDialogue(val ChallengeStart: Boolean = false) : DialogueFile() {
3 -> playerl("Nothing thanks.").also { stage = END_DIALOGUE } 3 -> playerl("Nothing thanks.").also { stage = END_DIALOGUE }
} }
3 -> npcl("Well pass it here and we'll get you started.").also { stage = END_DIALOGUE } 3 -> npcl("Well pass it here and we'll get you started.").also { stage = END_DIALOGUE }
4 -> npcl("This is the champions' arena, the champions of various, races use it to duel those they deem worthy of the, honour.").also { stage = END_DIALOGUE } 4 -> npcl("This is the champions' arena. The champions of various races use it to duel those they deem worthy of the honour. If you find a challenge scroll in your travels, bring it here to face your challenger.").also { stage = END_DIALOGUE }
} }
} }
} }

View file

@ -3,8 +3,6 @@ package content.global.activity.cchallange.npc
import core.api.* import core.api.*
import core.game.node.entity.Entity import core.game.node.entity.Entity
import core.game.node.entity.combat.BattleState import core.game.node.entity.combat.BattleState
import core.game.node.entity.combat.CombatStyle
import core.game.node.entity.combat.equipment.WeaponInterface
import core.game.node.entity.npc.AbstractNPC import core.game.node.entity.npc.AbstractNPC
import core.game.node.entity.player.Player import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills import core.game.node.entity.skill.Skills
@ -63,21 +61,11 @@ class ImpChampionNPC(id: Int = 0, location: Location? = null) : AbstractNPC(id,
super.checkImpact(state) super.checkImpact(state)
val player = state.attacker val player = state.attacker
if (player is Player) { if (player is Player) {
val w = player.getExtension<WeaponInterface>(WeaponInterface::class.java)
if (state.style == CombatStyle.MELEE || state.style == CombatStyle.MAGIC || state.style == CombatStyle.RANGE) { //somehow the maximumHit is determined to be zero by this point if you're using a melee special attack.
if (state.maximumHit == 0) {
state.neutralizeHits() state.neutralizeHits()
state.estimatedHit = state.maximumHit sendMessage(player, "Larxus said you couldn't use special attacks in this duel.")
}
if (w.weaponInterface.interfaceId == 10) {
sendMessage(player, "You cannot use special attack in this challenge.")
if (state.estimatedHit > -1) {
state.estimatedHit = 0
return
}
if (state.secondaryHit > -1) {
state.secondaryHit = 0
return
}
} }
} }
} }

View file

@ -6,6 +6,7 @@ import core.game.node.entity.player.Player
import core.game.node.entity.skill.SkillPulse import core.game.node.entity.skill.SkillPulse
import core.game.node.entity.skill.Skills import core.game.node.entity.skill.Skills
import content.data.skill.SkillingTool import content.data.skill.SkillingTool
import core.ServerConstants
import core.game.node.item.Item import core.game.node.item.Item
import core.tools.RandomFunction import core.tools.RandomFunction
import org.rs09.consts.Items import org.rs09.consts.Items
@ -13,6 +14,9 @@ import core.game.world.GameWorld
import core.game.world.repository.Repository import core.game.world.repository.Repository
import core.tools.colorize import core.tools.colorize
// TODO: Shooting stars should roll for bonus gems while mining
// See: https://youtu.be/6OqZ2TGc6fM?si=U8nB5IDQREhWXApD
/** /**
* The pulse used to handle mining shooting stars. * The pulse used to handle mining shooting stars.
*/ */
@ -46,9 +50,8 @@ class ShootingStarMiningPulse(player: Player?, node: Scenery?, val star: Shootin
//checks if the star has been discovered and if not, awards the bonus xp. Xp can be awarded regardless of mining level as per the wiki. //checks if the star has been discovered and if not, awards the bonus xp. Xp can be awarded regardless of mining level as per the wiki.
if (!star.isDiscovered && !player.isArtificial) { if (!star.isDiscovered && !player.isArtificial) {
val bonusXp = 75 * player.skills.getStaticLevel(Skills.MINING) val bonusXp = 75 * player.skills.getStaticLevel(Skills.MINING)
player.incrementAttribute("/save:shooting-star:bonus-xp", bonusXp) rewardXP(player, Skills.MINING, bonusXp.toDouble())
Repository.sendNews(player.username + " is the discoverer of the crashed star near " + star.location + "!") Repository.sendNews(player.username + " is the discoverer of the crashed star near " + star.location + "!")
player.sendMessage("You have ${player.skills.experienceMultiplier * player.getAttribute("shooting-star:bonus-xp", 0).toDouble()} bonus xp towards mining stardust.")
ShootingStarPlugin.submitScoreBoard(player) ShootingStarPlugin.submitScoreBoard(player)
star.isDiscovered = true star.isDiscovered = true
ShootingStarPlugin.getStoreFile()["isDiscovered"] = star.isDiscovered ShootingStarPlugin.getStoreFile()["isDiscovered"] = star.isDiscovered
@ -88,6 +91,7 @@ class ShootingStarMiningPulse(player: Player?, node: Scenery?, val star: Shootin
val bonusXp = player.getAttribute("shooting-star:bonus-xp", 0).toDouble() val bonusXp = player.getAttribute("shooting-star:bonus-xp", 0).toDouble()
var xp = star.level.exp.toDouble() var xp = star.level.exp.toDouble()
if(bonusXp > 0) { if(bonusXp > 0) {
// legacy: shooting star bonus xp used to be handed out in an inauthentic way; see GL !2092
val delta = Math.min(bonusXp, xp) val delta = Math.min(bonusXp, xp)
player.incrementAttribute("/save:shooting-star:bonus-xp", (-delta).toInt()) player.incrementAttribute("/save:shooting-star:bonus-xp", (-delta).toInt())
xp += delta xp += delta
@ -100,7 +104,7 @@ class ShootingStarMiningPulse(player: Player?, node: Scenery?, val star: Shootin
if (ShootingStarPlugin.getStarDust(player) < 200) { if (ShootingStarPlugin.getStarDust(player) < 200) {
player.inventory.add(Item(ShootingStarPlugin.STAR_DUST, 1)) player.inventory.add(Item(ShootingStarPlugin.STAR_DUST, 1))
} }
if(!inInventory(player, Items.ANCIENT_BLUEPRINT_14651) && !inBank(player, Items.ANCIENT_BLUEPRINT_14651)){ if (ServerConstants.SHOOTING_STAR_RING && hasAnItem(player, Items.ANCIENT_BLUEPRINT_14651).container == null) {
rollBlueprint(player) rollBlueprint(player)
} }
@ -130,7 +134,7 @@ class ShootingStarMiningPulse(player: Player?, node: Scenery?, val star: Shootin
override fun message(type: Int) { override fun message(type: Int) {
when (type) { when (type) {
0 -> player.packetDispatch.sendMessage("You swing your pickaxe at the rock...") 0 -> player.packetDispatch.sendMessage("You swing your pickaxe at the rock.")
} }
} }

View file

@ -2,22 +2,57 @@ package content.global.ame
import core.ServerConstants import core.ServerConstants
import core.api.* import core.api.*
import core.game.interaction.QueueStrength
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player import core.game.node.entity.player.Player
import core.game.node.entity.player.link.TeleportManager.TeleportType import core.game.node.entity.player.link.TeleportManager.TeleportType
import core.game.world.map.Location import core.game.world.map.Location
import core.game.world.update.flag.context.Graphics
import org.rs09.consts.Sounds
fun kidnapPlayer(player: Player, loc: Location, type: TeleportType) { fun kidnapPlayer(npc: NPC, player: Player, dest: Location, playerLine: String? = null, callback: (player: Player, npc: NPC) -> Unit) {
setAttribute(player, "kidnapped-by-random", true) val lockDuration = if (playerLine != null) 4 else 6
if (getAttribute(player, "/save:original-loc", null) == null) { lock(player, lockDuration)
setAttribute(player, "/save:original-loc", player.location) queueScript(player, 1, QueueStrength.SOFT) { stage: Int ->
when (stage) {
0 -> {
if (playerLine != null) {
sendChat(player, playerLine)
return@queueScript delayScript(player, 2)
}
return@queueScript delayScript(player, 0)
}
1 -> {
sendGraphics(Graphics(1576, 0, 0), player.location)
animate(player,8939)
playAudio(player, Sounds.TELEPORT_ALL_200)
return@queueScript delayScript(player, 3)
}
2 -> {
setAttribute(player, "kidnapped-by-random", true)
if (getAttribute<Location?>(player, "/save:original-loc", null) == null) {
setAttribute(player, "/save:original-loc", player.location)
}
teleport(player, dest, TeleportType.INSTANT)
sendGraphics(Graphics(1577, 0, 0), player.location)
animate(player, 8941)
resetAnimator(player)
callback(player, npc)
return@queueScript delayScript(player, 2)
}
3 -> {
removeAttribute(player, "kidnapped-by-random") //this is not needed at this point anymore and will reenable the original-loc sanity check tick action
return@queueScript stopExecuting(player)
}
else -> return@queueScript stopExecuting(player)
}
} }
teleport(player, loc, type)
} }
fun returnPlayer(player: Player) { fun returnPlayer(player: Player) {
player.locks.unlockTeleport() player.locks.unlockTeleport()
val destination = getAttribute(player, "/save:original-loc", ServerConstants.HOME_LOCATION ?: Location.create(3222, 3218, 0)) val destination = getAttribute(player, "/save:original-loc", ServerConstants.HOME_LOCATION)
teleport(player, destination) teleport(player, destination!!)
unlock(player) unlock(player)
removeAttributes(player, "/save:original-loc", "kidnapped-by-random") removeAttributes(player, "/save:original-loc", "kidnapped-by-random")
} }

View file

@ -1,9 +1,10 @@
package content.global.ame package content.global.ame
import content.global.ame.events.MysteriousOldManNPC import content.global.ame.events.surpriseexam.MysteriousOldManNPC
import core.api.playGlobalAudio import core.api.playGlobalAudio
import core.api.poofClear import core.api.poofClear
import core.api.sendMessage import core.api.sendMessage
import core.api.setAttribute
import core.api.utils.WeightBasedTable import core.api.utils.WeightBasedTable
import core.game.interaction.MovementPulse import core.game.interaction.MovementPulse
import core.game.node.entity.Entity import core.game.node.entity.Entity
@ -19,8 +20,10 @@ import core.game.world.map.RegionManager
import core.game.world.map.path.Pathfinder import core.game.world.map.path.Pathfinder
import core.game.world.update.flag.context.Graphics import core.game.world.update.flag.context.Graphics
import core.integrations.discord.Discord import core.integrations.discord.Discord
import core.tools.RandomFunction
import core.tools.secondsToTicks import core.tools.secondsToTicks
import core.tools.ticksToCycles import core.tools.ticksToCycles
import org.rs09.consts.NPCs
import org.rs09.consts.Sounds import org.rs09.consts.Sounds
import kotlin.math.ceil import kotlin.math.ceil
import kotlin.math.min import kotlin.math.min
@ -43,6 +46,7 @@ abstract class RandomEventNPC(id: Int) : NPC(id) {
event.loot = loot event.loot = loot
event.player = player event.player = player
event.spawnLocation = RegionManager.getSpawnLocation(player, this) event.spawnLocation = RegionManager.getSpawnLocation(player, this)
setAttribute(event, "spawned-by-ame", true)
return event return event
} }
@ -101,7 +105,6 @@ abstract class RandomEventNPC(id: Int) : NPC(id) {
} }
open fun onTimeUp() { open fun onTimeUp() {
noteAndTeleport()
terminate() terminate()
} }
@ -144,4 +147,23 @@ abstract class RandomEventNPC(id: Int) : NPC(id) {
val index = min(ids.size, ceil(player.properties.currentCombatLevel / 20.0).toInt()) - 1 val index = min(ids.size, ceil(player.properties.currentCombatLevel / 20.0).toInt()) - 1
return ids[index] return ids[index]
} }
fun sayLine(npc: NPC, phrases: Array<String>, hasOpeningPhrase: Boolean, hasOverTimePhrase: Boolean) {
if (!timerPaused && (ticksLeft % 20 == 0 || ticksLeft <= 2)) { //unless the Certer interface is up, speak every 20 ticks, or in the 2nd-to-last tick before attack/note-&-teleport
var playDwarfWhistle = true
if (ticksLeft == secondsToTicks(180) && hasOpeningPhrase) {
sendChat(phrases[0])
} else if (ticksLeft <= 2 && hasOverTimePhrase) {
sendChat(phrases[phrases.size - 1])
playDwarfWhistle = false
} else {
val start = if (hasOpeningPhrase) 0 else 1
val end = if (hasOverTimePhrase) phrases.size - 2 else phrases.size - 1
sendChat(phrases[RandomFunction.random(start, end + 1)])
}
if (npc.id == NPCs.DRUNKEN_DWARF_956 && playDwarfWhistle) {
playGlobalAudio(this.location, Sounds.DWARF_WHISTLE_2297)
}
}
}
} }

View file

@ -1,7 +1,7 @@
package content.global.ame package content.global.ame
import org.rs09.consts.Items import org.rs09.consts.Items
import content.global.ame.events.MysteriousOldManNPC import content.global.ame.events.surpriseexam.MysteriousOldManNPC
import content.global.ame.events.certer.CerterNPC import content.global.ame.events.certer.CerterNPC
import content.global.ame.events.drilldemon.SergeantDamienNPC import content.global.ame.events.drilldemon.SergeantDamienNPC
import content.global.ame.events.drunkendwarf.DrunkenDwarfNPC import content.global.ame.events.drunkendwarf.DrunkenDwarfNPC
@ -10,6 +10,7 @@ import content.global.ame.events.evilchicken.EvilChickenNPC
import content.global.ame.events.freakyforester.FreakyForesterNPC import content.global.ame.events.freakyforester.FreakyForesterNPC
import content.global.ame.events.maze.MazeNPC import content.global.ame.events.maze.MazeNPC
import content.global.ame.events.genie.GenieNPC import content.global.ame.events.genie.GenieNPC
import content.global.ame.events.candlelight.PiousPeteNPC
import content.global.ame.events.pillory.PilloryNPC import content.global.ame.events.pillory.PilloryNPC
import content.global.ame.events.rickturpentine.RickTurpentineNPC import content.global.ame.events.rickturpentine.RickTurpentineNPC
import content.global.ame.events.rivertroll.RiverTrollRENPC import content.global.ame.events.rivertroll.RiverTrollRENPC
@ -21,6 +22,7 @@ import content.global.ame.events.strangeplant.StrangePlantNPC
import content.global.ame.events.swarm.SwarmNPC import content.global.ame.events.swarm.SwarmNPC
import content.global.ame.events.treespirit.TreeSpiritRENPC import content.global.ame.events.treespirit.TreeSpiritRENPC
import content.global.ame.events.zombie.ZombieRENPC import content.global.ame.events.zombie.ZombieRENPC
import core.ServerConstants
import core.api.utils.WeightBasedTable import core.api.utils.WeightBasedTable
import core.api.utils.WeightedItem import core.api.utils.WeightedItem
@ -29,6 +31,7 @@ import core.game.node.entity.skill.Skills
enum class RandomEvents(val npc: RandomEventNPC, val loot: WeightBasedTable? = null, val skillIds: IntArray = intArrayOf(), val type: String = "") { enum class RandomEvents(val npc: RandomEventNPC, val loot: WeightBasedTable? = null, val skillIds: IntArray = intArrayOf(), val type: String = "") {
SANDWICH_LADY(npc = SandwichLadyRENPC()), SANDWICH_LADY(npc = SandwichLadyRENPC()),
GENIE(npc = GenieNPC()), GENIE(npc = GenieNPC()),
CANDLELIGHT(npc = PiousPeteNPC(), skillIds = intArrayOf(Skills.PRAYER)),
CERTER(npc = CerterNPC(), loot = WeightBasedTable.create( CERTER(npc = CerterNPC(), loot = WeightBasedTable.create(
WeightedItem(Items.UNCUT_SAPPHIRE_1623,1,1,3.4), WeightedItem(Items.UNCUT_SAPPHIRE_1623,1,1,3.4),
WeightedItem(Items.KEBAB_1971,1,1,1.7), WeightedItem(Items.KEBAB_1971,1,1,1.7),
@ -82,6 +85,9 @@ enum class RandomEvents(val npc: RandomEventNPC, val loot: WeightBasedTable? = n
private fun populateMappings() { private fun populateMappings() {
for (event in values()) { for (event in values()) {
if (!ServerConstants.INAUTHENTIC_CANDLELIGHT_RANDOM && event == CANDLELIGHT) {
continue
}
for (id in event.skillIds) { for (id in event.skillIds) {
val list = skillMap[id] ?: ArrayList<RandomEvents>().also { skillMap[id] = it } val list = skillMap[id] ?: ArrayList<RandomEvents>().also { skillMap[id] = it }
list.add (event) list.add (event)
@ -91,5 +97,4 @@ enum class RandomEvents(val npc: RandomEventNPC, val loot: WeightBasedTable? = n
} }
} }
} }
} }

View file

@ -1,5 +1,6 @@
package content.global.ame.events package content.global.ame.events
import core.api.getAttribute
import core.game.node.entity.Entity import core.game.node.entity.Entity
import core.game.node.entity.npc.NPC import core.game.node.entity.npc.NPC
import core.game.node.entity.npc.NPCBehavior import core.game.node.entity.npc.NPCBehavior
@ -8,12 +9,12 @@ import org.rs09.consts.NPCs
class HostileRandomEventBehavior : NPCBehavior( class HostileRandomEventBehavior : NPCBehavior(
NPCs.EVIL_CHICKEN_2463, NPCs.EVIL_CHICKEN_2464, NPCs.EVIL_CHICKEN_2465, NPCs.EVIL_CHICKEN_2466, NPCs.EVIL_CHICKEN_2467, NPCs.EVIL_CHICKEN_2468, NPCs.EVIL_CHICKEN_2463, NPCs.EVIL_CHICKEN_2464, NPCs.EVIL_CHICKEN_2465, NPCs.EVIL_CHICKEN_2466, NPCs.EVIL_CHICKEN_2467, NPCs.EVIL_CHICKEN_2468,
NPCs.RIVER_TROLL_391, NPCs.RIVER_TROLL_392, NPCs.RIVER_TROLL_393, NPCs.RIVER_TROLL_394, NPCs.RIVER_TROLL_395, NPCs.RIVER_TROLL_396, NPCs.RIVER_TROLL_391, NPCs.RIVER_TROLL_392, NPCs.RIVER_TROLL_393, NPCs.RIVER_TROLL_394, NPCs.RIVER_TROLL_395, NPCs.RIVER_TROLL_396,
NPCs.ROCK_GOLEM_413, NPCs.ROCK_GOLEM_414, NPCs.ROCK_GOLEM_415, NPCs.ROCK_GOLEM_416, NPCs.ROCK_GOLEM_417, NPCs.ROCK_GOLEM_418,
NPCs.SHADE_425, NPCs.SHADE_426, NPCs.SHADE_427, NPCs.SHADE_428, NPCs.SHADE_429, NPCs.SHADE_430, NPCs.SHADE_431, NPCs.SHADE_425, NPCs.SHADE_426, NPCs.SHADE_427, NPCs.SHADE_428, NPCs.SHADE_429, NPCs.SHADE_430, NPCs.SHADE_431,
NPCs.TREE_SPIRIT_438, NPCs.TREE_SPIRIT_439, NPCs.TREE_SPIRIT_440, NPCs.TREE_SPIRIT_441, NPCs.TREE_SPIRIT_442, NPCs.TREE_SPIRIT_443, NPCs.TREE_SPIRIT_438, NPCs.TREE_SPIRIT_439, NPCs.TREE_SPIRIT_440, NPCs.TREE_SPIRIT_441, NPCs.TREE_SPIRIT_442, NPCs.TREE_SPIRIT_443,
NPCs.ZOMBIE_419, NPCs.ZOMBIE_420, NPCs.ZOMBIE_421, NPCs.ZOMBIE_422, NPCs.ZOMBIE_423, NPCs.ZOMBIE_424 NPCs.ZOMBIE_419, NPCs.ZOMBIE_420, NPCs.ZOMBIE_421, NPCs.ZOMBIE_422, NPCs.ZOMBIE_423, NPCs.ZOMBIE_424
) { ) {
override fun getXpMultiplier(self: NPC, attacker: Entity): Double { override fun getXpMultiplier(self: NPC, attacker: Entity): Double {
return super.getXpMultiplier(self, attacker) / 16.0 val xprate = super.getXpMultiplier(self, attacker)
return if (getAttribute(self, "spawned-by-ame", false)) xprate / 16.0 else xprate
} }
} }

View file

@ -0,0 +1,164 @@
package content.global.ame.events.candlelight
import core.api.*
import core.api.utils.PlayerCamera
import core.game.interaction.InteractionListener
import core.game.interaction.InterfaceListener
import core.game.node.entity.Entity
import core.game.node.entity.player.Player
import core.game.world.map.Direction
import core.game.world.map.Location
import core.game.world.map.zone.ZoneBorders
import core.game.world.map.zone.ZoneRestriction
import org.rs09.consts.Scenery
/**
* Candlelight Interface CANDLELIGHT_178
*
*/
class CandlelightInterface : InterfaceListener, InteractionListener, MapArea {
companion object {
const val CANDLELIGHT_INTERFACE = 178
const val CANDLELIGHT_RETURN_LOC = "/save:original-loc"
const val CANDLELIGHT_CANDLE_ARRAY = "/save:candlelight:candle-array"
const val CANDLELIGHT_CAMERA_AT = "candlelight:camera-at"
val CANDLE_LOC_ARRAY = arrayOf(
Location(1967, 4997),
Location(1968, 4998),
Location(1967, 4999),
Location(1968, 5000),
Location(1967, 5001),
Location(1968, 5002),
Location(1967, 5003),
Location(1968, 5004),
Location(1967, 5005),
Location(1968, 5006),
Location(1967, 5007),
)
fun initCandlelight(player: Player) {
val candleArray = intArrayOf(0,0,0,0,0,0,2,2,2,2,2)
candleArray.shuffle()
setAttribute(player, CANDLELIGHT_CANDLE_ARRAY, candleArray)
for (candleIndex in 0..10) {
setVarbit(player, 1771 + candleIndex, candleArray[candleIndex])
}
}
fun areCandlesLit(player: Player): Boolean {
val candleArray = getAttribute(player, CANDLELIGHT_CANDLE_ARRAY, intArrayOf(0,0,0,0,0,0,0,0,0,0,0))
for (candle in candleArray) {
if (candle == 0) {
return false
}
}
return true
}
fun lightCandle(player: Player) {
var currentCamLoc = getAttribute(player, CANDLELIGHT_CAMERA_AT, Location(1968, 5002))
val candleIndex = CANDLE_LOC_ARRAY.indexOf(currentCamLoc)
val varbit = candleIndex + 1771 // Essentially all varbits are 1771 .. 1881
if (candleIndex != -1) {
val candleArray = getAttribute(player, CANDLELIGHT_CANDLE_ARRAY, intArrayOf(0,0,0,0,0,0,0,0,0,0,0))
if (candleArray[candleIndex] == 0) {
candleArray[candleIndex] = 1
setAttribute(player, CANDLELIGHT_CANDLE_ARRAY, candleArray)
setVarbit(player, varbit, 1)
sendMessage(player, "You light the candle.")
} else if (candleArray[candleIndex] == 1) {
sendMessage(player, "This candle is already lit.")
} else {
sendMessage(player, "This candle is too short to light.")
}
} else {
sendMessage(player, "There is nothing to light here.")
}
}
fun moveCamera(player: Player, direction: Direction, firstTime: Boolean = false) {
var currentCamLoc = getAttribute(player, CANDLELIGHT_CAMERA_AT, Location(1968, 5002))
when(direction) {
Direction.NORTH -> currentCamLoc = currentCamLoc.transform(Direction.NORTH)
Direction.SOUTH -> currentCamLoc = currentCamLoc.transform(Direction.SOUTH)
Direction.EAST -> currentCamLoc = currentCamLoc.transform(Direction.EAST)
Direction.WEST -> currentCamLoc = currentCamLoc.transform(Direction.WEST)
else -> {}
}
if (currentCamLoc.x < 1967) { currentCamLoc.x = 1967 }
if (currentCamLoc.x > 1968) { currentCamLoc.x = 1968 }
if (currentCamLoc.y < 4997) { currentCamLoc.y = 4997 }
if (currentCamLoc.y > 5007) { currentCamLoc.y = 5007 }
setAttribute(player, CANDLELIGHT_CAMERA_AT, currentCamLoc)
PlayerCamera(player).rotateTo(currentCamLoc.x - 30, currentCamLoc.y,0,200) // height is kind of a relative value?
PlayerCamera(player).panTo(currentCamLoc.x + 2, currentCamLoc.y,350, if(firstTime) 400 else 10)
}
}
override fun defineInterfaceListeners() {
on(CANDLELIGHT_INTERFACE){ player, component, opcode, buttonID, slot, itemID ->
when (buttonID) {
1 -> moveCamera(player, Direction.WEST)
2 -> moveCamera(player, Direction.EAST)
3 -> lightCandle(player)/* Light */
4 -> moveCamera(player, Direction.SOUTH)
5 -> moveCamera(player, Direction.NORTH)
9 -> closeInterface(player)
}
return@on true
}
onOpen(CANDLELIGHT_INTERFACE){ player, component ->
// Move camera
return@onOpen true
}
onClose(CANDLELIGHT_INTERFACE){ player, component ->
PlayerCamera(player).reset()
// Reset camera
return@onClose true
}
}
override fun defineListeners() {
on((11364 .. 11394).toIntArray(), SCENERY, "light") { player, node ->
setAttribute(player, CANDLELIGHT_CAMERA_AT, Location(node.location.x, node.location.y))
moveCamera(player, Direction.NORTH_WEST, true)
openInterface(player, CANDLELIGHT_INTERFACE)
return@on true
}
}
override fun defineDestinationOverrides() {
setDest(SCENERY, (11364 .. 11394).toIntArray(),"light"){ player, node ->
return@setDest Location(1970, node.location.y)
}
}
override fun defineAreaBorders(): Array<ZoneBorders> {
return arrayOf(ZoneBorders.forRegion(7758))
}
override fun getRestrictions(): Array<ZoneRestriction> {
return arrayOf(ZoneRestriction.RANDOM_EVENTS, ZoneRestriction.CANNON, ZoneRestriction.FOLLOWERS, ZoneRestriction.TELEPORT, ZoneRestriction.OFF_MAP)
}
override fun areaEnter(entity: Entity) {
if (entity is Player) {
initCandlelight(entity)
entity.interfaceManager.removeTabs(0, 1, 2, 3, 4, 5, 6, 12)
}
}
override fun areaLeave(entity: Entity, logout: Boolean) {
if (entity is Player) {
entity.interfaceManager.restoreTabs()
}
}
}

View file

@ -0,0 +1,94 @@
package content.global.ame.events.candlelight
import content.global.ame.RandomEvents
import content.global.ame.events.pillory.PilloryInterface
import content.global.ame.returnPlayer
import core.api.*
import core.game.dialogue.*
import core.game.interaction.QueueStrength
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.game.world.map.Location
import core.game.world.update.flag.context.Graphics
import core.plugin.Initializable
import core.tools.END_DIALOGUE
import org.rs09.consts.Items
import org.rs09.consts.NPCs
import org.rs09.consts.Sounds
// iface 178
@Initializable
class PiousPeteDialogue (player: Player? = null) : DialoguePlugin(player) {
override fun newInstance(player: Player): DialoguePlugin {
return PiousPeteDialogue(player)
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
openDialogue(player, PiousPeteDialogueFile(), npc)
return false
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.PIOUS_PETE_3207, NPCs._6564)
}
}
class PiousPeteDialogueFile : DialogueLabeller() {
override fun addConversation() {
npc(ChatAnim.THINKING, "Have you lit all the tall candles?")
exec { player, npc ->
if (CandlelightInterface.areCandlesLit(player)) {
loadLabel(player, "yeslit")
} else {
loadLabel(player, "nolit")
}
}
label("nolit")
player(ChatAnim.HALF_GUILTY, "Sorry, not yet.")
npc(ChatAnim.SAD, "Please help me in lighting the candles. I just need you to light all the tall candles, but not the short ones.")
line("Click on the pillars to open an interface", "to move around and light the candles.")
label("yeslit")
player(ChatAnim.FRIENDLY, "Yes, the tall ones are all lit.")
npc(ChatAnim.HAPPY, "Thank you my brother! I will now return you where you came from with a parting gift.")
npc(ChatAnim.FRIENDLY, "Take care brother!")
exec { player, npc ->
queueScript(player, 0, QueueStrength.SOFT) { stage: Int ->
when (stage) {
0 -> {
lock(player, 6)
sendGraphics(Graphics(1576, 0, 0), player.location)
animate(player,8939)
playAudio(player, Sounds.TELEPORT_ALL_200)
return@queueScript delayScript(player, 3)
}
1 -> {
returnPlayer(player)
sendGraphics(Graphics(1577, 0, 0), player.location)
animate(player,8941)
closeInterface(player)
return@queueScript delayScript(player, 3)
}
2 -> {
val loot = RandomEvents.CERTER.loot!!.roll(player)[0]
addItemOrDrop(player, loot.id, loot.amount)
return@queueScript stopExecuting(player)
}
else -> return@queueScript stopExecuting(player)
}
}
}
}
}
class PiousPeteStartingDialogueFile : DialogueLabeller() {
override fun addConversation() {
npc("I'm sorry to drag you away from your tasks, but I need a little help with something.")
player(ChatAnim.THINKING,"How can I help?")
npc("This is a chapel dedicated to our lord, Saradomin, and I'm tasked with maintaining this chapel.")
npc(ChatAnim.SAD,"My task is to light the chapel candles, but I couldn't reach them myself and I kept getting dazzled by the light whenever I tried.")
npc("So I need your help in lighting the candles. I need you to light all the tall candles, but not the short ones.")
npc(ChatAnim.FRIENDLY, "Once all the tall candles are all lit, come back and see me, and I will reward you for your work.")
}
}

View file

@ -0,0 +1,26 @@
package content.global.ame.events.candlelight
import content.global.ame.RandomEventNPC
import content.global.ame.kidnapPlayer
import core.api.*
import core.api.utils.WeightBasedTable
import core.game.node.entity.npc.NPC
import core.game.world.map.Location
import org.rs09.consts.NPCs
class PiousPeteNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.PRIEST_3206) {
override fun init() {
super.init()
// Supposed to be "I'm sorry to drag you away from your tasks, but I need a little help with something." but it's too goddamn long.
sendChat("${player.username}! I need a little help with something.")
face(player)
kidnapPlayer(this, player, Location(1972, 5002, 0)) { player, _ ->
CandlelightInterface.initCandlelight(player)
openDialogue(player, PiousPeteStartingDialogueFile(), NPC(NPCs.PIOUS_PETE_3207))
}
}
override fun talkTo(npc: NPC) {
player.dialogueInterpreter.open(PiousPeteDialogueFile(),npc)
}
}

View file

@ -2,29 +2,19 @@ package content.global.ame.events.certer
import core.game.node.entity.npc.NPC import core.game.node.entity.npc.NPC
import core.game.node.entity.player.link.emote.Emotes import core.game.node.entity.player.link.emote.Emotes
import core.tools.RandomFunction
import org.rs09.consts.NPCs import org.rs09.consts.NPCs
import content.global.ame.RandomEventNPC import content.global.ame.RandomEventNPC
import core.api.animate import core.api.animate
import core.api.lock
import core.api.utils.WeightBasedTable import core.api.utils.WeightBasedTable
class CerterNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.GILES_2538) { class CerterNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.GILES_2538) {
lateinit var pName: String
lateinit var phrases: Array<String> lateinit var phrases: Array<String>
override fun tick() { override fun tick() {
// Don't speak if we have the interface opened sayLine(this, phrases, true, true)
if (!timerPaused) { if (ticksLeft == 2) {
// Over allotted time phrase lock(player, 2)
if (ticksLeft <= 2) {
player.lock(2)
sendChat(phrases[4])
// Say a phrase every 20 ticks starting at 280 ticks
// as to not interfere with the init chat phrase
} else if (ticksLeft <= 280 && ticksLeft % 20 == 0) {
sendChat(phrases[RandomFunction.random(1, 3)])
}
} }
super.tick() super.tick()
} }
@ -36,15 +26,20 @@ class CerterNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NP
override fun init() { override fun init() {
super.init() super.init()
pName = player.username.capitalize() phrases = arrayOf(
phrases = arrayOf("Greetings $pName, I need your help.", "Greetings ${player.username}, I need your help.",
"ehem... Hello $pName, please talk to me!", "ehem... Hello ${player.username}, please talk to me!",
"Hello, are you there $pName?", "Hello, are you there ${player.username}?",
"It's really rude to ignore someone, $pName!", "It's really rude to ignore someone, ${player.username}!",
"No-one ignores me!") "No-one ignores me!"
)
player.setAttribute("random:pause", false) player.setAttribute("random:pause", false)
player.setAttribute("certer:reward", false) player.setAttribute("certer:reward", false)
sendChat(phrases[0])
animate(this, Emotes.BOW.animation, true) animate(this, Emotes.BOW.animation, true)
} }
override fun onTimeUp() {
noteAndTeleport()
terminate()
}
} }

View file

@ -1,12 +1,9 @@
package content.global.ame.events.drilldemon package content.global.ame.events.drilldemon
import content.global.ame.kidnapPlayer
import content.global.ame.returnPlayer import content.global.ame.returnPlayer
import core.api.* import core.api.*
import core.game.interaction.QueueStrength import core.game.interaction.QueueStrength
import core.game.node.entity.player.Player import core.game.node.entity.player.Player
import core.game.node.entity.player.link.TeleportManager
import core.game.world.map.Location
import core.game.world.map.zone.ZoneBorders import core.game.world.map.zone.ZoneBorders
import core.game.world.update.flag.context.Animation import core.game.world.update.flag.context.Animation
import org.rs09.consts.Items import org.rs09.consts.Items
@ -24,13 +21,6 @@ object DrillDemonUtils {
val DD_AREA = ZoneBorders(3158, 4817, 3168, 4823) val DD_AREA = ZoneBorders(3158, 4817, 3168, 4823)
val DD_NPC = NPCs.SERGEANT_DAMIEN_2790 val DD_NPC = NPCs.SERGEANT_DAMIEN_2790
fun teleport(player: Player) {
kidnapPlayer(player, Location.create(3163, 4819, 0), TeleportManager.TeleportType.INSTANT)
player.interfaceManager.closeDefaultTabs()
setComponentVisibility(player, 548, 69, true)
setComponentVisibility(player, 746, 12, true)
}
fun changeSignsAndAssignTask(player: Player) { fun changeSignsAndAssignTask(player: Player) {
setVarp(player, DD_SIGN_VARP, 0) setVarp(player, DD_SIGN_VARP, 0)
val tempList = arrayListOf(DD_SIGN_JOG, DD_SIGN_JUMP, DD_SIGN_PUSHUP, DD_SIGN_SITUP).shuffled().toMutableList() val tempList = arrayListOf(DD_SIGN_JOG, DD_SIGN_JUMP, DD_SIGN_PUSHUP, DD_SIGN_SITUP).shuffled().toMutableList()
@ -94,6 +84,5 @@ object DrillDemonUtils {
} }
return@queueScript stopExecuting(player) return@queueScript stopExecuting(player)
} }
} }
} }

View file

@ -3,32 +3,22 @@ package content.global.ame.events.drilldemon
import core.game.node.entity.npc.NPC import core.game.node.entity.npc.NPC
import org.rs09.consts.NPCs import org.rs09.consts.NPCs
import content.global.ame.RandomEventNPC import content.global.ame.RandomEventNPC
import content.global.ame.kidnapPlayer
import core.api.* import core.api.*
import core.api.utils.WeightBasedTable import core.api.utils.WeightBasedTable
import core.game.interaction.QueueStrength import core.game.world.map.Location
import core.game.system.timer.impl.AntiMacro
import core.tools.secondsToTicks
class SergeantDamienNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.SERGEANT_DAMIEN_2790) { class SergeantDamienNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.SERGEANT_DAMIEN_2790) {
override fun init() { override fun init() {
super.init() super.init()
sendChat(player.username+ "! Drop and give me 20!") sendChat("${player.username}! Drop and give me 20!")
queueScript(player, 4, QueueStrength.SOFT) { stage: Int -> face(player)
when (stage) { kidnapPlayer(this, player, Location(3163, 4819, 0)) { player, _ ->
0 -> { player.interfaceManager.closeDefaultTabs()
lock(player, secondsToTicks(30)) setComponentVisibility(player, 548, 69, true)
DrillDemonUtils.teleport(player) setComponentVisibility(player, 746, 12, true)
AntiMacro.terminateEventNpc(player) openDialogue(player, SeargentDamienDialogue(isCorrect = true, eventStart = true), NPCs.SERGEANT_DAMIEN_2790)
return@queueScript delayScript(player, 2)
}
1 -> {
openDialogue(player, SeargentDamienDialogue(isCorrect = true, eventStart = true), NPCs.SERGEANT_DAMIEN_2790)
return@queueScript stopExecuting(player)
}
else -> return@queueScript stopExecuting(player)
}
} }
} }

View file

@ -9,35 +9,27 @@ import org.rs09.consts.NPCs
import org.rs09.consts.Sounds import org.rs09.consts.Sounds
class DrunkenDwarfNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.DRUNKEN_DWARF_956) { class DrunkenDwarfNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.DRUNKEN_DWARF_956) {
private val phrases = arrayOf("Oi, are you der @name!","Dunt ignore your matey!","Aww comeon, talk to ikle me @name!") lateinit var phrases: Array<String>
private var attackPhrase = false
private var attackDelay = 0 private var attackDelay = 0
private var lastPhraseTime = 0
private fun sendPhrases() {
if (getWorldTicks() > lastPhraseTime + 5) {
playGlobalAudio(this.location, Sounds.DWARF_WHISTLE_2297)
sendChat(this, phrases.random().replace("@name",player.username.capitalize()))
this.face(player)
lastPhraseTime = getWorldTicks()
}
}
override fun init() { override fun init() {
super.init() super.init()
playGlobalAudio(this.location, Sounds.DWARF_WHISTLE_2297) phrases = arrayOf(
sendChat(this, "'Ello der ${player.username.capitalize()}! *hic*") "'Ello der ${player.username}! *hic*",
"Oi, are you der ${player.username}!",
"Dunt ignore your matey!",
"Aww comeon, talk to ikle me ${player.username}!",
"I hates you, ${player.username}!"
)
} }
override fun tick() { override fun tick() {
if (RandomFunction.roll(20) && !attackPhrase) sayLine(this, phrases, true, true)
sendPhrases()
if (ticksLeft <= 10) { if (ticksLeft <= 10) {
ticksLeft = 10 ticksLeft = 10
if (!attackPhrase) if (attackDelay <= getWorldTicks()) {
sendChat("I hates you, ${player.username.capitalize()}!").also { attackPhrase = true }
if (attackDelay <= getWorldTicks())
this.attack(player) this.attack(player)
}
} }
super.tick() super.tick()
} }
@ -47,4 +39,10 @@ class DrunkenDwarfNPC(override var loot: WeightBasedTable? = null) : RandomEvent
this.pulseManager.clear() this.pulseManager.clear()
openDialogue(player, DrunkenDwarfDialogue(), this.asNpc()) openDialogue(player, DrunkenDwarfDialogue(), this.asNpc())
} }
override fun onTimeUp() {
if (attackDelay <= getWorldTicks()) {
this.attack(player)
}
}
} }

View file

@ -1,40 +1,22 @@
package content.global.ame.events.evilbob package content.global.ame.events.evilbob
import content.global.ame.RandomEventNPC import content.global.ame.RandomEventNPC
import content.global.ame.kidnapPlayer
import core.api.* import core.api.*
import core.api.utils.WeightBasedTable import core.api.utils.WeightBasedTable
import core.game.interaction.QueueStrength
import core.game.node.entity.npc.NPC import core.game.node.entity.npc.NPC
import core.game.system.timer.impl.AntiMacro import core.game.world.map.Location
import org.rs09.consts.NPCs import org.rs09.consts.NPCs
import org.rs09.consts.Sounds
class EvilBobNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.EVIL_BOB_2478) { class EvilBobNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.EVIL_BOB_2478) {
override fun init() { override fun init() {
super.init() super.init()
sendChat("meow") sendChat("meow")
queueScript(player, 4, QueueStrength.SOFT) { stage: Int -> face(player)
when (stage) { kidnapPlayer(this, player, Location(3419, 4776, 0), "No... what? Nooooooooooooo!") { player, _ ->
0 -> { EvilBobUtils.giveEventFishingSpot(player)
lock(player, 6) sendMessage(player, "Welcome to Scape2009.")
sendChat(player, "No... what? Nooooooooooooo!") openDialogue(player, EvilBobDialogue(), NPCs.EVIL_BOB_2479)
animate(player, EvilBobUtils.teleAnim)
player.graphics(EvilBobUtils.telegfx)
playAudio(player, Sounds.TELEPORT_ALL_200)
EvilBobUtils.giveEventFishingSpot(player)
return@queueScript delayScript(player, 3)
}
1 -> {
sendMessage(player, "Welcome to Scape2009.")
EvilBobUtils.teleport(player)
resetAnimator(player)
openDialogue(player, EvilBobDialogue(), NPCs.EVIL_BOB_2479)
AntiMacro.terminateEventNpc(player)
return@queueScript stopExecuting(player)
}
else -> return@queueScript stopExecuting(player)
}
} }
} }

View file

@ -1,12 +1,8 @@
package content.global.ame.events.evilbob package content.global.ame.events.evilbob
import content.global.ame.kidnapPlayer
import content.global.ame.returnPlayer
import core.api.* import core.api.*
import core.game.node.entity.player.Player import core.game.node.entity.player.Player
import core.game.node.entity.player.link.TeleportManager
import core.game.node.entity.skill.Skills import core.game.node.entity.skill.Skills
import core.game.world.map.Location
import core.game.world.map.zone.ZoneBorders import core.game.world.map.zone.ZoneBorders
import core.game.world.update.flag.context.Animation import core.game.world.update.flag.context.Animation
import core.game.world.update.flag.context.Graphics import core.game.world.update.flag.context.Graphics
@ -53,10 +49,6 @@ object EvilBobUtils {
} }
} }
fun teleport(player: Player) {
kidnapPlayer(player, Location.create(3419, 4776, 0), TeleportManager.TeleportType.INSTANT)
}
fun cleanup(player: Player) { fun cleanup(player: Player) {
removeAttributes(player, assignedFishingZone, eventComplete, attentive, servantHelpDialogueSeen, attentiveNewSpot, startingDialogueSeen) removeAttributes(player, assignedFishingZone, eventComplete, attentive, servantHelpDialogueSeen, attentiveNewSpot, startingDialogueSeen)
removeAll(player, Items.FISHLIKE_THING_6202) removeAll(player, Items.FISHLIKE_THING_6202)

View file

@ -3,38 +3,47 @@ package content.global.ame.events.evilbob
import core.api.* import core.api.*
import core.game.activity.Cutscene import core.game.activity.Cutscene
import core.game.node.entity.player.Player import core.game.node.entity.player.Player
import core.game.world.map.Direction
class ServantCutsceneN(player: Player) : Cutscene(player) { class ServantCutsceneN(player: Player) : Cutscene(player) {
override fun setup() { override fun setup() {
setExit(player.location.transform(0, 0, 0)) setExit(player.location.transform(0, 0, 0))
loadRegion(13642) loadRegion(13642)
addNPC(2479, 28, 41, Direction.SOUTH) // Evil Bob
addNPC(2481, 31, 41, Direction.SOUTH_WEST) // Servant
} }
override fun runStage(stage: Int) { override fun runStage(stage: Int) {
when (stage) { when (stage) {
0 -> { 0 -> {
fadeToBlack() teleport(player, 30, 41)
timedUpdate(4) moveCamera(30, 37, 400, 255)
rotateCamera(30, 50, 400, 255)
openInterface(player, 186)
timedUpdate(0)
} }
1 -> { 1 -> {
teleport(player, 29, 41) timedUpdate(0)
moveCamera(30, 43) // +7 from statue }
openInterface(player, 186) 2 -> { // Slow start
moveCamera(30, 49, 400, 2)
timedUpdate(2) timedUpdate(2)
} }
2 -> { 3 -> { // Fast middle
moveCamera(30, 44, 380, 4)
timedUpdate(6)
}
4 -> { // Slow end
moveCamera(30, 45, 340, 2)
timedUpdate(2) timedUpdate(2)
rotateCamera(30, 51, 300, 100) // the statue loc
fadeFromBlack()
} }
3 -> { 5 -> {
timedUpdate(9) timedUpdate(2)
moveCamera(30, 46, 300, 2) // +4 from statue
} }
4 -> { 6 -> {
end{ player.locks.lockTeleport(1000000) }
closeInterface(player) closeInterface(player)
end(fade = false) { player.locks.lockTeleport(1000000) }
} }
} }
} }
@ -45,32 +54,40 @@ class ServantCutsceneS(player: Player) : Cutscene(player) {
override fun setup() { override fun setup() {
setExit(player.location.transform(0, 0, 0)) setExit(player.location.transform(0, 0, 0))
loadRegion(13642) loadRegion(13642)
addNPC(2479, 28, 41, Direction.SOUTH) // Evil Bob
addNPC(2481, 31, 41, Direction.SOUTH_WEST) // Servant
} }
override fun runStage(stage: Int) { override fun runStage(stage: Int) {
when (stage) { when (stage) {
0 -> { 0 -> {
fadeToBlack() teleport(player, 30, 41)
timedUpdate(4) moveCamera(31, 46, 365, 255)
rotateCamera(29, 30, 365, 255)
openInterface(player, 186)
timedUpdate(0)
} }
1 -> { 1 -> {
teleport(player, 29, 41) timedUpdate(0)
moveCamera(29, 38) // +7 from statue
openInterface(player, 186)
timedUpdate(2)
} }
2 -> { 2 -> {
moveCamera(31, 43, 480, 2)
timedUpdate(2) timedUpdate(2)
rotateCamera(29, 30, 300, 100) // the statue loc
fadeFromBlack()
} }
3 -> { 3 -> {
timedUpdate(9) moveCamera(31, 37, 455, 4)
moveCamera(29, 35, 300, 2) // +4 from statue timedUpdate(8)
} }
4 -> { 4 -> {
end{ player.locks.lockTeleport(1000000) } moveCamera(31, 36, 395, 2)
timedUpdate(2)
}
5 -> {
timedUpdate(3)
}
6 -> {
closeInterface(player) closeInterface(player)
end(fade = false) { player.locks.lockTeleport(1000000) }
} }
} }
} }
@ -81,32 +98,40 @@ class ServantCutsceneE(player: Player) : Cutscene(player) {
override fun setup() { override fun setup() {
setExit(player.location.transform(0, 0, 0)) setExit(player.location.transform(0, 0, 0))
loadRegion(13642) loadRegion(13642)
addNPC(2479, 28, 41, Direction.SOUTH) // Evil Bob
addNPC(2481, 31, 41, Direction.SOUTH_WEST) // Servant
} }
override fun runStage(stage: Int) { override fun runStage(stage: Int) {
when (stage) { when (stage) {
0 -> { 0 -> {
fadeToBlack() teleport(player, 30, 41)
timedUpdate(4) moveCamera(25, 41, 440, 255)
rotateCamera(42, 41, 440, 255)
openInterface(player, 186)
timedUpdate(0)
} }
1 -> { 1 -> {
teleport(player, 29, 41) timedUpdate(0)
moveCamera(35, 41) // +7 from statue }
openInterface(player, 186) 2 -> { // Slow start
moveCamera(28, 41, 500, 3)
timedUpdate(2) timedUpdate(2)
} }
2 -> { 3 -> { // Fast middle
moveCamera(34, 41, 390, 5)
timedUpdate(6)
}
4 -> { // Slow end
moveCamera(36, 41, 340, 2)
timedUpdate(2) timedUpdate(2)
rotateCamera(43, 41, 300, 100) // the statue loc
fadeFromBlack()
} }
3 -> { 5 -> {
timedUpdate(9) timedUpdate(4)
moveCamera(38, 41, 300, 2) // +4 from statue
} }
4 -> { 6 -> {
end{ player.locks.lockTeleport(1000000) }
closeInterface(player) closeInterface(player)
end(fade = false) { player.locks.lockTeleport(1000000) }
} }
} }
} }
@ -117,34 +142,41 @@ class ServantCutsceneW(player: Player) : Cutscene(player) {
override fun setup() { override fun setup() {
setExit(player.location.transform(0, 0, 0)) setExit(player.location.transform(0, 0, 0))
loadRegion(13642) loadRegion(13642)
addNPC(2479, 28, 41, Direction.SOUTH) // Evil Bob
addNPC(2481, 31, 41, Direction.SOUTH_WEST) // Servant
} }
override fun runStage(stage: Int) { override fun runStage(stage: Int) {
when (stage) { when (stage) {
0 -> { 0 -> {
fadeToBlack() teleport(player, 30, 41)
timedUpdate(4) moveCamera(34, 41, 325, 255)
rotateCamera(16, 40, 300, 255)
openInterface(player, 186)
timedUpdate(0)
} }
1 -> { 1 -> {
teleport(player, 29, 41) timedUpdate(0)
moveCamera(25, 40) // +7 from statue }
openInterface(player, 186) 2 -> { // Slow start
moveCamera(31, 41, 440, 3)
timedUpdate(2) timedUpdate(2)
} }
2 -> { 3 -> { // Fast middle
moveCamera(24, 41, 330, 5)
timedUpdate(7)
}
4 -> { // Slow end
moveCamera(23, 41, 300, 2)
timedUpdate(2) timedUpdate(2)
rotateCamera(18, 40, 300, 100) // the statue loc
fadeFromBlack()
} }
3 -> { 5 -> {
timedUpdate(9) timedUpdate(3)
moveCamera(22, 40, 300, 2) // +4 from statue
} }
4 -> { 6 -> {
end{ player.locks.lockTeleport(1000000) }
closeInterface(player) closeInterface(player)
end(fade = false) { player.locks.lockTeleport(1000000) }
} }
} }
} }
} }

View file

@ -1,13 +1,10 @@
package content.global.ame.events.freakyforester package content.global.ame.events.freakyforester
import content.global.ame.kidnapPlayer
import content.global.ame.returnPlayer import content.global.ame.returnPlayer
import core.api.* import core.api.*
import org.rs09.consts.Items import org.rs09.consts.Items
import org.rs09.consts.NPCs import org.rs09.consts.NPCs
import core.game.node.entity.player.Player import core.game.node.entity.player.Player
import core.game.node.entity.player.link.TeleportManager
import core.game.world.map.Location
import core.game.world.map.zone.ZoneBorders import core.game.world.map.zone.ZoneBorders
import core.tools.RandomFunction import core.tools.RandomFunction
@ -28,10 +25,6 @@ object FreakUtils{
player.dialogueInterpreter.open(FreakyForesterDialogue(), freakNpc) player.dialogueInterpreter.open(FreakyForesterDialogue(), freakNpc)
} }
fun teleport(player: Player) {
kidnapPlayer(player, Location.create(2599, 4777 ,0), TeleportManager.TeleportType.INSTANT)
}
fun cleanup(player: Player) { fun cleanup(player: Player) {
returnPlayer(player) returnPlayer(player)
removeAttributes(player, freakTask, freakComplete, pheasantKilled) removeAttributes(player, freakTask, freakComplete, pheasantKilled)

View file

@ -1,39 +1,21 @@
package content.global.ame.events.freakyforester package content.global.ame.events.freakyforester
import content.global.ame.RandomEventNPC import content.global.ame.RandomEventNPC
import content.global.ame.kidnapPlayer
import core.api.* import core.api.*
import org.rs09.consts.NPCs import org.rs09.consts.NPCs
import core.api.utils.WeightBasedTable import core.api.utils.WeightBasedTable
import core.game.interaction.QueueStrength
import core.game.node.entity.npc.NPC import core.game.node.entity.npc.NPC
import core.game.system.timer.impl.AntiMacro import core.game.world.map.Location
import core.game.world.update.flag.context.Graphics
import org.rs09.consts.Sounds
class FreakyForesterNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.FREAKY_FORESTER_2458) { class FreakyForesterNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.FREAKY_FORESTER_2458) {
override fun init() { override fun init() {
super.init() super.init()
sendChat("Ah, ${player.username}, just the person I need!") sendChat("Ah, ${player.username}, just the person I need!")
queueScript(player, 4, QueueStrength.SOFT) { stage: Int -> face(player)
when (stage) { kidnapPlayer(this, player, Location(2599, 4777, 0)) { player, _ ->
0 -> { FreakUtils.giveFreakTask(player)
lock(player, 6) openDialogue(player, FreakyForesterDialogue(), FreakUtils.freakNpc)
sendGraphics(Graphics(308, 100, 50), player.location)
animate(player,714)
playAudio(player, Sounds.TELEPORT_ALL_200)
return@queueScript delayScript(player, 3)
}
1 -> {
FreakUtils.teleport(player)
FreakUtils.giveFreakTask(player)
AntiMacro.terminateEventNpc(player)
openDialogue(player, FreakyForesterDialogue(), FreakUtils.freakNpc)
resetAnimator(player)
return@queueScript stopExecuting(player)
}
else -> return@queueScript stopExecuting(player)
}
} }
} }

View file

@ -4,27 +4,40 @@ import core.game.node.entity.npc.NPC
import core.tools.RandomFunction import core.tools.RandomFunction
import org.rs09.consts.NPCs import org.rs09.consts.NPCs
import content.global.ame.RandomEventNPC import content.global.ame.RandomEventNPC
import core.api.lock
import core.api.playAudio import core.api.playAudio
import core.api.utils.WeightBasedTable import core.api.utils.WeightBasedTable
import org.rs09.consts.Sounds import org.rs09.consts.Sounds
class GenieNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.GENIE_409) { class GenieNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.GENIE_409) {
val phrases = arrayOf("Greetings, @name!","Ehem... Master @name?","Are you there, Master @name?","No one ignores me!") lateinit var phrases: Array<String>
override fun tick() { override fun tick() {
if(RandomFunction.random(1,15) == 5){ sayLine(this, phrases, true, true)
sendChat(phrases.random().replace("@name",player.username.capitalize())) if (ticksLeft == 2) {
lock(player, 2)
} }
super.tick() super.tick()
} }
override fun init() { override fun init() {
super.init() super.init()
val honorific = if (player.isMale) "Master" else "Mistress"
phrases = arrayOf(
"Greetings, ${player.username}!",
"Ehem... $honorific ${player.username}?",
"Are you there, $honorific ${player.username}?",
"No one ignores me!"
)
playAudio(player, Sounds.GENIE_APPEAR_2301) playAudio(player, Sounds.GENIE_APPEAR_2301)
sendChat(phrases.random().replace("@name",player.username.capitalize()))
} }
override fun talkTo(npc: NPC) { override fun talkTo(npc: NPC) {
player.dialogueInterpreter.open(GenieDialogue(),npc) player.dialogueInterpreter.open(GenieDialogue(),npc)
} }
override fun onTimeUp() {
noteAndTeleport()
terminate()
}
} }

View file

@ -160,7 +160,7 @@ class MazeInterface : InteractionListener, EventHook<TickEvent>, MapArea {
animate(player, 536) animate(player, 536)
// val actualScenery = RegionManager.getObject(node.location.z, node.location.x, node.location.y, 3626) // val actualScenery = RegionManager.getObject(node.location.z, node.location.x, node.location.y, 3626)
val tableRoll = CHEST_REWARDS.roll() val tableRoll = CHEST_REWARDS.roll()
addItemOrBank(player, tableRoll[0].id) addItemOrBank(player, tableRoll[0].id, tableRoll[0].amount)
when (tableRoll[0].id){ when (tableRoll[0].id){
Items.AIR_RUNE_556 -> sendItemDialogue(player, Items.AIR_RUNE_556, "You've found some air runes!") Items.AIR_RUNE_556 -> sendItemDialogue(player, Items.AIR_RUNE_556, "You've found some air runes!")
Items.WATER_RUNE_555 -> sendItemDialogue(player, Items.WATER_RUNE_555, "You've found some water runes!") Items.WATER_RUNE_555 -> sendItemDialogue(player, Items.WATER_RUNE_555, "You've found some water runes!")
@ -199,17 +199,16 @@ class MazeInterface : InteractionListener, EventHook<TickEvent>, MapArea {
on(Scenery.STRANGE_SHRINE_3634, IntType.SCENERY, "touch") { player, node -> on(Scenery.STRANGE_SHRINE_3634, IntType.SCENERY, "touch") { player, node ->
player.unhook(this) player.unhook(this)
lock(player, 12)
closeOverlay(player) closeOverlay(player)
queueScript(player, 0, QueueStrength.SOFT) { stage: Int -> queueScript(player, 0, QueueStrength.SOFT) { stage: Int ->
when (stage) { when (stage) {
0 -> { 0 -> {
lock(player, 6)
sendGraphics(Graphics(86, 0, 3), player.location) sendGraphics(Graphics(86, 0, 3), player.location)
animate(player,862) animate(player,862)
return@queueScript delayScript(player, 6) return@queueScript delayScript(player, 6)
} }
1 -> { 1 -> {
lock(player, 6)
sendGraphics(Graphics(1576, 0, 0), player.location) sendGraphics(Graphics(1576, 0, 0), player.location)
animate(player,8939) animate(player,8939)
playAudio(player, Sounds.TELEPORT_ALL_200) playAudio(player, Sounds.TELEPORT_ALL_200)

View file

@ -4,54 +4,29 @@ import content.global.ame.RandomEventNPC
import content.global.ame.kidnapPlayer import content.global.ame.kidnapPlayer
import core.api.* import core.api.*
import core.api.utils.WeightBasedTable import core.api.utils.WeightBasedTable
import core.game.interaction.QueueStrength
import core.game.node.entity.npc.NPC import core.game.node.entity.npc.NPC
import core.game.node.entity.player.link.TeleportManager
import core.game.system.timer.impl.AntiMacro
import core.game.world.map.Location
import core.game.world.map.build.DynamicRegion
import core.game.world.update.flag.context.Graphics
import org.rs09.consts.NPCs import org.rs09.consts.NPCs
import org.rs09.consts.Sounds
class MazeNPC(var type: String = "", override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.MYSTERIOUS_OLD_MAN_410) { class MazeNPC(var type: String = "", override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.MYSTERIOUS_OLD_MAN_410) {
override fun init() { override fun init() {
super.init() super.init()
sendChat("Aha, you'll do ${player.username}!") sendChat("Aha, you'll do ${player.username}!")
face(player) face(player)
queueScript(player, 4, QueueStrength.SOFT) { stage: Int -> // Note: This event is NOT instanced:
when (stage) { // Sources:
0 -> { // https://youtu.be/2gpzn9oNdy0 (2007)
lock(player, 6) // https://youtu.be/Tni1HURgnxg (2008)
sendGraphics(Graphics(1576, 0, 0), player.location) // https://youtu.be/igdwDZOv9LU (2008)
animate(player,8939) // https://youtu.be/0oBCkLArUmc (2011 - even with personal Mysterious Old Man) - "Sorry, this is not the old man you are looking for."
playAudio(player, Sounds.TELEPORT_ALL_200) // https://youtu.be/FMuKZm-Ikgs (2011)
return@queueScript delayScript(player, 3) // val region = DynamicRegion.create(11591)
} kidnapPlayer(this, player, MazeInterface.STARTING_POINTS.random()) { player, _ ->
1 -> { MazeInterface.initMaze(player)
MazeInterface.initMaze(player) removeAttribute(player, MazeInterface.MAZE_ATTRIBUTE_CHESTS_OPEN)
// Note: This event is NOT instanced:
// Sources:
// https://youtu.be/2gpzn9oNdy0 (2007)
// https://youtu.be/Tni1HURgnxg (2008)
// https://youtu.be/igdwDZOv9LU (2008)
// https://youtu.be/0oBCkLArUmc (2011 - even with personal Mysterious Old Man) - "Sorry, this is not the old man you are looking for."
// https://youtu.be/FMuKZm-Ikgs (2011)
// val region = DynamicRegion.create(11591)
kidnapPlayer(player, MazeInterface.STARTING_POINTS.random(), TeleportManager.TeleportType.INSTANT) // 10 random spots
AntiMacro.terminateEventNpc(player)
sendGraphics(Graphics(1577, 0, 0), player.location)
animate(player,8941)
removeAttribute(player, MazeInterface.MAZE_ATTRIBUTE_CHESTS_OPEN)
return@queueScript stopExecuting(player)
}
else -> return@queueScript stopExecuting(player)
}
} }
} }
override fun talkTo(npc: NPC) { override fun talkTo(npc: NPC) {
// Do nothing. sendMessage(player, "He isn't interested in talking to you.")
} }
} }

View file

@ -4,47 +4,22 @@ import content.global.ame.RandomEventNPC
import content.global.ame.kidnapPlayer import content.global.ame.kidnapPlayer
import core.api.* import core.api.*
import core.api.utils.WeightBasedTable import core.api.utils.WeightBasedTable
import core.game.interaction.QueueStrength import core.game.component.Component.setUnclosable
import core.game.node.entity.npc.NPC import core.game.node.entity.npc.NPC
import core.game.node.entity.player.link.TeleportManager
import core.game.system.timer.impl.AntiMacro
import core.game.world.map.Location
import core.game.world.update.flag.context.Graphics
import org.rs09.consts.NPCs import org.rs09.consts.NPCs
import org.rs09.consts.Sounds
// "::revent [-p] <lt>player name<gt> [-e <lt>event name<gt>]"
class PilloryNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.PILLORY_GUARD_2791) { class PilloryNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.PILLORY_GUARD_2791) {
override fun init() { override fun init() {
super.init() super.init()
sendChat("${player.username}, you're under arrest!") sendChat("${player.username}, you're under arrest!")
face(player) face(player)
player.dialogueInterpreter.sendPlainMessage(true, "", "Solve the pillory puzzle to be returned to where you came from.") kidnapPlayer(this, player, PilloryInterface.LOCATIONS.random()) { player, _ ->
queueScript(player, 4, QueueStrength.SOFT) { stage: Int -> PilloryInterface.initPillory(player)
when (stage) { setUnclosable(player, player.dialogueInterpreter.sendPlainMessage(true, "", "Solve the pillory puzzle to be returned to where you came from."))
0 -> {
lock(player, 6)
sendGraphics(Graphics(1576, 0, 0), player.location)
animate(player,8939)
playAudio(player, Sounds.TELEPORT_ALL_200)
return@queueScript delayScript(player, 3)
}
1 -> {
PilloryInterface.initPillory(player)
val dest = PilloryInterface.LOCATIONS.random() //9 random spots!
kidnapPlayer(player, dest, TeleportManager.TeleportType.INSTANT)
AntiMacro.terminateEventNpc(player)
sendGraphics(Graphics(1577, 0, 0), player.location)
animate(player,8941)
return@queueScript stopExecuting(player)
}
else -> return@queueScript stopExecuting(player)
}
} }
} }
override fun talkTo(npc: NPC) { override fun talkTo(npc: NPC) {
//player.dialogueInterpreter.open(FreakyForesterDialogue(),npc) sendMessage(player, "He isn't interested in talking to you.")
} }
} }

View file

@ -5,15 +5,17 @@ import core.ServerConstants
import core.api.* import core.api.*
import core.api.utils.WeightBasedTable import core.api.utils.WeightBasedTable
import core.api.utils.WeightedItem import core.api.utils.WeightedItem
import core.game.dialogue.DialogueFile import core.game.component.Component
import core.game.dialogue.DialogueLabeller
import core.game.dialogue.DialogueOption
import core.game.dialogue.FacialExpression import core.game.dialogue.FacialExpression
import core.game.interaction.QueueStrength import core.game.interaction.QueueStrength
import core.game.node.entity.player.Player import core.game.node.entity.player.Player
import core.tools.END_DIALOGUE
import org.rs09.consts.Components import org.rs09.consts.Components
import org.rs09.consts.Items import org.rs09.consts.Items
import org.rs09.consts.NPCs
class QuizMasterDialogueFile : DialogueFile() { class QuizMasterDialogueFile : DialogueLabeller() {
companion object { companion object {
const val QUIZMASTER_INTERFACE = Components.MACRO_QUIZSHOW_191 const val QUIZMASTER_INTERFACE = Components.MACRO_QUIZSHOW_191
const val QUIZMASTER_ATTRIBUTE_QUESTIONS_CORRECT = "/save:quizmaster:questions-correct" const val QUIZMASTER_ATTRIBUTE_QUESTIONS_CORRECT = "/save:quizmaster:questions-correct"
@ -58,7 +60,7 @@ class QuizMasterDialogueFile : DialogueFile() {
// Random Item should be "Mystery Box", but the current MYSTERY_BOX_6199 is already inauthentically used by Giftmas. // Random Item should be "Mystery Box", but the current MYSTERY_BOX_6199 is already inauthentically used by Giftmas.
val tableRoll = WeightBasedTable.create( val tableRoll = WeightBasedTable.create(
WeightedItem(Items.LAMP_6796, 1, 1, 1.0, false), WeightedItem(Items.LAMP_2528, 1, 1, 1.0, false),
WeightedItem(Items.CABBAGE_1965, 1, 1, 1.0, false), WeightedItem(Items.CABBAGE_1965, 1, 1, 1.0, false),
WeightedItem(Items.DIAMOND_1601, 1, 1, 1.0, false), WeightedItem(Items.DIAMOND_1601, 1, 1, 1.0, false),
WeightedItem(Items.BUCKET_1925, 1, 1, 1.0, false), WeightedItem(Items.BUCKET_1925, 1, 1, 1.0, false),
@ -74,56 +76,77 @@ class QuizMasterDialogueFile : DialogueFile() {
} }
override fun handle(componentID: Int, buttonID: Int) { override fun addConversation() {
when (stage) { assignToIds(NPCs.QUIZ_MASTER_2477)
0 -> npc(FacialExpression.FRIENDLY,"WELCOME to the GREATEST QUIZ SHOW in the", "whole of ${ServerConstants.SERVER_NAME}:", "<col=8A0808>O D D</col> <col=8A088A>O N E</col> <col=08088A>O U T</col>").also { stage++ } afterClose { player ->
1 -> player(FacialExpression.THINKING, "I'm sure I didn't ask to take part in a quiz show...").also { stage++ } loadLabel(player, "question")
2 -> npc(FacialExpression.FRIENDLY,"Please welcome our newest contestant:", "<col=FF0000>${player?.username}</col>!", "Just pick the O D D O N E O U T.", "Four questions right, and then you win!").also { stage++ } }
3 -> {
setAttribute(player!!, QUIZMASTER_ATTRIBUTE_RANDOM_ANSWER, randomQuestion(player!!)) npc(FacialExpression.FRIENDLY,"WELCOME to the GREATEST QUIZ SHOW in the", "whole of ${ServerConstants.SERVER_NAME}:", "<col=8A0808>O D D</col> <col=8A088A>O N E</col> <col=08088A>O U T</col>", unclosable = true)
player!!.interfaceManager.openChatbox(QUIZMASTER_INTERFACE) player(FacialExpression.THINKING, "I'm sure I didn't ask to take part in a quiz show...", unclosable = true)
stage++ npc(FacialExpression.FRIENDLY,"Please welcome our newest contestant:", "<col=FF0000>${player?.username}</col>!", "Just pick the O D D O N E O U T.", "Four questions right, and then you win!", unclosable = true)
} goto("question")
4-> {
if (buttonID == getAttribute(player!!, QUIZMASTER_ATTRIBUTE_RANDOM_ANSWER, 0)) { label("question")
// Correct Answer manual(unclosable = true) { player, _ ->
setAttribute(player!!, QUIZMASTER_ATTRIBUTE_QUESTIONS_CORRECT, getAttribute(player!!, QUIZMASTER_ATTRIBUTE_QUESTIONS_CORRECT, 0) + 1) setAttribute(player, QUIZMASTER_ATTRIBUTE_RANDOM_ANSWER, randomQuestion(player))
if (getAttribute(player!!, QUIZMASTER_ATTRIBUTE_QUESTIONS_CORRECT, 0) >= 4) { val comp = Component(QUIZMASTER_INTERFACE)
npc(FacialExpression.FRIENDLY,"<col=08088A>CONGRATULATIONS!</col>", "You are a <col=8A0808>WINNER</col>!", "Please choose your <col=08088A>PRIZE</col>!") player.interfaceManager.openChatbox(comp)
stage = 5 return@manual comp
} else { }
npc(FacialExpression.FRIENDLY,"Wow, you're a smart one!", "You're absolutely RIGHT!", "Okay, next question!") exec { player, _ ->
stage = 3 if (buttonID == getAttribute(player, QUIZMASTER_ATTRIBUTE_RANDOM_ANSWER, 0)) {
} // Correct Answer
setAttribute(player, QUIZMASTER_ATTRIBUTE_QUESTIONS_CORRECT, getAttribute(player, QUIZMASTER_ATTRIBUTE_QUESTIONS_CORRECT, 0) + 1)
if (getAttribute(player, QUIZMASTER_ATTRIBUTE_QUESTIONS_CORRECT, 0) >= 4) {
goto("winner")
} else { } else {
// Wrong Answer goto("right")
npc(FacialExpression.FRIENDLY,"WRONG!", "That's just WRONG!", "Okay, next question!")
stage = 3
} }
} } else {
// Random Item should be "Mystery Box", but the current MYSTERY_BOX_6199 is already inauthentically used by Giftmas. goto("wrong")
5 -> options("1000 Coins", "Random Item").also { stage++ }
6 -> {
resetAnimator(player!!)
returnPlayer(player!!)
when (buttonID) {
1 -> {
queueScript(player!!, 0, QueueStrength.SOFT) { stage: Int ->
addItemOrDrop(player!!, Items.COINS_995, 1000)
return@queueScript stopExecuting(player!!)
}
}
2 -> {
queueScript(player!!, 0, QueueStrength.SOFT) { stage: Int ->
addItemOrDrop(player!!, tableRoll.roll()[0].id)
return@queueScript stopExecuting(player!!)
}
}
}
removeAttributes(player!!, QUIZMASTER_ATTRIBUTE_QUESTIONS_CORRECT, QUIZMASTER_ATTRIBUTE_RANDOM_ANSWER)
stage = END_DIALOGUE
end()
} }
} }
label("right")
npc(FacialExpression.FRIENDLY,"Wow, you're a smart one!", "You're absolutely RIGHT!", "Okay, next question!", unclosable = true)
goto("question")
label("wrong")
npc(FacialExpression.FRIENDLY,"WRONG!", "That's just WRONG!", "Okay, next question!", unclosable = true)
goto("question")
label("winner")
npc(FacialExpression.FRIENDLY,"<col=08088A>CONGRATULATIONS!</col>", "You are a <col=8A0808>WINNER</col>!", "Please choose your <col=08088A>PRIZE</col>!", unclosable = true)
options(
DialogueOption("money", "1000 Coins", skipPlayer = true),
DialogueOption("item", "Random Item", skipPlayer = true)
)
label("money")
exec { player, _ ->
queueScript(player, 0, QueueStrength.SOFT) { _ ->
addItemOrDrop(player, Items.COINS_995, 1000)
return@queueScript stopExecuting(player)
}
}
goto("cleanup")
label("item")
exec { player, _ ->
queueScript(player, 0, QueueStrength.SOFT) { _ ->
addItemOrDrop(player, tableRoll.roll()[0].id)
return@queueScript stopExecuting(player)
}
}
goto("cleanup")
label("cleanup")
exec { player, _ ->
resetAnimator(player)
returnPlayer(player)
removeAttributes(player, QUIZMASTER_ATTRIBUTE_QUESTIONS_CORRECT, QUIZMASTER_ATTRIBUTE_RANDOM_ANSWER)
}
goto("nowhere")
} }
} }

View file

@ -4,14 +4,9 @@ import content.global.ame.RandomEventNPC
import content.global.ame.kidnapPlayer import content.global.ame.kidnapPlayer
import core.api.* import core.api.*
import core.api.utils.WeightBasedTable import core.api.utils.WeightBasedTable
import core.game.interaction.QueueStrength
import core.game.node.entity.npc.NPC import core.game.node.entity.npc.NPC
import core.game.node.entity.player.link.TeleportManager
import core.game.system.timer.impl.AntiMacro
import core.game.world.map.Location import core.game.world.map.Location
import core.game.world.update.flag.context.Graphics
import org.rs09.consts.NPCs import org.rs09.consts.NPCs
import org.rs09.consts.Sounds
/** /**
* Quiz Master NPC: * Quiz Master NPC:
@ -27,35 +22,14 @@ class QuizMasterNPC(var type: String = "", override var loot: WeightBasedTable?
override fun init() { override fun init() {
super.init() super.init()
sendChat("Hey ${player.username}! It's your lucky day!") sendChat("Hey ${player.username}! It's your lucky day!")
queueScript(player, 4, QueueStrength.SOFT) { stage: Int -> face(player)
when (stage) { kidnapPlayer(this, player, Location(1952, 4764, 0)) { player, _ ->
0 -> { setAttribute(player, QuizMasterDialogueFile.QUIZMASTER_ATTRIBUTE_QUESTIONS_CORRECT, 0)
lock(player, 6) sendMessage(player, "Answer four questions correctly in a row to be teleported back where you came from.")
sendGraphics(Graphics(1576, 0, 0), player.location) sendMessage(player, "You will need to relog in if you lose the quiz dialog.") // Inauthentic, but there to notify the player in case.
animate(player,8939) face(player, Location(1952, 4768, 1))
playAudio(player, Sounds.TELEPORT_ALL_200) animate(player,2378)
return@queueScript delayScript(player, 3) // Quiz dialogue gets opened automatically on zone entry.
}
1 -> {
kidnapPlayer(player, Location(1952, 4764, 1), TeleportManager.TeleportType.INSTANT)
setAttribute(player, QuizMasterDialogueFile.QUIZMASTER_ATTRIBUTE_QUESTIONS_CORRECT, 0)
AntiMacro.terminateEventNpc(player)
sendGraphics(Graphics(1577, 0, 0), player.location)
animate(player,8941)
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.
return@queueScript delayScript(player, 6)
}
2 -> {
face(player, Location(1952, 4768, 1))
animate(player,2378)
// This is not needed as when you enter the QuizMasterBorders, it should fire off the dialogue
// openDialogue(player, QuizMasterDialogueFile(), this.asNpc())
return@queueScript stopExecuting(player)
}
else -> return@queueScript stopExecuting(player)
}
} }
} }

View file

@ -0,0 +1,25 @@
package content.global.ame.events.rockgolem
import core.game.node.entity.Entity
import core.game.node.entity.combat.CombatStyle
import core.game.node.entity.combat.CombatSwingHandler
import core.game.node.entity.combat.MultiSwingHandler
import core.game.node.entity.combat.equipment.SwitchAttack
import core.game.node.entity.npc.NPC
import core.game.node.entity.npc.NPCBehavior
import org.rs09.consts.NPCs
class RockGolemBehavior() : NPCBehavior(
NPCs.ROCK_GOLEM_413, NPCs.ROCK_GOLEM_414, NPCs.ROCK_GOLEM_415, NPCs.ROCK_GOLEM_416, NPCs.ROCK_GOLEM_417, NPCs.ROCK_GOLEM_418
) {
val rangeHandler = SwitchAttack(CombatStyle.RANGE)
val meleeHandler = SwitchAttack(CombatStyle.MELEE)
val combatHandler = MultiSwingHandler(rangeHandler, meleeHandler)
override fun getSwingHandlerOverride(self: NPC, original: CombatSwingHandler): CombatSwingHandler {
return combatHandler
}
override fun getXpMultiplier(self: NPC, attacker: Entity): Double {
return super.getXpMultiplier(self, attacker) / 16.0
}
}

View file

@ -5,32 +5,49 @@ import core.tools.RandomFunction
import org.rs09.consts.Items import org.rs09.consts.Items
import org.rs09.consts.NPCs import org.rs09.consts.NPCs
import content.global.ame.RandomEventNPC import content.global.ame.RandomEventNPC
import core.api.lock
import core.api.utils.WeightBasedTable import core.api.utils.WeightBasedTable
class SandwichLadyRENPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.SANDWICH_LADY_3117) { class SandwichLadyRENPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.SANDWICH_LADY_3117) {
val phrases = arrayOf("Hello, @name, can you hear me?","Sandwiches, @name!","Are you ignoring me, @name??","Yoohoo! Sandwiches, @name!","Hello, @name?", "Come get your sandwiches, @name!", "How could you ignore me like this, @name?!", "Do you even want your sandwiches, @name?") lateinit var phrases: Array<String>
var assigned_item = 0 var assigned_item = 0
val items = arrayOf(Items.BAGUETTE_6961,Items.TRIANGLE_SANDWICH_6962,Items.SQUARE_SANDWICH_6965,Items.ROLL_6963,Items.MEAT_PIE_2327,Items.KEBAB_1971,Items.CHOCOLATE_BAR_1973) val items = arrayOf(Items.BAGUETTE_6961, Items.TRIANGLE_SANDWICH_6962, Items.SQUARE_SANDWICH_6965, Items.ROLL_6963, Items.MEAT_PIE_2327, Items.KEBAB_1971, Items.CHOCOLATE_BAR_1973)
override fun tick() { override fun tick() {
if(RandomFunction.random(1,15) == 5){ sayLine(this, phrases, true, true)
sendChat(phrases.random().replace("@name",player.username.capitalize())) if (ticksLeft == 2) {
lock(player, 2)
} }
super.tick() super.tick()
} }
override fun init() { override fun init() {
super.init() super.init()
phrases = arrayOf(
// https://www.youtube.com/watch?v=ek8r3ZS929E
// She always starts with "Sandwiches, ${player.username}!" but she ALSO picks that at random, hence duplicate it with hasOpeningPhrase = true
"Sandwiches, ${player.username}!",
"Sandwiches, ${player.username}!",
"Come on ${player.username}, I made these specially!!",
"All types of sandwiches, ${player.username}.",
"Did you hear me ${player.username}?",
"You think I made these just for fun?!!?",
"How could you ignore me like this, ${player.username}?!" //unknown if authentic but it was already here
)
assignItem() assignItem()
sendChat(phrases.random().replace("@name",player.username.capitalize())) }
override fun onTimeUp() {
noteAndTeleport()
terminate()
} }
fun assignItem(){ fun assignItem(){
assigned_item = items.random() assigned_item = items.random()
player.setAttribute("sandwich-lady:item",assigned_item) player.setAttribute("sandwich-lady:item", assigned_item)
} }
override fun talkTo(npc: NPC) { override fun talkTo(npc: NPC) {
player.dialogueInterpreter.open(SandwichLadyDialogue(false),npc) player.dialogueInterpreter.open(SandwichLadyDialogue(false), npc)
} }
} }

View file

@ -1,41 +0,0 @@
package content.global.ame.events
import core.game.node.entity.player.Player
import content.global.ame.events.surpriseexam.SurpriseExamUtils
import core.game.dialogue.DialogueFile
import core.game.system.timer.impl.AntiMacro
class MysteriousOldManDialogue(val type: String) : DialogueFile() {
val CHOICE_STAGE = 50000
override fun handle(componentID: Int, buttonID: Int) {
if(type == "sexam" && stage < CHOICE_STAGE){
npc("Would you like to come do a surprise exam?")
stage = CHOICE_STAGE
}
else if(stage >= CHOICE_STAGE){
when(stage) {
CHOICE_STAGE -> options("Yeah, sure!", "No, thanks.").also { stage++ }
CHOICE_STAGE.substage(1) -> when(buttonID){
1 -> {
end()
teleport(player!!,type)
AntiMacro.terminateEventNpc(player!!)
}
2 -> {
end()
AntiMacro.terminateEventNpc(player!!)
}
}
}
}
}
fun teleport(player: Player,type: String){
when(type){
"sexam" -> SurpriseExamUtils.teleport(player)
}
}
}

View file

@ -1,31 +1,24 @@
package content.global.ame.events package content.global.ame.events.surpriseexam
import content.global.ame.RandomEventNPC import content.global.ame.RandomEventNPC
import core.game.node.entity.npc.NPC import content.global.ame.kidnapPlayer
import core.tools.RandomFunction import core.api.*
import org.rs09.consts.NPCs import org.rs09.consts.NPCs
import core.api.utils.WeightBasedTable import core.api.utils.WeightBasedTable
import core.game.node.entity.npc.NPC
import core.game.world.map.Location
class MysteriousOldManNPC(var type: String = "", override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.MYSTERIOUS_OLD_MAN_410) { class MysteriousOldManNPC(var type: String = "", override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.MYSTERIOUS_OLD_MAN_410) {
override fun init() { override fun init() {
super.init() super.init()
sayLine() sendChat("Surprise exam, ${player.username}!")
} face(player)
kidnapPlayer(this, player, Location(1886, 5025, 0)) { _, _ ->
override fun tick() { /* nothing needed */
super.tick()
if(RandomFunction.random(1,10) == 5) sayLine()
}
fun sayLine() {
when(type){
"sexam" -> sendChat("Surprise exam, ${player.username.capitalize()}!")
} }
} }
override fun talkTo(npc: NPC) { override fun talkTo(npc: NPC) {
when(type){ sendMessage(player, "He isn't interested in talking to you.")
"sexam" -> player.dialogueInterpreter.open(MysteriousOldManDialogue("sexam"),this.asNpc())
}
} }
} }

View file

@ -2,7 +2,6 @@ package content.global.ame.events.surpriseexam
import core.game.component.Component import core.game.component.Component
import core.game.node.entity.player.Player import core.game.node.entity.player.Player
import core.game.node.item.Item
import core.game.world.map.Location import core.game.world.map.Location
import org.rs09.consts.Items import org.rs09.consts.Items
import org.rs09.consts.NPCs import org.rs09.consts.NPCs
@ -66,6 +65,6 @@ class SupriseExamListeners : InteractionListener, MapArea {
} }
override fun getRestrictions(): Array<ZoneRestriction> { override fun getRestrictions(): Array<ZoneRestriction> {
return arrayOf(ZoneRestriction.RANDOM_EVENTS, ZoneRestriction.CANNON, ZoneRestriction.FOLLOWERS, ZoneRestriction.OFF_MAP) return arrayOf(ZoneRestriction.RANDOM_EVENTS, ZoneRestriction.CANNON, ZoneRestriction.FOLLOWERS, ZoneRestriction.TELEPORT, ZoneRestriction.OFF_MAP)
} }
} }

View file

@ -1,15 +1,12 @@
package content.global.ame.events.surpriseexam package content.global.ame.events.surpriseexam
import content.global.ame.kidnapPlayer
import content.global.ame.returnPlayer import content.global.ame.returnPlayer
import core.api.* import core.api.*
import core.game.node.entity.impl.PulseType import core.game.node.entity.impl.PulseType
import core.game.node.entity.player.Player import core.game.node.entity.player.Player
import core.game.system.task.Pulse import core.game.system.task.Pulse
import core.game.world.map.Location
import org.rs09.consts.Components import org.rs09.consts.Components
import org.rs09.consts.Items import org.rs09.consts.Items
import core.game.node.entity.player.link.TeleportManager
object SurpriseExamUtils { object SurpriseExamUtils {
val SE_KEY_INDEX = "supexam:index" val SE_KEY_INDEX = "supexam:index"
@ -26,10 +23,6 @@ object SurpriseExamUtils {
intArrayOf(Items.FLY_FISHING_ROD_309,Items.BARBARIAN_ROD_11323,Items.SMALL_FISHING_NET_303,Items.HARPOON_311) intArrayOf(Items.FLY_FISHING_ROD_309,Items.BARBARIAN_ROD_11323,Items.SMALL_FISHING_NET_303,Items.HARPOON_311)
) )
fun teleport(player: Player) {
kidnapPlayer(player, Location.create(1886, 5025, 0), TeleportManager.TeleportType.INSTANT)
}
fun cleanup(player: Player){ fun cleanup(player: Player){
returnPlayer(player) returnPlayer(player)
removeAttributes(player, SE_KEY_INDEX, SE_KEY_CORRECT) removeAttributes(player, SE_KEY_INDEX, SE_KEY_CORRECT)

View file

@ -1,12 +1,12 @@
package content.global.bots package content.global.bots
import content.global.skill.fletching.log.LogCraftInfo
import content.global.skill.fletching.log.CraftItemWithLogScript
import core.game.bots.Script
import core.game.bots.SkillingBotAssembler
import core.game.node.entity.skill.Skills import core.game.node.entity.skill.Skills
import content.global.skill.fletching.Fletching
import content.global.skill.fletching.FletchingPulse
import core.game.node.item.Item import core.game.node.item.Item
import org.rs09.consts.Items import org.rs09.consts.Items
import core.game.bots.SkillingBotAssembler
import core.game.bots.Script
class FletchingBankstander : Script(){ class FletchingBankstander : Script(){
var state = State.FLETCHING var state = State.FLETCHING
@ -17,7 +17,7 @@ class FletchingBankstander : Script(){
State.FLETCHING -> { State.FLETCHING -> {
bot.inventory.add(Item(Items.KNIFE_946)) bot.inventory.add(Item(Items.KNIFE_946))
bot.inventory.add(Item(Items.LOGS_1511,27)) bot.inventory.add(Item(Items.LOGS_1511,27))
bot.pulseManager.run(FletchingPulse(bot, Item(Items.LOGS_1511),27, Fletching.FletchingItems.ARROW_SHAFT)) CraftItemWithLogScript(bot, LogCraftInfo.ARROW_SHAFT, 27).invoke()
State.BANKING State.BANKING
} }

View file

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

View file

@ -1,181 +0,0 @@
package content.global.dialogue
import core.api.*
import core.game.node.entity.player.Player
import core.game.node.entity.player.link.IronmanMode
import core.plugin.Initializable
import core.game.dialogue.IfTopic
import core.game.dialogue.Topic
import content.global.handlers.npc.BankerNPC
import core.tools.END_DIALOGUE
import core.tools.START_DIALOGUE
@Initializable
class BankerDialogue(player: Player? = null) : core.game.dialogue.DialoguePlugin(player) {
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
when (stage) {
START_DIALOGUE -> when {
hasIronmanRestriction(player, IronmanMode.ULTIMATE) -> {
npcl(
core.game.dialogue.FacialExpression.ANNOYED,
"My apologies, dear ${if (player.isMale) "sir" else "madam"}, " +
"our services are not available for Ultimate ${if (player.isMale) "Ironmen" else "Ironwomen"}"
).also { stage = END_DIALOGUE }
}
else -> {
npcl(
core.game.dialogue.FacialExpression.FRIENDLY,
"Good day, how may I help you?"
).also {
if (hasAwaitingGrandExchangeCollections(player)) {
stage++
} else {
stage += 2
}
}
}
}
1 -> npcl(
core.game.dialogue.FacialExpression.FRIENDLY,
"Before we go any further, I should inform you that you " +
"have items ready for collection from the Grand Exchange."
).also { stage++ }
2 -> showTopics(
Topic(core.game.dialogue.FacialExpression.FRIENDLY, "I'd like to access my bank account, please.", 10),
IfTopic(
core.game.dialogue.FacialExpression.FRIENDLY,
"I'd like to switch to my ${getBankAccountName(player, true)} bank account.",
13,
hasActivatedSecondaryBankAccount(player)
),
IfTopic(
core.game.dialogue.FacialExpression.FRIENDLY,
"I'd like to open a secondary bank account.",
20,
!hasActivatedSecondaryBankAccount(player)
),
Topic(core.game.dialogue.FacialExpression.FRIENDLY, "I'd like to check my PIN settings.", 11),
Topic(core.game.dialogue.FacialExpression.FRIENDLY, "I'd like to collect items.", 12),
Topic(core.game.dialogue.FacialExpression.ASKING, "What is this place?", 3),
)
3 -> npcl(
core.game.dialogue.FacialExpression.FRIENDLY,
"This is a branch of the Bank of Gielinor. We have branches in many towns."
).also { stage++ }
4 -> playerl(
core.game.dialogue.FacialExpression.ASKING,
"And what do you do?"
).also { stage++ }
5 -> npcl(
core.game.dialogue.FacialExpression.FRIENDLY,
"We will look after your items and money for you. " +
"Leave your valuables with us if you want to keep them safe."
).also { stage = END_DIALOGUE }
10 -> {
openBankAccount(player)
end()
}
11 -> {
openBankPinSettings(player)
end()
}
12 -> {
openGrandExchangeCollectionBox(player)
end()
}
13 -> {
toggleBankAccount(player)
npcl(
core.game.dialogue.FacialExpression.FRIENDLY,
"Your active bank account has been switched. " +
"You can now access your ${getBankAccountName(player)} account."
).also { stage = 2 }
}
20 -> npcl(
core.game.dialogue.FacialExpression.FRIENDLY,
"Certainly. We offer secondary accounts to all our customers."
).also { stage++ }
21 -> npcl(
core.game.dialogue.FacialExpression.FRIENDLY,
"The secondary account comes with a standard fee of 5,000,000 coins. The fee is non-refundable " +
"and account activation is permanent."
).also { stage++ }
22 -> npcl(
core.game.dialogue.FacialExpression.FRIENDLY,
"If your inventory does not contain enough money to cover the costs, we will complement " +
"the amount with the money inside your primary bank account."
).also { stage++ }
23 -> npcl(
core.game.dialogue.FacialExpression.ASKING,
"Knowing all this, would you like to proceed with opening your secondary bank account?"
).also { stage++ }
24 -> showTopics(
Topic(core.game.dialogue.FacialExpression.HAPPY, "Yes, I am still interested.", 25),
Topic(core.game.dialogue.FacialExpression.ANNOYED, "Actually, I've changed my mind.", 26)
)
25 -> {
when (activateSecondaryBankAccount(player)) {
SecondaryBankAccountActivationResult.ALREADY_ACTIVE -> {
npcl(
core.game.dialogue.FacialExpression.FRIENDLY,
"Your bank account was already activated, there is no need to pay twice."
).also { stage = END_DIALOGUE }
}
SecondaryBankAccountActivationResult.INTERNAL_FAILURE -> {
npcl(
core.game.dialogue.FacialExpression.ANNOYED,
"I must apologize, the transaction was not successful. Please check your " +
"primary bank account and your inventory - if there's money missing, please " +
"screenshot your chat box and contact the game developers."
).also { stage = END_DIALOGUE }
}
SecondaryBankAccountActivationResult.NOT_ENOUGH_MONEY -> {
npcl(
core.game.dialogue.FacialExpression.ANNOYED,
"It appears that you do not have the money necessary to cover the costs " +
"associated with opening a secondary bank account. I will be waiting here " +
"until you do."
).also { stage = END_DIALOGUE }
}
SecondaryBankAccountActivationResult.SUCCESS -> {
npcl(
core.game.dialogue.FacialExpression.FRIENDLY,
"Your secondary bank account has been opened and can be accessed through any " +
"of the Bank of Gielinor's employees. Thank you for choosing our services."
).also { stage = END_DIALOGUE }
}
}
}
26 -> npcl(
core.game.dialogue.FacialExpression.FRIENDLY,
"Very well. Should you decide a secondary bank account is needed, do not hesitate to " +
"contact any of the Bank of Gielinor's stationary employees. We will be happy to help."
).also { stage = END_DIALOGUE }
}
return true
}
override fun getIds(): IntArray = BankerNPC.NPC_IDS
}

View file

@ -1,5 +1,6 @@
package content.global.handlers.iface package content.global.handlers.iface
import content.global.handlers.iface.BookInterface.Companion.FANCY_BOOK_2_27
import core.api.closeInterface import core.api.closeInterface
import core.api.getAttribute import core.api.getAttribute
import core.api.openInterface import core.api.openInterface
@ -158,9 +159,22 @@ class BookInterface : InterfaceListener {
if (pageSet == getAttribute(player, CURRENT_PAGE_ATTRIBUTE, 0)) { if (pageSet == getAttribute(player, CURRENT_PAGE_ATTRIBUTE, 0)) {
player.packetDispatch.sendInterfaceConfig(componentId, enableLineId, false) player.packetDispatch.sendInterfaceConfig(componentId, enableLineId, false)
player.packetDispatch.sendModelOnInterface(modelId, componentId, drawLineId, 0) player.packetDispatch.sendModelOnInterface(modelId, componentId, drawLineId, 0)
player.packetDispatch.sendAngleOnInterface(componentId, drawLineId, zoom, pitch, yaw) player.packetDispatch.sendAngleOnInterface(componentId, drawLineId, zoom, pitch, yaw)
} else { }
player.packetDispatch.sendInterfaceConfig(componentId, enableLineId, true) }
/** Sets item on lineId of pageSet (0 index). Call this in the display function after pageSetup. */
fun setItemOnPage(player: Player, pageSet: Int, itemId: Int, componentId: Int, enableLineId: Int, drawLineId: Int, zoom: Int, pitch: Int, yaw: Int) {
if (pageSet == getAttribute(player, CURRENT_PAGE_ATTRIBUTE, 0)) {
player.packetDispatch.sendInterfaceConfig(componentId, enableLineId, false)
player.packetDispatch.sendItemOnInterface(itemId, 1, componentId, drawLineId)
}
}
/** Clears models(pictures) on lineId of pageSet (0 index). Call this in the display function after pageSetup. */
fun clearModelsOnPage(player: Player, componentId: Int) {
BookInterface.FANCY_BOOK_2_27_IMAGE_ENABLE_DRAW_IDS.forEach { drawId ->
player.packetDispatch.sendInterfaceConfig(componentId, drawId, true);
} }
} }

View file

@ -1,159 +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.game.node.entity.player.link.RunScript;
import core.game.system.communication.ClanRank;
import core.game.system.communication.ClanRepository;
import core.net.amsc.MSPacketRepository;
import core.net.amsc.WorldCommunicator;
import core.plugin.Initializable;
import core.plugin.Plugin;
import core.tools.StringUtils;
import kotlin.Unit;
import static core.api.ContentAPIKt.sendInputDialogue;
import static core.api.ContentAPIKt.setInterfaceText;
/**
* Represents the plugin used to handle the clan interfaces.
* @author Vexia
*/
@Initializable
public final class ClanInterfacePlugin extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(590, this);
ComponentDefinition.put(589, this);
return this;
}
@Override
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
switch (component.getId()) {
case 589:
switch (button) {
case 9:
if (player.getInterfaceManager().getComponent(590) != null) {
player.getPacketDispatch().sendMessage("Please close the interface you have open before using 'Clan Setup'");
return true;
}
ClanRepository.openSettings(player);
return true;
case 14:
if (player.getIronmanManager().checkRestriction()) {
return false;
}
player.getDetails().getCommunication().toggleLootshare(player);
return true;
}
break;
case 590:
final ClanRepository clan = ClanRepository.get(player.getName(), true);
switch (button) {
case 23:
if (opcode == 155) {
clan.setJoinRequirement(ClanRank.NONE);
} else {
clan.setJoinRequirement(getRank(opcode));
}
player.getDetails().getCommunication().setJoinRequirement(clan.getJoinRequirement());
MSPacketRepository.setClanSetting(player, 0, clan.getJoinRequirement());
player.getPacketDispatch().sendString(clan.getJoinRequirement().getInfo(), 590, 23);
break;
case 24:
clan.setMessageRequirement(getRank(opcode));
player.getDetails().getCommunication().setMessageRequirement(clan.getMessageRequirement());
MSPacketRepository.setClanSetting(player, 1, clan.getMessageRequirement());
player.getPacketDispatch().sendString(clan.getMessageRequirement().getInfo(), 590, 24);
break;
case 25:
clan.setKickRequirement(getRank(opcode));
player.getDetails().getCommunication().setKickRequirement(clan.getKickRequirement());
MSPacketRepository.setClanSetting(player, 2, clan.getKickRequirement());
player.getPacketDispatch().sendString(clan.getKickRequirement().getInfo(), 590, 25);
clan.update();
break;
case 26:
if (opcode == 230) {
clan.setLootRequirement(ClanRank.ADMINISTRATOR);
} else {
clan.setLootRequirement(getRank(opcode));
}
player.getDetails().getCommunication().setLootRequirement(clan.getLootRequirement());
MSPacketRepository.setClanSetting(player, 3, clan.getLootRequirement());
player.getPacketDispatch().sendString(clan.getLootRequirement().getInfo(), 590, 26);
break;
case 22:
switch (opcode) {
case 196:
clan.setName("Chat disabled");
player.getCommunication().setClanName("");
player.getPacketDispatch().sendString(clan.getName(), 590, 22);
if (WorldCommunicator.isEnabled()) {
MSPacketRepository.sendClanRename(player, "");
break;
}
clan.clean(true);
break;
default:
sendInputDialogue(player, false, "Enter clan prefix:", (value) -> {
String name = StringUtils.formatDisplayName((String) value);
setInterfaceText(player, name, 590, 22);
if(WorldCommunicator.isEnabled()){
MSPacketRepository.sendClanRename(player, name);
clan.setName(name);
return Unit.INSTANCE;
}
if (clan.getName().equals("Chat disabled")) {
player.getPacketDispatch().sendMessage("Your clan channel has now been enabled!");
player.getPacketDispatch().sendMessage("Join your channel by clicking 'Join Chat' and typing: " + player.getUsername());
}
clan.setName(name);
player.getCommunication().setClanName(name);
clan.update();
return Unit.INSTANCE;
});
break;
}
break;
}
break;
}
return true;
}
/**
* Gets the value to set.
* @param opcode the opcode.
* @return the value.
*/
public static ClanRank getRank(int opcode) {
switch (opcode) {
case 155:
return ClanRank.NONE;
case 196:
return ClanRank.FRIEND;
case 124:
return ClanRank.RECRUIT;
case 199:
return ClanRank.CORPORAL;
case 234:
return ClanRank.SERGEANT;
case 168:
return ClanRank.LIEUTENANT;
case 166:
return ClanRank.CAPTAIN;
case 64:
return ClanRank.GENERAL;
case 53:
return ClanRank.OWNER;
}
return ClanRank.NONE;
}
}

View file

@ -1,50 +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;
@Initializable
public class CrystalKeyChestPlugin extends ComponentPlugin {
private final Integer CHEST_INTERFACE = 501;
private Player player;
public CrystalKeyChestPlugin() {
/*
* Empty
*/
}
public CrystalKeyChestPlugin(Player player) {
this.player = player;
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(CHEST_INTERFACE, this);
return this;
}
@Override
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
return false;
}
public void constructInterface(Player player) {
Integer[] hiddenChildren = new Integer[] { 3, 4, 5, 6, 7};
Component component = new Component(CHEST_INTERFACE);
for (int i = 3; i < hiddenChildren.length; i++) {
player.getPacketDispatch().sendInterfaceConfig(CHEST_INTERFACE, i, true);
}
player.getPacketDispatch().sendItemOnInterface(989, 1, CHEST_INTERFACE, hiddenChildren[2]);
player.getInterfaceManager().open(component);
this.player = player;
}
}

View file

@ -0,0 +1,17 @@
package content.global.handlers.iface
import core.api.closeInterface
import core.game.interaction.InterfaceListener
import org.rs09.consts.Components
class DeathInterface : InterfaceListener {
override fun defineInterfaceListeners() {
on(Components.AIDE_DEATH_153) { player, _, _, buttonID, _, _ ->
if (buttonID == 1) {
player.savedData.globalData.setDisableDeathScreen(true)
closeInterface(player)
}
return@on true
}
}
}

View file

@ -1,32 +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 death interface.
* @author Vexia
*/
@Initializable
public final class DeathInterfacePlugin extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.forId(153).setPlugin(this);
return this;
}
@Override
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
if (button == 1) {
player.getSavedData().getGlobalData().setDisableDeathScreen(true);
player.getInterfaceManager().close();
}
return true;
}
}

View file

@ -1,30 +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.game.node.entity.player.link.emote.Emotes;
import core.plugin.Initializable;
import core.plugin.Plugin;
/**
* Handles the emote tab interface.
* @author Vexia
*
*/
@Initializable
public final class EmoteTabInterface extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(464, this);
return this;
}
@Override
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
Emotes.handle(player, button);
return true;
}
}

View file

@ -1,231 +0,0 @@
package content.global.handlers.iface;
import content.global.skill.summoning.familiar.BurdenBeast;
import core.api.ContentAPIKt;
import core.cache.def.impl.ItemDefinition;
import core.game.component.Component;
import core.game.component.ComponentDefinition;
import core.game.component.ComponentPlugin;
import core.game.container.Container;
import core.game.container.ContainerEvent;
import core.game.container.ContainerListener;
import core.game.container.access.InterfaceContainer;
import core.game.container.impl.EquipmentContainer;
import core.game.interaction.OptionHandler;
import core.game.node.entity.combat.DeathTask;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.prayer.PrayerType;
import core.game.node.item.Item;
import core.game.system.task.Pulse;
import core.net.packet.PacketRepository;
import core.net.packet.context.ContainerContext;
import core.net.packet.out.ContainerPacket;
import core.plugin.Initializable;
import core.plugin.Plugin;
import core.game.global.action.EquipHandler;
import core.game.interaction.IntType;
import core.game.interaction.InteractionListeners;
import core.game.world.GameWorld;
import core.tools.Log;
/**
* Represents the equipment interface.
* @author Emperor
*
*/
@Initializable
public final class EquipmentInterface extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(102, this);
ComponentDefinition.put(387, this);
ComponentDefinition.put(667, this);
ComponentDefinition.put(670, this);
return this;
}
@Override
public boolean handle(final Player p, Component component, int opcode, int button, final int slot, final int itemId) {
if (component.getId() == 667) {
if (button != 14) {
return false;
}
switch (opcode) {
case 155:
p.getPulseManager().clear();
GameWorld.getPulser().submit(new Pulse(1, p) {
@Override
public boolean pulse() {
EquipHandler.unequip(p, slot, itemId);
return true;
}
});
return true;
case 9:
p.sendMessage(p.getEquipment().get(slot).getDefinition().getExamine());
return true;
case 196:
GameWorld.getPulser().submit(new Pulse(1, p) {
@Override
public boolean pulse() {
operate(p, slot, itemId);
return true;
}
});
return true;
}
return false;
}
else if (component.getId() == 670) {
switch (opcode) {
case 155:
p.getPulseManager().clear();
final Item item = p.getInventory().get(slot);
GameWorld.getPulser().submit(new Pulse(1, p) {
@Override
public boolean pulse() {
if (item == null) return true;
InteractionListeners.run(item.getId(), IntType.ITEM,"equip",p, item);
return true;
}
});
return true;
case 9:
p.sendMessage(p.getInventory().get(slot).getDefinition().getExamine());
return true;
}
}
switch (opcode) {
case 206:
if (button != 28) {
return false;
}
GameWorld.getPulser().submit(new Pulse(1, p) {
@Override
public boolean pulse() {
operate(p, slot, itemId);
return true;
}
});
return true;
default:
switch (button) {
case 52:
if (p.getInterfaceManager().isOpened() && p.getInterfaceManager().getOpened().getId() == 102) {
return true;
}
// (Highlight white items are auto destroyed on death Enum#616 (Items kept on death interface) TODO: Parse server sided
// SCRIPT 118 - Items kept on death interface CS
// ARG 0: Safe location check Takes: 0 Safe Area/2 in POH/3 in Castle Wars/4 in Trouble Brewing/5 in Barbass
int zoneType = p.getZoneMonitor().getType();
// ARG 1: Amount of items kept on death Takes: 0/1/3/4
Container[] itemArray = DeathTask.getContainers(p);
Container kept = itemArray[0];
int amtKeptOnDeath = kept.itemCount();
if (amtKeptOnDeath > 4 && zoneType == 0) {
ContentAPIKt.log(this.getClass(), Log.ERR, "Items kept on death interface should not contain more than 4 items when not in a safe zone!");
}
// ARG 2: Item kept on death slot 0
int slot0 = kept.getId(0);
// ARG 3: Item kept on death slot 1
int slot1 = kept.getId(1);
// ARG 4: Item kept on death slot 2
int slot2 = kept.getId(2);
// ARG 5: Item kept on death slot 3
int slot3 = kept.getId(3);
// ARG 6: Player skulled Takes: 0 not skulled/1 skulled
int skulled = p.getSkullManager().isSkulled() ? 1 : 0;
// ARG 7: Player has summoning creature out Takes: 0 not out/1 Creature summoned
int hasBoB;
if (p.getFamiliarManager().hasFamiliar()) {
if (p.getFamiliarManager().getFamiliar().isBurdenBeast()) {
hasBoB = ((BurdenBeast) p.getFamiliarManager().getFamiliar()).getContainer().isEmpty() ? 0 : 1;
} else {
hasBoB = 0;
}
} else {
hasBoB = 0;
}
// ARG 8: String for effect:
// if (arg1 == 0) arg8 + " This reduces the items you keep from three to zero!"
// if (arg1 == 1) arg8 + " This reduces the items you keep from three to zero!" + "<br>" + "<br>" + "However, you also have the " + "<col=ff3333>" + "Protect Items" + "<col=ff981f>" + " prayer active, which saves you one extra item!");
Object[] params = new Object[] { hasBoB, skulled, slot3, slot2, slot1, slot0, amtKeptOnDeath, zoneType, "You are skulled." };
p.getPacketDispatch().sendRunScript(118, "siiooooii", params);
p.getInterfaceManager().openComponent(102);
break;
case 28:
if (opcode == 81) {
p.getPulseManager().clear();
GameWorld.getPulser().submit(new Pulse(1, p) {
@Override
public boolean pulse() {
EquipHandler.unequip(p, slot, itemId);
return true;
}
});
return true;
}
break;
case 55:
if (p.getInterfaceManager().isOpened() && p.getInterfaceManager().getOpened().getId() == 667) {
return true;
}
final ContainerListener listener = new ContainerListener() {
@Override
public void update(Container c, ContainerEvent e) {
PacketRepository.send(ContainerPacket.class, new ContainerContext(p, -1, -1, 98, e.getItems(), false, e.getSlots()));
}
@Override
public void refresh(Container c) {
PacketRepository.send(ContainerPacket.class, new ContainerContext(p, -1, -1, 98, c, false));
}
};
p.getInterfaceManager().openComponent(667).setCloseEvent((player, c) -> {
player.removeAttribute("equip_stats_open");
player.getInterfaceManager().closeSingleTab();
player.getInventory().getListeners().remove(listener);
return true;
});
p.setAttribute("equip_stats_open", true);
EquipmentContainer.update(p);
p.getInterfaceManager().openSingleTab(new Component(670));
InterfaceContainer.generateItems(p, p.getInventory().toArray(), new String[] { "Equip" }, 670, 0, 7, 4, 93);
p.getInventory().getListeners().add(listener);
p.getInventory().refresh();
ItemDefinition.statsUpdate(p);
p.getPacketDispatch().sendIfaceSettings(1278, 14, 667, 0, 13);
break;
}
}
return true;
}
/**
* Operates an item.
* @param player The player.
* @param slot The container slot.
* @param itemId The item id.
*/
public void operate(Player player, int slot, int itemId) {
if (slot < 0 || slot > 13) {
return;
}
Item item = player.getEquipment().get(slot);
if (item == null) {
return;
}
if(InteractionListeners.run(item.getId(),IntType.ITEM,"operate",player,item)){
return;
}
OptionHandler handler = item.getOperateHandler();
if (handler != null && handler.handle(player, item, "operate")) {
return;
}
player.getPacketDispatch().sendMessage("You can't operate that.");
}
}

View file

@ -162,9 +162,10 @@ class FurClothingInterface : ComponentPlugin(){
return return
} }
removeItem(player, requiredFur, Container.INVENTORY) if (removeItem(player, requiredFur, Container.INVENTORY) &&
removeItem(player, coins, Container.INVENTORY) removeItem(player, coins, Container.INVENTORY)) {
addItem(player, clothing.product.id, amount) addItem(player, clothing.product.id, amount)
}
} }
override fun newInstance(arg: Any?): Plugin<Any> { override fun newInstance(arg: Any?): Plugin<Any> {

View file

@ -1,185 +0,0 @@
package content.global.handlers.iface;
import core.game.component.Component;
import core.game.component.ComponentDefinition;
import core.game.component.ComponentPlugin;
import core.plugin.Initializable;
import core.game.node.entity.combat.equipment.WeaponInterface;
import core.game.node.entity.combat.equipment.WeaponInterface.WeaponInterfaces;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.info.Rights;
import core.game.world.GameWorld;
import core.plugin.Plugin;
/**
* Represents the component plugin used for the game interface.
* @author Vexia
*
*/
@Initializable
public final class GameInterface extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(740, this);
return this;
}
@Override
public boolean handle(final Player player, Component component, int opcode, int button, int slot, int itemId) {
switch (component.getId()) {
case 740:
switch (button){
case 3:
player.getInterfaceManager().closeChatbox();
break;
}
return true;
case 746:
switch (button){
case 12:
player.getPacketDispatch().sendString("When you have finished playing " + GameWorld.getSettings().getName() + ", always use the button below to logout safely. ", 182, 0);
break;
case 49:
player.getPacketDispatch().sendString("Friends List - " + GameWorld.getSettings().getName() + " " + GameWorld.getSettings().getWorldId(), 550, 3);
break;
case 110:
configureWorldMap(player);
break;
}
return true;
case 548:
if (button >= 38 && button<= 44 || button >= 20 && button <= 26) {
player.getInterfaceManager().setCurrentTabIndex(getTabIndex(button));
}
//Interface buttons that advance the Tutorial Island stages
switch (button) {
case 21://Friends Tab
player.getPacketDispatch().sendString("Friends List -" + GameWorld.getSettings().getName() + " " + GameWorld.getSettings().getWorldId(), 550, 3);
break;
case 22://Ignore Tab
break;
case 24://Settings Tab
break;
case 25://Emotes Tab
break;
case 26://Music Tab
break;
case 38://Attack Tab
if (player.getExtension(WeaponInterface.class) == WeaponInterfaces.STAFF) {
final Component c = new Component(WeaponInterfaces.STAFF.getInterfaceId());
player.getInterfaceManager().openTab(0, c);
final WeaponInterface inter = player.getExtension(WeaponInterface.class);
inter.updateInterface();
}
break;
case 39://Skill Tab
break;
case 40://Quest Tab
/*if (GameWorld.isEconomyWorld()) {
player.getQuestRepository().syncronizeTab(player);
} else {
player.getSavedData().getSpawnData().drawStatsTab(player);
}*/
player.getQuestRepository().syncronizeTab(player);
break;
case 41://Inventory Tab
player.getInventory().refresh();
break;
case 42://Worn Equipment Tab
break;
case 43://Prayer Tab
break;
case 44://Magic Tab
break;
case 66://World map
case 110:
configureWorldMap(player);
break;
case 69://Logout
player.getPacketDispatch().sendString("When you have finished playing " + GameWorld.getSettings().getName() + ", always use the button below to logout safely. ", 182, 0);
break;
}
return true;
case 750:
switch (opcode) {
case 155:
switch (button) {
case 1:
player.getSettings().toggleRun();
break;
}
break;
}
return true;
case 751:
switch (opcode) {
case 155:
switch (button) {
case 27:
openReport(player);
break;
}
break;
}
return true;
}
return true;
}
/**
* World map
* Thanks, Snickerize!
*/
private void configureWorldMap(Player player) {
if (player.inCombat()) {
player.getPacketDispatch().sendMessage("It wouldn't be very wise opening the world map during combat.");
return;
}
if(player.getLocks().isInteractionLocked() || player.getLocks().isMovementLocked()){
player.getPacketDispatch().sendMessage("You can't do this right now.");
return;
}
player.getInterfaceManager().openWindowsPane(new Component(755));
int posHash = (player.getLocation().getZ() << 28) | (player.getLocation().getX() << 14) | player.getLocation().getY();
player.getPacketDispatch().sendScriptConfigs(622, posHash, "", 0);
player.getPacketDispatch().sendScriptConfigs(674, posHash, "", 0);
}
/**
* Method used to open the report interface.
* @param player the player.
*/
public static void openReport(final Player player) {
player.getInterfaceManager().open(new Component(553)).setCloseEvent((player1, c) -> {
player1.getPacketDispatch().sendRunScript(80, "");
player1.getPacketDispatch().sendRunScript(137, "");
return true;
});
player.getPacketDispatch().sendRunScript(508, "");
if (player.getDetails().getRights() != Rights.REGULAR_PLAYER) {
for (int i = 0; i < 18; i++) {
player.getPacketDispatch().sendInterfaceConfig(553, i, false);
}
}
}
/**
* Gets the tab index.
* @param button The button id.
* @return The tab index.
*/
private static int getTabIndex(int button) {
int tabIndex = button - 38;
if (button < 27) {
tabIndex = (button - 20) + 7;
}
return tabIndex;
}
/**
* Configures the world map for a player.
* @param player The player.
*/
}

View file

@ -152,11 +152,11 @@ class HairDresserInterface : ComponentPlugin(){
player.setAttribute("beard-setting",false) player.setAttribute("beard-setting",false)
if(!pl.getAttribute("hairdresser-paid",false)){ if(!pl.getAttribute("hairdresser-paid",false)){
val original_hair = player.getAttribute("original-hair",0) val original_hair = player.getAttribute("original-hair",0)
val original_beard = player.getAttribute("original_beard",-1) val original_beard = player.getAttribute("original-beard",-1)
val original_color = player.getAttribute("original_color",0) val original_color = player.getAttribute("original-color",0)
pl.appearance.hair.changeLook(original_hair) pl.appearance.hair.changeLook(original_hair)
pl.appearance.hair.changeColor(original_color) pl.appearance.hair.changeColor(original_color)
if(original_beard != -1) { if (original_beard != -1) {
pl.appearance.beard.changeLook(original_beard) pl.appearance.beard.changeLook(original_beard)
} }
pl.appearance.sync() pl.appearance.sync()
@ -174,7 +174,7 @@ class HairDresserInterface : ComponentPlugin(){
when(button){ when(button){
199 -> player.setAttribute("beard-setting",false) 199 -> player.setAttribute("beard-setting",false)
200 -> player.setAttribute("beard-setting",true) 200 -> player.setAttribute("beard-setting",true)
68,196,274 -> pay(player) 196,274,68,100 -> pay(player)
else -> when(component?.id){ else -> when(component?.id){
592 -> { //Female 592 -> { //Female
if(femaleColorButtonRange.contains(button)){ if(femaleColorButtonRange.contains(button)){

View file

@ -0,0 +1,34 @@
package content.global.handlers.iface
import core.api.closeInterface
import core.api.runTask
import core.game.interaction.InterfaceListener
import core.game.node.entity.player.info.login.LoginConfiguration
import org.rs09.consts.Components
class LoginInterface : InterfaceListener {
override fun defineInterfaceListeners() {
on(Components.WELCOME_SCREEN_378) { player, _, _, buttonID, _, _ ->
val playButton = 140
val creditButton = 145
val discordButton = 204
when (buttonID) {
playButton -> {
player.locks.lock("login", 2)
closeInterface(player)
runTask(player, 1, 0) {
LoginConfiguration.configureGameWorld(player)
}
}
creditButton -> return@on true
discordButton -> return@on true
}
return@on true
}
onClose(Components.WELCOME_SCREEN_378) { player, _ ->
return@onClose player.locks.isLocked("login")
}
}
}

View file

@ -1,51 +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.game.node.entity.player.info.login.LoginConfiguration;
import core.game.system.task.Pulse;
import core.plugin.Initializable;
import core.plugin.Plugin;
/**
* Represents the plugin used for the login interface.
* @author 'Vexia
* @version 1.0
*/
@Initializable
public final class LoginInterfacePlugin extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(378, this);
return null;
}
@Override
public boolean handle(final Player player, Component component, int opcode, int button, int slot, int itemId) {
switch (button) {
case 140:
if (player.getLocks().isLocked("login")) {
return true;
}
player.getLocks().lock("login", 2);
player.getInterfaceManager().close();
player.getPulseManager().run(new Pulse(1) {
@Override
public boolean pulse() {
LoginConfiguration.configureGameWorld(player);
return true;
}
});
break;
case 145://credits
break;
case 204://message centre
break;
}
return true;
}
}

View file

@ -1,42 +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.game.world.GameWorld;
import core.plugin.Initializable;
import core.plugin.Plugin;
import core.game.world.repository.Repository;
/**
* Represents the interface used to logout of the game.
* @author 'Vexia
* @version 1.0
*/
@Initializable
public final class LogoutInterface extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(182, this);
return this;
}
@Override
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
if (!player.getZoneMonitor().canLogout()) {
return true;
}
if (player.inCombat()) {
player.getPacketDispatch().sendMessage("You can't log out until 10 seconds after the end of combat.");
return true;
}
if (player.isTeleporting()) {
player.sendMessage("Please finish your teleport before logging out.");
return true;
}
Repository.getDisconnectionQueue().add(player);
return true;
}
}

View file

@ -1,50 +0,0 @@
package content.global.handlers.iface;
import content.global.skill.magic.SpellListener;
import content.global.skill.magic.SpellListeners;
import content.global.skill.magic.SpellUtils;
import core.game.event.SpellCastEvent;
import core.game.component.Component;
import core.game.component.ComponentDefinition;
import core.game.component.ComponentPlugin;
import core.plugin.Initializable;
import core.game.node.entity.combat.spell.MagicSpell;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.SpellBookManager.SpellBook;
import core.game.world.GameWorld;
import core.plugin.Plugin;
/**
* Represents the magic book interface handling of non-combat spells.
* @author 'Vexia
* @version 1.0
*/
@Initializable
public final class MagicBookInterface extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(192, this);
ComponentDefinition.put(193, this);
ComponentDefinition.put(430, this);
return this;
}
@Override
public boolean handle(final Player player, Component component, int opcode, int button, int slot, int itemId) {
if (GameWorld.getTicks() < player.getAttribute("magic:delay", -1)) {
return true;
}
SpellBook spellBook = component.getId() == 192
? SpellBook.MODERN
: component.getId() == 193
? SpellBook.ANCIENT
: SpellBook.LUNAR;
SpellListeners.run(button, SpellListener.NONE, SpellUtils.getBookFromInterface(component.getId()),player,null);
boolean result = MagicSpell.castSpell(player, spellBook, button, player);
return result;
}
}

View file

@ -31,32 +31,13 @@ class MainGameInterface : InterfaceListener {
} }
on(TOPLEVEL_FS){player, _, _, buttonID, _, _ -> on(TOPLEVEL_FS){player, _, _, buttonID, _, _ ->
when (buttonID) { if (buttonID == 110)
12 -> setInterfaceText(player, configureWorldMap(player)
"When you have finished playing " + settings!!.name + ", always use the button below to logout safely. ",
182,
0
)
49 -> setInterfaceText(player,
"Friends List - " + settings!!.name + " " + settings!!.worldId,
550,
3
)
110 -> configureWorldMap(player)
}
return@on true return@on true
} }
on(TOPLEVEL){player, _, _, buttonID, _, _ -> on(TOPLEVEL){player, _, _, buttonID, _, _ ->
when (buttonID) { when (buttonID) {
21 -> {
player.packetDispatch.sendString(
"Friends List -" + settings!!.name + " " + settings!!.worldId,
550,
3
)
}
38 -> { 38 -> {
if (player.getExtension<Any>(WeaponInterface::class.java) === WeaponInterfaces.STAFF) { if (player.getExtension<Any>(WeaponInterface::class.java) === WeaponInterfaces.STAFF) {
val c = Component(WeaponInterfaces.STAFF.interfaceId) val c = Component(WeaponInterfaces.STAFF.interfaceId)
@ -67,12 +48,7 @@ class MainGameInterface : InterfaceListener {
} }
40 -> player.questRepository.syncronizeTab(player) 40 -> player.questRepository.syncronizeTab(player)
41 -> player.inventory.refresh() 41 -> player.inventory.refresh()
66, 110 -> configureWorldMap(player) 66 -> configureWorldMap(player)
69 -> player.packetDispatch.sendString(
"When you have finished playing " + settings!!.name + ", always use the button below to logout safely. ",
182,
0
)
} }
return@on true return@on true
} }
@ -95,11 +71,11 @@ class MainGameInterface : InterfaceListener {
private fun configureWorldMap(player: Player) { private fun configureWorldMap(player: Player) {
if (player.inCombat()) { if (player.inCombat()) {
player.packetDispatch.sendMessage("It wouldn't be very wise opening the world map during combat.") sendMessage(player, "It wouldn't be very wise opening the world map during combat.")
return return
} }
if (player.locks.isInteractionLocked || player.locks.isMovementLocked) { if (player.locks.isInteractionLocked || player.locks.isMovementLocked) {
player.packetDispatch.sendMessage("You can't do this right now.") sendMessage(player, "You can't do this right now.")
return return
} }
player.interfaceManager.close() player.interfaceManager.close()

View file

@ -1,57 +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.game.node.entity.player.info.Rights;
import core.game.node.entity.player.link.music.MusicEntry;
import core.plugin.Initializable;
import core.plugin.Plugin;
/**
* Handles the interface tab buttons.
* @author Emperor
*/
@Initializable
public final class MusicTabInterface extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(187, this);
return this;
}
@Override
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
switch (opcode) {
case 155:
switch (button) {
case 11:
player.getMusicPlayer().toggleLooping();
return true;
case 1:
MusicEntry entry = player.getMusicPlayer().getUnlocked().get(slot);
if (entry == null) {
if(player.getRights().equals(Rights.ADMINISTRATOR)){
for(MusicEntry ent : MusicEntry.getSongs().values()){
if(ent.getIndex() == slot){
player.getMusicPlayer().unlock(ent.getId());
break;
}
}
} else {
player.getPacketDispatch().sendMessage("You have not unlocked this piece of music yet!</col>");
}
return true;
}
player.getMusicPlayer().setPlaying(false);
player.getMusicPlayer().play(entry);
return true;
}
break;
}
return false;
}
}

View file

@ -0,0 +1,57 @@
package content.global.handlers.iface
import core.api.*
import core.game.dialogue.FacialExpression
import core.game.interaction.InterfaceListener
import core.game.node.item.Item
import core.tools.StringUtils
import org.rs09.consts.Items
import org.rs09.consts.NPCs
class MysticStaffEnchantInterface : InterfaceListener {
override fun defineInterfaceListeners() {
on(INTERFACE_332) { player, _, _, buttonID, _, _ ->
val staff = buttonMap[buttonID] ?: return@on true
if (!inInventory(player, staff.basicID)) {
sendMessage(player, "You don't have a${if (StringUtils.isPlusN(getItemName(staff.basicID))) "n" else ""} ${getItemName(staff.basicID)} to enchant.")
return@on true
}
closeInterface(player)
if (!inInventory(player, Items.COINS_995, 40000)) {
sendNPCDialogue(player, NPCs.THORMAC_389, "I need ${String.format("%,d", 40000)} coins for materials. Come back when you have the money!", FacialExpression.NEUTRAL)
return@on true
}
if (removeItem(player, Item(staff.basicID, 1)) && removeItem(player, Item(Items.COINS_995, 40000))) {
sendNPCDialogue(player, NPCs.THORMAC_389, "Just a moment... hang on... hocus pocus abra-cadabra... there you go! Enjoy your enchanted staff!", FacialExpression.NEUTRAL)
addItem(player, staff.enchantedID, 1)
}
return@on true
}
}
enum class EnchantedStaff(val enchantedID: Int, val basicID: Int, val buttonID: Int) {
AIR(Items.MYSTIC_AIR_STAFF_1405, Items.AIR_BATTLESTAFF_1397, 21),
WATER(Items.MYSTIC_WATER_STAFF_1403, Items.WATER_BATTLESTAFF_1395, 22),
EARTH(Items.MYSTIC_EARTH_STAFF_1407, Items.EARTH_BATTLESTAFF_1399, 23),
FIRE(Items.MYSTIC_FIRE_STAFF_1401, Items.FIRE_BATTLESTAFF_1393, 24),
LAVA(Items.MYSTIC_LAVA_STAFF_3054, Items.LAVA_BATTLESTAFF_3053, 25),
MUD(Items.MYSTIC_MUD_STAFF_6563, Items.MUD_BATTLESTAFF_6562, 26),
STEAM(Items.MYSTIC_STEAM_STAFF_11738, Items.STEAM_BATTLESTAFF_11736, 27),
}
companion object {
private const val INTERFACE_332 = 332
val buttonMap = HashMap<Int, EnchantedStaff>()
init {
for (staff in EnchantedStaff.values()) {
buttonMap[staff.buttonID] = staff
}
}
}
}

View file

@ -1,95 +0,0 @@
package content.global.handlers.iface;
import core.game.component.Component;
import core.game.component.ComponentDefinition;
import core.game.component.ComponentPlugin;
import org.rs09.consts.Items;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import core.plugin.Plugin;
import core.plugin.Initializable;
import core.tools.StringUtils;
import java.util.HashMap;
/**
* Represents the plugin used to handle the agility ticket interface.
* @author afaroutdude
*/
@Initializable
public final class MysticStaffEnchantingPlugin extends ComponentPlugin {
private final Component COMPONENT = new Component(332);
protected enum EnchantedStaff {
AIR(Items.MYSTIC_AIR_STAFF_1405, Items.AIR_BATTLESTAFF_1397, 21),
WATER(Items.MYSTIC_WATER_STAFF_1403, Items.WATER_BATTLESTAFF_1395, 22),
EARTH(Items.MYSTIC_EARTH_STAFF_1407, Items.EARTH_BATTLESTAFF_1399, 23),
FIRE(Items.MYSTIC_FIRE_STAFF_1401, Items.FIRE_BATTLESTAFF_1393, 24),
LAVA(Items.MYSTIC_LAVA_STAFF_3054, Items.LAVA_BATTLESTAFF_3053, 25),
MUD(Items.MYSTIC_MUD_STAFF_6563, Items.MUD_BATTLESTAFF_6562, 26),
STEAM(Items.MYSTIC_STEAM_STAFF_11738, Items.STEAM_BATTLESTAFF_11736, 27);
public final int enchanted;
public final int basic;
public final int child;
private static final HashMap<Integer, Integer> basicToEnchanted = new HashMap<>();
private static final HashMap<Integer, Integer> childToBasic = new HashMap<>();
static {
for (EnchantedStaff staff : EnchantedStaff.values()) {
basicToEnchanted.put(staff.basic, staff.enchanted);
childToBasic.put(staff.child, staff.basic);
}
}
EnchantedStaff(int enchantedId, int basicId, int childId) {
this.enchanted = enchantedId;
this.basic = basicId;
this.child = childId;
}
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.forId(332).setPlugin(this);
return this;
}
@Override
public void open(Player player, Component component) {
super.open(player, component);
// zoom doesn't work, but based on https://youtu.be/qxxhhCdxBsQ?t=75 seems correct anyway
for (EnchantedStaff staff : EnchantedStaff.values()) {
player.getPacketDispatch().sendItemZoomOnInterface(staff.basic, 240, COMPONENT.getId(), staff.child);
}
}
@Override
public boolean handle(Player player, Component component, int opcode, int buttonId, int slot, int itemId) {
if (EnchantedStaff.childToBasic.containsKey(buttonId)) {
Item basicStaff = new Item(EnchantedStaff.childToBasic.get(buttonId));
Item enchantedStaff = new Item(EnchantedStaff.basicToEnchanted.get(basicStaff.getId()));
if (!player.getInventory().containsItem(basicStaff)) {
player.getPacketDispatch().sendMessage("You don't have a" + (StringUtils.isPlusN(basicStaff.getName()) ? "n " : " ") + basicStaff.getName() + " to enchant.");
return true;
}
int cost = player.getEquipment().contains(Items.SEERS_HEADBAND_14631, 1)? 27000 : 40000;
if (!player.getInventory().contains(995, cost)) {
player.getInterfaceManager().close();
player.getDialogueInterpreter().sendDialogues(389, null, "I need " + String.format("%,d", cost) + " coins for materials. Come", "back when you have the money!");
return true;
}
if (player.getInventory().remove(basicStaff, new Item(995, cost))) {
player.getInterfaceManager().close();
player.getDialogueInterpreter().sendDialogues(389, null, "Just a moment... hang on... hocus pocus abra-", "cadabra... there you go! Enjoy your enchanted staff!");
player.getInventory().add(enchantedStaff);
}
}
return true;
}
}

View file

@ -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.game.node.entity.player.link.prayer.PrayerType;
import core.plugin.Initializable;
import core.plugin.Plugin;
import static core.api.ContentAPIKt.hasRequirement;
import content.data.Quests;
/**
* Represents the prayer interface.
* @author 'Vexia
*/
@Initializable
public final class PrayerTabInterface extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(271, this);
return this;
}
@Override
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
final PrayerType type = PrayerType.get(button);
if (type == PrayerType.CHIVALRY || type == PrayerType.PIETY)
if (!hasRequirement(player, Quests.KINGS_RANSOM))
return true;
if (type == null) {
return true;
}
player.getPrayer().toggle(type);
return true;
}
}

View file

@ -1,71 +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.game.node.entity.player.link.diary.AchievementDiary;
import core.game.node.entity.player.link.diary.DiaryType;
import core.game.node.entity.player.link.quest.Quest;
import core.plugin.Initializable;
import core.plugin.Plugin;
/**
* Handles the quest tab reward buttons.
* @author Emperor
* @author Vexia
*/
@Initializable
public class QuestTabInterface extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(274, this); // Quests
ComponentDefinition.put(259, this); // Achievement diary
return this;
}
@Override
public boolean handle(Player p, Component component, int opcode, int button, int slot, int itemId) {
p.getPulseManager().clear();
switch (component.getId()) {
case 274:
// if (!GameWorld.isEconomyWorld()) {
// p.getSavedData().getSpawnData().handleButton(p, button);
// }
switch (button) {
case 3:
p.getAchievementDiaryManager().openTab();
return true;
case 10:
break;
default:
// if (GameWorld.isEconomyWorld()) {
Quest quest = p.getQuestRepository().forButtonId(button);
if (quest != null) {
p.getInterfaceManager().open(new Component(275));
quest.drawJournal(p, quest.getStage(p));
return true;
} else QuestTabUtils.showRequirementsInterface(p, button);
// }
return false;
}
break;
case 259:
switch (button) {
case 8:
p.getInterfaceManager().openTab(2, new Component(274));
return true;
default:
AchievementDiary diary = p.getAchievementDiaryManager().getDiary(DiaryType.forChild(button));
if (diary != null) {
diary.open(p);
}
return true;
}
}
return true;
}
}

View file

@ -1,89 +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 core.plugin.Initializable;
import core.game.node.entity.player.Player;
import core.plugin.Plugin;
/**
* @author 'Vexia
*/
@Initializable
public class SettingTabInterface extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(261, this);
return this;
}
@Override
public boolean handle(Player p, Component component, int opcode, int button, int slot, int itemId) {
switch (button) {
case 10:// brightness
int brightness = button - 7;
p.getSettings().setBrightness(brightness);
break;
case 11:
case 12:
case 13:
case 14:
case 15:// music
int volume = 15 - button;
p.getSettings().setMusicVolume(volume);
break;
case 16://530 settings
/* if (TutorialSession.getExtension(p).getStage() != TutorialSession.MAX_STAGE) {
p.sendMessage("You must finish the tutorial before opening the graphic settings.");
break;
}*/
p.getInterfaceManager().open(new Component(742));
break;
case 18://530 settings
p.getInterfaceManager().open(new Component(743));
break;
case 17:
case 19:
case 20:// sonund
int volume1 = 20 - button;
p.getSettings().setSoundEffectVolume(volume1);
break;
case 29:
case 30:
case 31:
case 32:
case 33:// all sound
int volume11 = 33 - button;
p.getSettings().setAreaSoundVolume(volume11);
break;
case 6:// mouse
p.getSettings().toggleMouseButton();
break;
case 4:// effects
p.getSettings().toggleChatEffects();
break;
case 5:// private chat
p.getSettings().toggleSplitPrivateChat();
break;
case 7:// aid
if (p.getIronmanManager().checkRestriction()) {
return true;
}
p.getSettings().toggleAcceptAid();
break;
case 3:// run
p.getSettings().toggleRun();
break;
case 8:// house
p.getInterfaceManager().close();
setVarp(p, 261, getVarp(p, 261) & 0x1);
p.getInterfaceManager().openSingleTab(new Component(398));
break;
}
return true;
}
}

View file

@ -1,32 +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;
import static core.api.ContentAPIKt.*;
/**
* Represents the plugin used for the skilling interface.
* @author 'Vexia
* @version 1.0
*/
@Initializable
public final class SkillInterface extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(499, this);
return this;
}
@Override
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
setVarbit(player, 3288, player.getAttribute("skillMenu", -1));
setVarbit(player, 3289, button - 10);
return true;
}
}

View file

@ -1,162 +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.skill.LevelUp;
import core.game.node.entity.skill.Skills;
import core.game.node.entity.player.Player;
import core.game.world.GameWorld;
import core.plugin.Initializable;
import core.plugin.Plugin;
import static core.api.ContentAPIKt.*;
/**
* Represents the plugin used to handle the skilling tab.
* @author Vexia
* @author Splinter
* @version 1.1
*/
@Initializable
public final class SkillTabInterface extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(320, this);
return this;
}
@Override
public boolean handle(Player p, Component component, int opcode, int button, int slot, int itemId) {
final SkillConfig config = SkillConfig.forId(button);
if (config == null) {
return true;
}
if (!GameWorld.getSettings().isPvp()) {
if (p.getAttribute("levelup:" + config.getSkillId(), false)) {
p.removeAttribute("levelup:" + config.getSkillId());
LevelUp.sendFlashingIcons(p, -1);
setVarp(p, 1230, ADVANCE_CONFIGS[config.getSkillId()]);
p.getInterfaceManager().open(new Component(741));
} else {
p.getPulseManager().clear();
p.getInterfaceManager().open(new Component(499));
setVarp(p, 965, config.getConfig());
p.getAttributes().put("skillMenu", config.getConfig());
}
} else {
if (config.getSkillId() > 6) {
p.getPacketDispatch().sendMessage("You cannot set a target level for this skill.");
return false;
}
if (p.canSpawn()) {
p.sendMessage("You must be inside Edgeville bank to set levels.");
return false;
}
}
return true;
}
/**
* Holds all the config values of the skill advances.
*/
public static final int[] ADVANCE_CONFIGS = {
9, 40, 17, 49,
25, 57, 33, 641,
659, 664, 121, 649,
89, 114, 107, 72,
64, 80, 673, 680,
99, 698, 689, 705,
};
public enum SkillConfig {
ATTACK(125, 1, Skills.ATTACK),
STRENGTH(126, 2, Skills.STRENGTH),
DEFENCE(127, 5, Skills.DEFENCE),
RANGE(128, 3, Skills.RANGE),
PRAYER(129, 7, Skills.PRAYER),
MAGIC(130, 4, Skills.MAGIC),
RUNECRAFTING(131, 12, Skills.RUNECRAFTING),
HITPOINTS(133, 6, Skills.HITPOINTS),
AGILITY(134, 8, Skills.AGILITY),
HERBLORE(135, 9, Skills.HERBLORE),
THIEVING(136, 10, Skills.THIEVING),
CRAFTING(137, 11, Skills.CRAFTING),
FLETCHING(138, 19, Skills.FLETCHING),
SLAYER(139, 20, Skills.SLAYER),
MINING(141, 13, Skills.MINING),
SMITHING(142, 14, Skills.SMITHING),
FISHING(143, 15, Skills.FISHING),
COOKING(144, 16, Skills.COOKING),
FIREMAKING(145, 17, Skills.FIREMAKING),
WOODCUTTING(146, 18, Skills.WOODCUTTING),
FARMING(147, 21, Skills.FARMING),
CONSTRUCTION(132, 22, Skills.CONSTRUCTION),
HUNTER(140, 23, Skills.HUNTER),
SUMMONING(148, 24, Skills.SUMMONING);
/**
* Constructs a new {@code SkillConfig} {@code Object}.
* @param button the button.
* @param config the config.
*/
SkillConfig(int button, int config, int skillId) {
this.button = button;
this.config = config;
this.skillId = skillId;
}
/**
* Represents the button.
*/
private int button;
/**
* Represents the config.
*/
private int config;
/**
* The skill id.
*/
private int skillId;
/**
* Gets the skill config.
* @param id the id.
* @return the skill config.
*/
public static SkillConfig forId(int id) {
for (SkillConfig config : SkillConfig.values()) {
if (config.button == id)
return config;
}
return null;
}
/**
* Gets the button.
* @return the button.
*/
public int getButton() {
return button;
}
/**
* Gets the config.
* @return the config.
*/
public int getConfig() {
return config;
}
/**
* Gets the skill id.
* @return The skill id.
*/
public int getSkillId() {
return skillId;
}
}
}

View file

@ -0,0 +1,109 @@
package content.global.handlers.iface.tabs
import core.api.sendInputDialogue
import core.api.sendMessage
import core.game.interaction.InterfaceListener
import core.game.system.communication.ClanRank
import core.game.system.communication.ClanRepository
import core.net.amsc.MSPacketRepository
import core.net.amsc.WorldCommunicator
import core.tools.StringUtils
import org.rs09.consts.Components
class ClanTabInterface : InterfaceListener {
override fun defineInterfaceListeners() {
on(Components.CLANJOIN_589) { player, _, _, buttonID, _, _ ->
if (buttonID == 9) {
if (player.interfaceManager.opened != null) {
sendMessage(player, "Please close the interface you have open before using 'Clan Setup'")
} else {
ClanRepository.openSettings(player)
}
}
if (buttonID == 14) {
player.communication.toggleLootshare(player)
}
return@on true
}
on(Components.CLANSETUP_590) { player, _, opcode, buttonID, _, _ ->
val clan = ClanRepository.get(player.name, true)
when (buttonID) {
22 -> {
if (opcode == 155) {
sendInputDialogue(player, false, "Enter clan prefix:", ) { value ->
val clanName = StringUtils.formatDisplayName(value.toString())
if (WorldCommunicator.isEnabled()) { MSPacketRepository.sendClanRename(player, clanName) }
if (clan.name == "Chat disabled") {
sendMessage(player, "Your clan channel has now been enabled!")
sendMessage(player, "Join your channel by clicking 'Join Chat' and typing: ${player.username}")
}
clan.name = clanName
player.communication.clanName = clanName
clan.updateSettings(player)
clan.update()
}
}
if (opcode == 196) {
clan.name = "Chat disabled"
player.communication.clanName = ""
if (WorldCommunicator.isEnabled()) { MSPacketRepository.sendClanRename(player, player.communication.clanName) }
clan.updateSettings(player)
clan.delete()
}
}
23 -> {
clan.joinRequirement = getRank(opcode)
player.communication.joinRequirement = clan.joinRequirement
MSPacketRepository.setClanSetting(player, 0, clan.joinRequirement)
}
24 -> {
clan.messageRequirement = getRank(opcode)
player.communication.messageRequirement = clan.messageRequirement
MSPacketRepository.setClanSetting(player, 1, clan.messageRequirement)
}
25 -> {
clan.kickRequirement = getRank(opcode)
player.communication.kickRequirement = clan.kickRequirement
MSPacketRepository.setClanSetting(player, 2, clan.kickRequirement)
}
26 -> {
clan.lootRequirement = if (opcode == 155) ClanRank.ADMINISTRATOR else getRank(opcode)
player.communication.lootRequirement = clan.lootRequirement
MSPacketRepository.setClanSetting(player, 3, clan.lootRequirement)
}
33 -> sendMessage(player, "CoinShare is not available.")
}
clan.updateSettings(player)
clan.update()
return@on true
}
}
fun getRank(opcode: Int): ClanRank {
return when (opcode) {
155 -> ClanRank.NONE
196 -> ClanRank.FRIEND
124 -> ClanRank.RECRUIT
199 -> ClanRank.CORPORAL
234 -> ClanRank.SERGEANT
168 -> ClanRank.LIEUTENANT
166 -> ClanRank.CAPTAIN
64 -> ClanRank.GENERAL
53 -> ClanRank.OWNER
else -> ClanRank.NONE
}
}
}

View file

@ -1,4 +1,4 @@
package content.global.handlers.iface; package content.global.handlers.iface.tabs;
import core.game.component.Component; import core.game.component.Component;
import core.game.component.ComponentDefinition; import core.game.component.ComponentDefinition;

View file

@ -0,0 +1,14 @@
package content.global.handlers.iface.tabs
import core.game.interaction.InterfaceListener
import core.game.node.entity.player.link.emote.Emotes
import org.rs09.consts.Components
class EmoteTabInterface : InterfaceListener {
override fun defineInterfaceListeners() {
on(Components.EMOTES_464) { player, _, _, buttonID, _, _ ->
Emotes.handle(player, buttonID)
return@on true
}
}
}

View file

@ -0,0 +1,136 @@
package content.global.handlers.iface.tabs
import content.global.skill.summoning.familiar.BurdenBeast
import core.api.*
import core.game.container.access.InterfaceContainer
import core.game.container.impl.EquipmentContainer
import core.game.global.action.EquipHandler
import core.game.interaction.IntType
import core.game.interaction.InteractionListeners
import core.game.interaction.InterfaceListener
import core.game.node.entity.combat.DeathTask
import core.game.node.entity.player.Player
import core.game.node.entity.player.link.prayer.PrayerType
import core.tools.Log
import org.rs09.consts.Components
import org.rs09.consts.Items
class EquipmentTabInterface : InterfaceListener {
override fun defineInterfaceListeners() {
onOpen(ITEMS_KEPT_ON_DEATH_102) { player, component ->
/**
* (Highlight white items are auto destroyed on death Enum#616 (Items kept on death interface) TODO: Parse server sided
* CS2 Script 118 - Items kept on death interface
* Credit Woahscam for figuring this all out.
* @arg_0 (Int): Zone type - 0 Default/1 Safe/2 POH/3 Castle Wars/4 Trouble Brewing/5 Barbarian Assault
* @arg_1 (Int): Amount of items kept on death - 0/1/3/4
* @arg_2 (Object): Item kept on death - slot 0 item id
* @arg_3 (Object): Item kept on death - slot 1 item id
* @arg_4 (Object): Item kept on death - slot 2 item id
* @arg_5 (Object): Item kept on death - slot 3 item id
* @arg_6 (Int): Player is skulled - 0 Not Skulled/1 Skulled
* @arg_7 (Int): Player has BoB summoned with items - 0 BoB not summoned or has no items /1 BoB summoned with items
* @arg_8 (String): String to append based on amount of items kept on death.
*/
val zoneType = player.zoneMonitor.type
val itemsKeptOnDeath = DeathTask.getContainers(player)[0]
val amountKeptOnDeath = if (!player.skullManager.isSkulled && itemsKeptOnDeath.itemCount() < 3) {
if (player.prayer[PrayerType.PROTECT_ITEMS]) 4 else 3
} else {
itemsKeptOnDeath.itemCount()
}
val slot0 = itemsKeptOnDeath.getId(0)
val slot1 = itemsKeptOnDeath.getId(1)
val slot2 = itemsKeptOnDeath.getId(2)
val slot3 = itemsKeptOnDeath.getId(3)
val hasSkull = if (player.skullManager.isSkulled) 1 else 0
val beast: BurdenBeast? = if (player.familiarManager.hasFamiliar() && player.familiarManager.familiar.isBurdenBeast) player.familiarManager.familiar as BurdenBeast else null
val hasBob = if (beast != null && !beast.container.isEmpty) 1 else 0
val message = "You are skulled."
val cs2Args = arrayOf<Any>(hasBob, hasSkull, slot3, slot2, slot1, slot0, amountKeptOnDeath, zoneType, message)
if (amountKeptOnDeath > 4 && zoneType == 0) {
log(this::class.java, Log.ERR, "Items kept on death interface should not contain more than 4 items when not in a safe zone!")
}
player.packetDispatch.sendRunScript(118, "siiooooii", *cs2Args)
val settings = IfaceSettingsBuilder().enableAllOptions().build()
player.packetDispatch.sendIfaceSettings(settings, 18, component.id, 0, itemsKeptOnDeath.itemCount())
player.packetDispatch.sendIfaceSettings(settings, 21, component.id, 0, DeathTask.getContainers(player)[1].itemCount())
return@onOpen true
}
on(Components.WORNITEMS_387) { player, component, opcode, buttonID, slot, itemID ->
when (buttonID) {
28 -> {
if (opcode == 81) EquipHandler.unequip(player, slot, itemID)
if (opcode == 206) operateItem(player, slot)
}
52 -> openInterface(player, ITEMS_KEPT_ON_DEATH_102)
55 -> openInterface(player, Components.EQUIP_SCREEN2_667)
}
return@on true
}
onOpen(Components.EQUIP_SCREEN2_667) { player, component ->
val settings = IfaceSettingsBuilder().enableAllOptions().build()
player.packetDispatch.sendIfaceSettings(settings, 14, component.id, 0, 13)
EquipmentContainer.update(player)
openSingleTab(player, Components.INVENTORY_WEAR2_670)
return@onOpen true
}
on(Components.EQUIP_SCREEN2_667) { player, _, opcode, buttonID, slot, itemID ->
if (buttonID == 14) {
when (opcode) {
9 -> sendMessage(player, player.equipment.get(slot).definition.examine)
155 -> EquipHandler.unequip(player, slot, itemID)
196 -> operateItem(player, slot)
}
}
return@on true
}
onClose(Components.EQUIP_SCREEN2_667) { player, _ ->
closeTabInterface(player)
return@onClose true
}
onOpen(Components.INVENTORY_WEAR2_670) { player, component ->
InterfaceContainer.generateItems(player, player.inventory.toArray(), arrayOf("Equip"), component.id, 0, 7, 4, 93)
return@onOpen true
}
on(Components.INVENTORY_WEAR2_670) { player, _, opcode, _, slot, _ ->
if (opcode == 9) sendMessage(player, player.inventory.get(slot).definition.examine)
if (opcode == 155) equipItem(player, slot)
return@on true
}
}
private fun equipItem(player: Player, slot: Int) {
val item = player.inventory.get(slot) ?: return
if (item.definition.options.any { it in arrayOf("Equip", "Wield", "Wear") } || item.id == Items.BEER_1917) {
InteractionListeners.run(item.id, IntType.ITEM, "equip", player, item)
} else {
sendMessage(player, "You can't wear that.")
}
}
private fun operateItem(player: Player, slot: Int) {
val item = player.equipment.get(slot) ?: return
when {
InteractionListeners.run(item.id, IntType.ITEM, "operate", player, item) -> return
item.operateHandler?.handle(player, item, "operate") == true -> return
else -> sendMessage(player, "You can't operate that.")
}
}
companion object {
private const val ITEMS_KEPT_ON_DEATH_102 = 102
}
}

View file

@ -0,0 +1,34 @@
package content.global.handlers.iface.tabs
import core.api.sendMessage
import core.game.interaction.InterfaceListener
import core.game.world.repository.Repository
import org.rs09.consts.Components
class LogoutTabInterface : InterfaceListener {
override fun defineInterfaceListeners() {
on(Components.LOGOUT_182) { player, _, _, buttonID, _, _ ->
if (buttonID == 6) {
return@on when {
!player.zoneMonitor.canLogout() -> true
player.inCombat() -> {
sendMessage(player, "You can't log out until 10 seconds after the end of combat.")
true
}
player.isTeleporting -> {
sendMessage(player, "Please finish your teleport before logging out.")
true
}
else -> {
Repository.disconnectionQueue.add(player)
true
}
}
}
return@on true
}
}
}

View file

@ -0,0 +1,23 @@
package content.global.handlers.iface.tabs
import content.global.skill.magic.SpellListener
import content.global.skill.magic.SpellListeners
import core.api.getAttribute
import core.game.interaction.InterfaceListener
import core.game.node.entity.combat.spell.MagicSpell
import core.game.node.entity.player.link.SpellBookManager.SpellBook
import core.game.world.GameWorld
class MagicTabInterface : InterfaceListener {
override fun defineInterfaceListeners() {
SpellBook.values().forEach {
on(it.interfaceId) { player, _, _, buttonID, _, _ ->
if (GameWorld.ticks < getAttribute(player, "magic:delay", -1)) return@on true
SpellListeners.run(buttonID, SpellListener.NONE, it.name.lowercase(), player)
return@on MagicSpell.castSpell(player, it, buttonID, player)
}
}
}
}

View file

@ -0,0 +1,38 @@
package content.global.handlers.iface.tabs
import core.api.sendMessage
import core.game.interaction.InterfaceListener
import core.game.node.entity.player.link.music.MusicEntry
import org.rs09.consts.Components
class MusicTabInterface : InterfaceListener {
override fun defineInterfaceListeners() {
on(Components.MUSIC_V3_187) { player, _, opcode, buttonID, slot, _ ->
if (opcode == 155) {
if (buttonID == 11) {
player.musicPlayer.toggleLooping()
return@on true
}
if (buttonID == 1) {
if (player.musicPlayer.unlocked[slot] != null) {
player.musicPlayer.play(player.musicPlayer.unlocked[slot])
return@on true
}
if (player.isAdmin) {
for (entry in MusicEntry.getSongs().values) {
if (entry.index == slot) {
player.musicPlayer.unlock(entry.id)
}
}
} else {
sendMessage(player, "You have not unlocked this piece of music yet!")
}
return@on true
}
}
return@on true
}
}
}

View file

@ -0,0 +1,14 @@
package content.global.handlers.iface.tabs
import core.game.interaction.InterfaceListener
import core.game.node.entity.player.link.prayer.PrayerType
import org.rs09.consts.Components
class PrayerTabInterface : InterfaceListener {
override fun defineInterfaceListeners() {
on(Components.PRAYER_271) { player, _, _, buttonID, _, _ ->
val prayer = PrayerType.get(buttonID) ?: return@on true
return@on player.prayer.toggle(prayer)
}
}
}

View file

@ -0,0 +1,36 @@
package content.global.handlers.iface.tabs
import content.global.handlers.iface.tabs.QuestTabUtils.showRequirementsInterface
import core.api.openInterface
import core.game.component.Component
import core.game.interaction.InterfaceListener
import core.game.node.entity.player.link.diary.DiaryType
import org.rs09.consts.Components
class QuestTabInterface : InterfaceListener {
override fun defineInterfaceListeners() {
on(Components.QUESTJOURNAL_V2_274) { player, _, _, buttonID, _, _ ->
if (buttonID == 3) {
player.achievementDiaryManager.openTab()
} else {
val quest = player.questRepository.forButtonId(buttonID)
if (quest != null) {
openInterface(player, Components.QUESTJOURNAL_SCROLL_275)
quest.drawJournal(player, quest.getStage(player))
} else {
showRequirementsInterface(player, buttonID)
}
}
return@on true
}
on(Components.AREA_TASK_259) { player, _, _, buttonID, _, _ ->
if (buttonID == 8) {
player.interfaceManager.openTab(2, Component(Components.QUESTJOURNAL_V2_274))
} else {
player.achievementDiaryManager.getDiary(DiaryType.forChild(buttonID))?.open(player)
}
return@on true
}
}
}

View file

@ -1,4 +1,4 @@
package content.global.handlers.iface package content.global.handlers.iface.tabs
import core.game.requirement.* import core.game.requirement.*
import core.api.* import core.api.*

View file

@ -0,0 +1,35 @@
package content.global.handlers.iface.tabs
import core.api.*
import core.game.interaction.InterfaceListener
import core.game.node.entity.player.link.IronmanMode
import org.rs09.consts.Components
class SettingsTabInterface : InterfaceListener {
override fun defineInterfaceListeners() {
on(Components.OPTIONS_261) { player, _, _, buttonID, _, _ ->
when (buttonID) {
RUN -> player.settings.toggleRun()
CHAT_EFFECTS -> player.settings.toggleChatEffects()
SPLIT_PM -> player.settings.toggleSplitPrivateChat()
MOUSE -> player.settings.toggleMouseButton()
AID -> restrictForIronman(player, IronmanMode.STANDARD) { player.settings.toggleAcceptAid() }
HOUSE -> openSingleTab(player, Components.POH_HOUSE_OPTIONS_398)
GRAPHICS -> openInterface(player, Components.GRAPHICS_OPTIONS_742)
AUDIO -> openInterface(player, Components.SOUND_OPTIONS_743)
}
return@on true
}
}
companion object {
const val RUN = 3
const val CHAT_EFFECTS = 4
const val SPLIT_PM = 5
const val MOUSE = 6
const val AID = 7
const val HOUSE = 8
const val GRAPHICS = 16
const val AUDIO = 18
}
}

View file

@ -0,0 +1,87 @@
package content.global.handlers.iface.tabs
import core.api.*
import core.game.interaction.InterfaceListener
import core.game.node.entity.skill.LevelUp
import core.game.node.entity.skill.Skills
import org.rs09.consts.Components
class StatsTabInterface : InterfaceListener {
override fun defineInterfaceListeners() {
on(Components.STATS_320) { player, _, _, buttonID, _, _ ->
val config = skillMap[buttonID] ?: return@on true
if (getAttribute(player, "levelup:${config.skillID}", false)) {
removeAttributes(player, "levelup:${config.skillID}")
LevelUp.sendFlashingIcons(player, -1)
setVarp(player, 1230, ADVANCE_CONFIGS[config.skillID])
openInterface(player, 741)
} else {
openInterface(player, Components.SKILL_GUIDE_V2_499)
setVarp(player, 965, config.configID)
setAttribute(player, "skillMenu", config.configID)
}
return@on true
}
on(Components.SKILL_GUIDE_V2_499) { player, _, _, buttonID, _, _ ->
setVarbit(player, 3288, getAttribute(player, "skillMenu", -1))
setVarbit(player, 3289, buttonID - 10)
return@on true
}
on(LEVEL_UP_INTERFACE_740) { player, component, opcode, buttonID, slot, itemID ->
if (buttonID == 3) {
closeInterface(player)
}
return@on true
}
}
enum class SkillConfig(val buttonID: Int, val configID: Int, val skillID: Int) {
ATTACK(125, 1, Skills.ATTACK),
STRENGTH(126, 2, Skills.STRENGTH),
DEFENCE(127, 5, Skills.DEFENCE),
RANGE(128, 3, Skills.RANGE),
PRAYER(129, 7, Skills.PRAYER),
MAGIC(130, 4, Skills.MAGIC),
RUNECRAFT(131, 12, Skills.RUNECRAFTING),
HITPOINTS(133, 6, Skills.HITPOINTS),
AGILITY(134, 8, Skills.AGILITY),
HERBLORE(135, 9, Skills.HERBLORE),
THIEVING(136, 10, Skills.THIEVING),
CRAFTING(137, 11, Skills.CRAFTING),
FLETCHING(138, 19, Skills.FLETCHING),
SLAYER(139, 20, Skills.SLAYER),
MINING(141, 13, Skills.MINING),
SMITHING(142, 14, Skills.SMITHING),
FISHING(143, 15, Skills.FISHING),
COOKING(144, 16, Skills.COOKING),
FIREMAKING(145, 17, Skills.FIREMAKING),
WOODCUTTING(146, 18, Skills.WOODCUTTING),
FARMING(147, 21, Skills.FARMING),
CONSTRUCTION(132, 22, Skills.CONSTRUCTION),
HUNTER(140, 23, Skills.HUNTER),
SUMMONING(148, 24, Skills.SUMMONING),
}
companion object {
private const val LEVEL_UP_INTERFACE_740 = 740
val skillMap= HashMap<Int, SkillConfig>()
val ADVANCE_CONFIGS = intArrayOf(
9, 40, 17, 49,
25, 57, 33, 641,
659, 664, 121, 649,
89, 114, 107, 72,
64, 80, 673, 680,
99, 698, 689, 705
)
init {
for (skill in SkillConfig.values()) {
skillMap[skill.buttonID] = skill
}
}
}
}

View file

@ -25,8 +25,7 @@ class EctophialListener : InteractionListener {
delayEntity(player, fillAnimation.duration) delayEntity(player, fillAnimation.duration)
animate(player, fillAnimation) animate(player, fillAnimation)
playAudio(player, Sounds.FILL_ECTOPLASM_1132) playAudio(player, Sounds.FILL_ECTOPLASM_1132)
if (removeItem(player, Items.ECTOPHIAL_4252)) { if (removeItem(player, Items.ECTOPHIAL_4252) && addItem(player, Items.ECTOPHIAL_4251)) {
addItem(player, Items.ECTOPHIAL_4251)
sendMessage(player, "You refill the ectophial from the Ectofuntus.") sendMessage(player, "You refill the ectophial from the Ectofuntus.")
} }
} }

View file

@ -17,7 +17,7 @@ class EmptyOptionListener : InteractionListener {
override fun defineListeners() { override fun defineListeners() {
on(EmptyItem.emptyItemList.toIntArray(), IntType.ITEM, "empty", "empty bowl", "empty dish") { player, node -> on(EmptyItem.emptyItemList.toIntArray(), IntType.ITEM, "empty", "empty bowl", "empty dish") { player, node ->
if (node.name.contains("brew") || node.name.contains("potion") || node.name.lowercase(Locale.getDefault()).contains("poison") || node.name.lowercase(Locale.getDefault()).contains("serum") || node.name.contains("cure") || node.name.contains("mix") || node.name.contains("balm")) { if (node.name.contains("brew") || node.name.contains("potion") || node.name.lowercase(Locale.getDefault()).contains("poison") || node.name.lowercase(Locale.getDefault()).contains("serum") || node.name.contains("cure") || node.name.contains("mix") || node.name.contains("balm") || node.name.contains("Super ")) {
replaceSlot(player, node.asItem().slot, Item(EmptyItem.getEmpty(Items.POTION_195)!!), node.asItem()) replaceSlot(player, node.asItem().slot, Item(EmptyItem.getEmpty(Items.POTION_195)!!), node.asItem())
playAudio(player, EmptyItem.getEmptyAudio(Items.POTION_195)!!) playAudio(player, EmptyItem.getEmptyAudio(Items.POTION_195)!!)
return@on true return@on true
@ -48,6 +48,7 @@ class EmptyOptionListener : InteractionListener {
POTION(Items.POTION_195, Items.VIAL_229, "You empty the vial.", Sounds.LIQUID_2401), POTION(Items.POTION_195, Items.VIAL_229, "You empty the vial.", Sounds.LIQUID_2401),
BURNT_STEW(Items.BURNT_STEW_2005, Items.BOWL_1923, "You empty the contents of the bowl onto the floor.", Sounds.LIQUID_2401), BURNT_STEW(Items.BURNT_STEW_2005, Items.BOWL_1923, "You empty the contents of the bowl onto the floor.", Sounds.LIQUID_2401),
NETTLE_TEA(Items.NETTLE_TEA_4239, Items.BOWL_1923, "You empty the contents of the bowl onto the floor.", Sounds.LIQUID_2401), NETTLE_TEA(Items.NETTLE_TEA_4239, Items.BOWL_1923, "You empty the contents of the bowl onto the floor.", Sounds.LIQUID_2401),
CUP_OF_TEA(Items.CUP_OF_TEA_4242, Items.EMPTY_CUP_1980, "You empty the cup of tea.", Sounds.LIQUID_2401),
NETTLE_WATER(Items.NETTLE_WATER_4237, Items.BOWL_1923, "You empty the contents of the bowl onto the floor.", Sounds.LIQUID_2401), NETTLE_WATER(Items.NETTLE_WATER_4237, Items.BOWL_1923, "You empty the contents of the bowl onto the floor.", Sounds.LIQUID_2401),
NETTLE_TEA_MILKY(Items.NETTLE_TEA_4240, Items.BOWL_1923, "You empty the contents of the bowl onto the floor.", Sounds.LIQUID_2401), NETTLE_TEA_MILKY(Items.NETTLE_TEA_4240, Items.BOWL_1923, "You empty the contents of the bowl onto the floor.", Sounds.LIQUID_2401),
BURNT_CURRY(Items.BURNT_CURRY_2013, Items.BOWL_1923, "You empty the contents of the bowl onto the floor.", Sounds.LIQUID_2401), BURNT_CURRY(Items.BURNT_CURRY_2013, Items.BOWL_1923, "You empty the contents of the bowl onto the floor.", Sounds.LIQUID_2401),
@ -70,7 +71,7 @@ class EmptyOptionListener : InteractionListener {
emptyItemList.add(item.fullId) emptyItemList.add(item.fullId)
} }
for (item in ItemDefinition.getDefinitions().values) for (item in ItemDefinition.getDefinitions().values)
if (item.name.contains("potion") || item.name.contains("brew") || item.name.contains("poison") || item.name.lowercase(Locale.getDefault()).contains("serum") || item.name.contains("cure") || item.name.contains("mix") || item.name.contains("balm")) { if (item.name.contains("potion") || item.name.contains("brew") || item.name.contains("poison") || item.name.lowercase(Locale.getDefault()).contains("serum") || item.name.contains("cure") || item.name.contains("mix") || item.name.contains("balm") || item.name.contains("Super ")) {
emptyItemList.add(item.id) emptyItemList.add(item.id)
} }
} }

View file

@ -1,86 +1,94 @@
package content.global.handlers.item package content.global.handlers.item
import core.ServerConstants
import core.api.* import core.api.*
import core.game.interaction.IntType import core.game.interaction.IntType
import core.game.interaction.InteractionListener import core.game.interaction.InteractionListener
import core.game.interaction.QueueStrength import core.game.interaction.QueueStrength
import core.game.node.entity.player.info.LogType
import core.game.node.entity.player.info.PlayerMonitor
import core.game.node.item.Item
import core.game.world.update.flag.context.Animation
import org.rs09.consts.Animations
import org.rs09.consts.Items import org.rs09.consts.Items
import org.rs09.consts.Sounds import org.rs09.consts.Sounds
class EnchantJewelleryTabListener : InteractionListener { class EnchantJewelleryTabListener : InteractionListener {
private val LVL_1_ENCHANT = mapOf( private val LVL_1_ENCHANT = mapOf(
Items.SAPPHIRE_RING_1637 to Items.RING_OF_RECOIL_2550, Items.SAPPHIRE_RING_1637 to Items.RING_OF_RECOIL_2550,
Items.SAPPHIRE_NECKLACE_1656 to Items.GAMES_NECKLACE8_3853, Items.SAPPHIRE_NECKLACE_1656 to Items.GAMES_NECKLACE8_3853,
Items.SAPPHIRE_AMULET_1694 to Items.AMULET_OF_MAGIC_1727, Items.SAPPHIRE_AMULET_1694 to Items.AMULET_OF_MAGIC_1727,
Items.SAPPHIRE_BRACELET_11072 to Items.BRACELET_OF_CLAY_11074 Items.SAPPHIRE_BRACELET_11072 to Items.BRACELET_OF_CLAY_11074
) )
private val LVL_2_ENCHANT = mapOf( private val LVL_2_ENCHANT = mapOf(
Items.EMERALD_RING_1639 to Items.RING_OF_DUELLING8_2552, Items.EMERALD_RING_1639 to Items.RING_OF_DUELLING8_2552,
Items.EMERALD_NECKLACE_1658 to Items.BINDING_NECKLACE_5521, Items.EMERALD_NECKLACE_1658 to Items.BINDING_NECKLACE_5521,
Items.EMERALD_AMULET_1696 to Items.AMULET_OF_DEFENCE_1729, Items.EMERALD_AMULET_1696 to Items.AMULET_OF_DEFENCE_1729,
Items.EMERALD_BRACELET_11076 to Items.CASTLEWAR_BRACE3_11079 Items.EMERALD_BRACELET_11076 to Items.CASTLEWAR_BRACE3_11079
) )
private val LVL_3_ENCHANT = mapOf( private val LVL_3_ENCHANT = mapOf(
Items.RUBY_RING_1641 to Items.RING_OF_FORGING_2568, Items.RUBY_RING_1641 to Items.RING_OF_FORGING_2568,
Items.RUBY_NECKLACE_1660 to Items.DIGSITE_PENDANT_5_11194, Items.RUBY_NECKLACE_1660 to Items.DIGSITE_PENDANT_5_11194,
Items.RUBY_AMULET_1698 to Items.AMULET_OF_STRENGTH_1725, Items.RUBY_AMULET_1698 to Items.AMULET_OF_STRENGTH_1725,
Items.RUBY_BRACELET_11085 to Items.INOCULATION_BRACE_11088 Items.RUBY_BRACELET_11085 to Items.INOCULATION_BRACE_11088
) )
private val LVL_4_ENCHANT = mapOf( private val LVL_4_ENCHANT = mapOf(
Items.DIAMOND_RING_1643 to Items.RING_OF_LIFE_2570, Items.DIAMOND_RING_1643 to Items.RING_OF_LIFE_2570,
Items.DIAMOND_NECKLACE_1662 to Items.PHOENIX_NECKLACE_11090, Items.DIAMOND_NECKLACE_1662 to Items.PHOENIX_NECKLACE_11090,
Items.DIAMOND_AMULET_1700 to Items.AMULET_OF_POWER_1731, Items.DIAMOND_AMULET_1700 to Items.AMULET_OF_POWER_1731,
Items.DIAMOND_BRACELET_11092 to Items.FORINTHRY_BRACE5_11095 Items.DIAMOND_BRACELET_11092 to Items.FORINTHRY_BRACE5_11095
) )
private val LVL_5_ENCHANT = mapOf( private val LVL_5_ENCHANT = mapOf(
Items.DRAGONSTONE_RING_1645 to Items.RING_OF_WEALTH4_14646, Items.DRAGONSTONE_RING_1645 to Items.RING_OF_WEALTH_2572,
Items.DRAGON_NECKLACE_1664 to Items.SKILLS_NECKLACE4_11105, Items.DRAGON_NECKLACE_1664 to Items.SKILLS_NECKLACE_11113,
Items.DRAGONSTONE_AMMY_1702 to Items.AMULET_OF_GLORY4_1712, Items.DRAGONSTONE_AMMY_1702 to Items.AMULET_OF_GLORY_1704,
Items.DRAGON_BRACELET_11115 to Items.COMBAT_BRACELET4_11118 Items.DRAGON_BRACELET_11115 to Items.COMBAT_BRACELET_11126
) )
private val LVL_6_ENCHANT = mapOf( private val LVL_6_ENCHANT = mapOf(
Items.ONYX_RING_6575 to Items.RING_OF_STONE_6583, Items.ONYX_RING_6575 to Items.RING_OF_STONE_6583,
Items.ONYX_NECKLACE_6577 to Items.BERSERKER_NECKLACE_11128, Items.ONYX_NECKLACE_6577 to Items.BERSERKER_NECKLACE_11128,
Items.ONYX_AMULET_6581 to Items.AMULET_OF_FURY_6585, Items.ONYX_AMULET_6581 to Items.AMULET_OF_FURY_6585,
Items.ONYX_BRACELET_11130 to Items.REGEN_BRACELET_11133 Items.ONYX_BRACELET_11130 to Items.REGEN_BRACELET_11133
)
private val TAB_MAPPING = arrayOf(
Pair(Items.ENCHANT_SAPPHIRE_8016, LVL_1_ENCHANT),
Pair(Items.ENCHANT_EMERALD_8017, LVL_2_ENCHANT),
Pair(Items.ENCHANT_RUBY_8018, LVL_3_ENCHANT),
Pair(Items.ENCHANT_DIAMOND_8019, LVL_4_ENCHANT),
Pair(Items.ENCHANT_DRAGONSTN_8020, LVL_5_ENCHANT),
Pair(Items.ENCHANT_ONYX_8021, LVL_6_ENCHANT)
) )
override fun defineListeners() { override fun defineListeners() {
on(IntType.ITEM, "break") {player, node -> for ((tablet, mapping) in TAB_MAPPING) {
closeAllInterfaces(player) on(tablet, IntType.ITEM, "break") { player, _ ->
delayEntity(player, 1) sendMessage(player, "Try using the tablet on the item instead.") //TODO authentic message
queueScript(player, strength = QueueStrength.SOFT) { return@on true
}
val items = when (node.id) { for ((unenchanted, enchanted) in mapping) {
8016 -> LVL_1_ENCHANT //Sapphire onUseWith(IntType.ITEM, tablet, unenchanted) { player, tabItem, node ->
8017 -> LVL_2_ENCHANT var product = enchanted
8018 -> LVL_3_ENCHANT if (product == Items.RING_OF_WEALTH_2572 && ServerConstants.RING_OF_WEALTH_TELEPORT) {
8019 -> LVL_4_ENCHANT product = Items.RING_OF_WEALTH_14638
8020 -> LVL_5_ENCHANT }
8021 -> LVL_6_ENCHANT if (removeItem(player, Item(tabItem.id))) {
else -> return@queueScript stopExecuting(player) closeAllInterfaces(player)
} playAudio(player, Sounds.POH_TABLET_BREAK_979)
val anim = Animation(Animations.POH_TABLET_BREAK_4069)
if (inInventory(player, node.id)) { animate(player, anim, true)
for (item in player.inventory.toArray()) { delayEntity(player, anim.duration)
if (item == null) continue queueScript(player, anim.duration, QueueStrength.SOFT) {
val product = items[item.id] ?: continue val item = node.asItem()
if (removeItem(player, node.id) && (removeItem(player, item.id))) { val ret = replaceSlot(player, item.slot, Item(product), item)
addItem(player, product) if (ret != item) {
playAudio(player, Sounds.POH_TABLET_BREAK_979) PlayerMonitor.log(player, LogType.DUPE_ALERT, "Unknown slot-replacement problem when enchanting jewellery (adding $product replaced $ret rather than $item)")
animate(player, 4069, true) }
break return@queueScript stopExecuting(player)
} }
} }
return@onUseWith true
} }
return@queueScript stopExecuting(player)
} }
return@on true }
} }
}
} }

View file

@ -0,0 +1,244 @@
package content.global.handlers.item.equipment
import core.game.node.item.Item
import org.rs09.consts.Items
/**
* Barrows equipment information and utilities.
* @author 'Vexia - original code
* @author Damighty - Kotlin conversion and refactor
*/
object BarrowsEquipment {
// Barrows equipment lasts for 15 hours of combat. Each piece has 4 degradation tiers (100, 75, 50, 25).
const val DEGRADATION_TICKS_PER_TIER = (15 * 6000) / 4 // 22500 ticks per tier
private const val MAX_DURABILITY = DEGRADATION_TICKS_PER_TIER * 4
/**
* A data class for each Barrows piece. Holds all information related to a specific piece of Barrows gear.
*
* @param brother The Barrows brother this item belongs to.
* @param equipmentType The slot type ("weapon", "body", "legs", "helm").
* @param itemName The formatted name of the item.
* @param baseRepairCost The full repair cost in GP.
* @param degradationStates A list of item IDs, from fully repaired (index 0) to broken (index 5).
*/
data class BarrowsItemDefinition(
val brother: String,
val equipmentType: String,
val itemName: String,
val baseRepairCost: Int,
val degradationStates: List<Int>
) {
val repairedId: Int = degradationStates.first()
val brokenId: Int = degradationStates.last()
/** Checks if a given item ID belongs to this specific equipment set. */
fun contains(itemId: Int): Boolean = itemId in degradationStates
/** Gets the degradation index for a given item ID (0=repaired, 1=100, ..., 5=broken). */
fun getDegradationIndex(itemId: Int): Int = degradationStates.indexOf(itemId)
}
/** All Barrows equipment data. */
private val barrowsItemDefinitions = listOf(
// Dharok
BarrowsItemDefinition("dharok", "helm", "Dharok's helm", 60_000,
listOf(Items.DHAROKS_HELM_4716, Items.DHAROKS_HELM_100_4880,
Items.DHAROKS_HELM_75_4881, Items.DHAROKS_HELM_50_4882,
Items.DHAROKS_HELM_25_4883, Items.DHAROKS_HELM_0_4884)),
BarrowsItemDefinition("dharok", "weapon", "Dharok's greataxe", 100_000,
listOf(Items.DHAROKS_GREATAXE_4718, Items.DHAROKS_AXE_100_4886,
Items.DHAROKS_AXE_75_4887, Items.DHAROKS_AXE_50_4888,
Items.DHAROKS_AXE_25_4889, Items.DHAROKS_AXE_0_4890)),
BarrowsItemDefinition("dharok", "body", "Dharok's platebody", 90_000,
listOf(Items.DHAROKS_PLATEBODY_4720, Items.DHAROKS_BODY_100_4892,
Items.DHAROKS_BODY_75_4893, Items.DHAROKS_BODY_50_4894,
Items.DHAROKS_BODY_25_4895, Items.DHAROKS_BODY_0_4896)),
BarrowsItemDefinition("dharok", "legs", "Dharok's platelegs", 80_000,
listOf(Items.DHAROKS_PLATELEGS_4722, Items.DHAROKS_LEGS_100_4898,
Items.DHAROKS_LEGS_75_4899, Items.DHAROKS_LEGS_50_4900,
Items.DHAROKS_LEGS_25_4901, Items.DHAROKS_LEGS_0_4902)),
// Guthan
BarrowsItemDefinition("guthan", "helm", "Guthan's helm", 60_000,
listOf(Items.GUTHANS_HELM_4724, Items.GUTHANS_HELM_100_4904,
Items.GUTHANS_HELM_75_4905, Items.GUTHANS_HELM_50_4906,
Items.GUTHANS_HELM_25_4907, Items.GUTHANS_HELM_0_4908)),
BarrowsItemDefinition("guthan", "weapon", "Guthan's warspear", 100_000,
listOf(Items.GUTHANS_WARSPEAR_4726, Items.GUTHANS_SPEAR_100_4910,
Items.GUTHANS_SPEAR_75_4911, Items.GUTHANS_SPEAR_50_4912,
Items.GUTHANS_SPEAR_25_4913, Items.GUTHANS_SPEAR_0_4914)),
BarrowsItemDefinition("guthan", "body", "Guthan's platebody", 90_000,
listOf(Items.GUTHANS_PLATEBODY_4728, Items.GUTHANS_BODY_100_4916,
Items.GUTHANS_BODY_75_4917, Items.GUTHANS_BODY_50_4918,
Items.GUTHANS_BODY_25_4919, Items.GUTHANS_BODY_0_4920)),
BarrowsItemDefinition("guthan", "legs", "Guthan's chainskirt", 80_000,
listOf(Items.GUTHANS_CHAINSKIRT_4730, Items.GUTHANS_SKIRT_100_4922,
Items.GUTHANS_SKIRT_75_4923, Items.GUTHANS_SKIRT_50_4924,
Items.GUTHANS_SKIRT_25_4925, Items.GUTHANS_SKIRT_0_4926)),
// Torag
BarrowsItemDefinition("torag", "helm", "Torag's helm", 60_000,
listOf(Items.TORAGS_HELM_4745, Items.TORAGS_HELM_100_4952,
Items.TORAGS_HELM_75_4953, Items.TORAGS_HELM_50_4954,
Items.TORAGS_HELM_25_4955, Items.TORAGS_HELM_0_4956)),
BarrowsItemDefinition("torag", "weapon", "Torag's hammers", 100_000,
listOf(Items.TORAGS_HAMMERS_4747, Items.TORAGS_HAMMER_100_4958,
Items.TORAGS_HAMMER_75_4959, Items.TORAGS_HAMMER_50_4960,
Items.TORAGS_HAMMER_25_4961, Items.TORAGS_HAMMER_0_4962)),
BarrowsItemDefinition("torag", "body", "Torag's platebody", 90_000,
listOf(Items.TORAGS_PLATEBODY_4749, Items.TORAGS_BODY_100_4964,
Items.TORAGS_BODY_75_4965, Items.TORAGS_BODY_50_4966,
Items.TORAGS_BODY_25_4967, Items.TORAGS_BODY_0_4968)),
BarrowsItemDefinition("torag", "legs", "Torag's platelegs", 80_000,
listOf(Items.TORAGS_PLATELEGS_4751, Items.TORAGS_LEGS_100_4970,
Items.TORAGS_LEGS_75_4971, Items.TORAGS_LEGS_50_4972,
Items.TORAGS_LEGS_25_4973, Items.TORAGS_LEGS_0_4974)),
// Verac
BarrowsItemDefinition("verac", "helm", "Verac's helm", 60_000,
listOf(Items.VERACS_HELM_4753, Items.VERACS_HELM_100_4976,
Items.VERACS_HELM_75_4977, Items.VERACS_HELM_50_4978,
Items.VERACS_HELM_25_4979, Items.VERACS_HELM_0_4980)),
BarrowsItemDefinition("verac", "weapon", "Verac's flail", 100_000,
listOf(Items.VERACS_FLAIL_4755, Items.VERACS_FLAIL_100_4982,
Items.VERACS_FLAIL_75_4983, Items.VERACS_FLAIL_50_4984,
Items.VERACS_FLAIL_25_4985, Items.VERACS_FLAIL_0_4986)),
BarrowsItemDefinition("verac", "body", "Verac's brassard", 90_000,
listOf(Items.VERACS_BRASSARD_4757, Items.VERACS_TOP_100_4988,
Items.VERACS_TOP_75_4989, Items.VERACS_TOP_50_4990,
Items.VERACS_TOP_25_4991, Items.VERACS_TOP_0_4992)),
BarrowsItemDefinition("verac", "legs", "Verac's plateskirt", 80_000,
listOf(Items.VERACS_PLATESKIRT_4759, Items.VERACS_SKIRT_100_4994,
Items.VERACS_SKIRT_75_4995, Items.VERACS_SKIRT_50_4996,
Items.VERACS_SKIRT_25_4997, Items.VERACS_SKIRT_0_4998)),
// Ahrim
BarrowsItemDefinition("ahrim", "helm", "Ahrim's hood", 60_000,
listOf(Items.AHRIMS_HOOD_4708, Items.AHRIMS_HOOD_100_4856,
Items.AHRIMS_HOOD_75_4857, Items.AHRIMS_HOOD_50_4858,
Items.AHRIMS_HOOD_25_4859, Items.AHRIMS_HOOD_0_4860)),
BarrowsItemDefinition("ahrim", "weapon", "Ahrim's staff", 100_000,
listOf(Items.AHRIMS_STAFF_4710, Items.AHRIMS_STAFF_100_4862,
Items.AHRIMS_STAFF_75_4863, Items.AHRIMS_STAFF_50_4864,
Items.AHRIMS_STAFF_25_4865, Items.AHRIMS_STAFF_0_4866)),
BarrowsItemDefinition("ahrim", "body", "Ahrim's robetop", 90_000,
listOf(Items.AHRIMS_ROBETOP_4712, Items.AHRIMS_TOP_100_4868,
Items.AHRIMS_TOP_75_4869, Items.AHRIMS_TOP_50_4870,
Items.AHRIMS_TOP_25_4871, Items.AHRIMS_TOP_0_4872)),
BarrowsItemDefinition("ahrim", "legs", "Ahrim's robeskirt", 80_000,
listOf(Items.AHRIMS_ROBESKIRT_4714, Items.AHRIMS_SKIRT_100_4874,
Items.AHRIMS_SKIRT_75_4875, Items.AHRIMS_SKIRT_50_4876,
Items.AHRIMS_SKIRT_25_4877, Items.AHRIMS_SKIRT_0_4878)),
// Karil
BarrowsItemDefinition("karil", "helm", "Karil's coif", 60_000,
listOf(Items.KARILS_COIF_4732, Items.KARILS_COIF_100_4928,
Items.KARILS_COIF_75_4929, Items.KARILS_COIF_50_4930,
Items.KARILS_COIF_25_4931, Items.KARILS_COIF_0_4932)),
BarrowsItemDefinition("karil", "weapon", "Karil's crossbow", 100_000,
listOf(Items.KARILS_CROSSBOW_4734, Items.KARILS_X_BOW_100_4934,
Items.KARILS_X_BOW_75_4935, Items.KARILS_X_BOW_50_4936,
Items.KARILS_X_BOW_25_4937, Items.KARILS_X_BOW_0_4938)),
BarrowsItemDefinition("karil", "body", "Karil's leathertop", 90_000,
listOf(Items.KARILS_LEATHERTOP_4736, Items.KARILS_TOP_100_4940,
Items.KARILS_TOP_75_4941, Items.KARILS_TOP_50_4942,
Items.KARILS_TOP_25_4943, Items.KARILS_TOP_0_4944)),
BarrowsItemDefinition("karil", "legs", "Karil's leatherskirt", 80_000,
listOf(Items.KARILS_LEATHERSKIRT_4738, Items.KARILS_SKIRT_100_4946,
Items.KARILS_SKIRT_75_4947, Items.KARILS_SKIRT_50_4948,
Items.KARILS_SKIRT_25_4949, Items.KARILS_SKIRT_0_4950))
)
/** Cached access to an item's full definition from its ID */
private val itemIdToDefinitionMap: Map<Int, BarrowsItemDefinition> by lazy {
barrowsItemDefinitions.flatMap { def ->
def.degradationStates.map { id -> id to def }
}.toMap()
}
/** Gets all degradation state arrays for degradation registration */
fun getAllEquipmentSets(): Collection<IntArray> = barrowsItemDefinitions.map { it.degradationStates.toIntArray() }
/** Gets all repairable Barrows item IDs (anything not fully repaired) */
fun getAllRepairableBarrowsIds(): List<Int> = itemIdToDefinitionMap.filter { !isFullyRepaired(it.key) }.keys.toList()
/** Gets the full definition for a Barrows item */
@JvmStatic
fun getDefinition(itemId: Int): BarrowsItemDefinition? = itemIdToDefinitionMap[itemId]
/** Checks if an item ID is any Barrows item */
@JvmStatic
fun isBarrowsItem(itemId: Int): Boolean = itemId in itemIdToDefinitionMap
/** Checks if a Barrows item is fully repaired */
@JvmStatic
fun isFullyRepaired(itemId: Int): Boolean = getDefinition(itemId)?.repairedId == itemId
/** Checks if a Barrows item is broken */
@JvmStatic
fun isBroken(itemId: Int): Boolean = getDefinition(itemId)?.brokenId == itemId
/**
* Calculates the repair cost for a degraded Barrows item
* @param item The degraded Barrows item
* @return The repair cost in GP, or -1 if the item cannot be repaired
*/
fun getRepairCost(item: Item): Int {
val def = getDefinition(item.id) ?: return -1
if (isFullyRepaired(item.id)) return -1
val totalRemainingDurability = calculateTotalRemainingDurability(item, def)
val durabilityLost = MAX_DURABILITY - totalRemainingDurability
val cost = ((durabilityLost.toDouble() / MAX_DURABILITY) * def.baseRepairCost).toInt()
return cost
}
/**
* Reduces the durability of a Barrows item by 20% of its total remaining durability
* @param item The Barrows item
* @return The item with reduced durability, or null if the item is not a valid Barrows piece
*/
@JvmStatic
fun graveDeathDurabilityReduction(item: Item): Item? {
val def = getDefinition(item.id) ?: return null
if (isBroken(item.id)) return item
val totalRemainingDurability = calculateTotalRemainingDurability(item, def)
val durabilityReduction = (totalRemainingDurability * 0.2).toInt()
val newRemainingDurability = totalRemainingDurability - durabilityReduction
return createItemFromDurability(def, newRemainingDurability, item.amount)
}
/**
* Calculates the total remaining durability ticks (charge) for a Barrows item
*/
private fun calculateTotalRemainingDurability(item: Item, def: BarrowsItemDefinition): Int {
return when (val index = def.getDegradationIndex(item.id)) {
-1 -> 0 // Invalid
0 -> MAX_DURABILITY // Fully repaired
5 -> 0 // Broken
else -> {
// For degraded items (100, 75, 50, 25), durability is the number of fully remaining tiers below it, plus the charge of the current tier.
// Index 1 (100) has 3 tiers below it. Index 4 (25) has 0 tiers below it.
val remainingTiers = 4 - index
(remainingTiers * DEGRADATION_TICKS_PER_TIER) + item.charge
}
}
}
/**
* Creates a new Item instance based on a total durability value
*/
private fun createItemFromDurability(def: BarrowsItemDefinition, durability: Int, amount: Int): Item {
if (durability <= 0) {
return Item(def.brokenId, amount)
}
// Tier is 1-indexed (1=25, 2=50, 3=75, 4=100)
val tier = ((durability - 1) / DEGRADATION_TICKS_PER_TIER) + 1
// Degradation index is 4-indexed (4=25, 3=50, 2=75, 1=100)
val degradationIndex = 5 - tier
val newId = def.degradationStates[degradationIndex]
val newCharge = (durability - 1) % DEGRADATION_TICKS_PER_TIER + 1
return Item(newId, amount, newCharge)
}
}

View file

@ -4,73 +4,16 @@ import core.plugin.Initializable
import core.plugin.Plugin import core.plugin.Plugin
@Initializable @Initializable
class BarrowsEquipmentRegister : Plugin<Any>{ class BarrowsEquipmentRegister : Plugin<Any> {
public companion object {
// Barrows equipment lasts for 15 hours of combat, and each piece has 4 stages of degredation
@JvmField
public val TICKS = (15 * 6000) / 4
}
val DHAROK_HELM = arrayOf(4716,4880,4881,4882,4883,4884)
val DHAROK_AXE = arrayOf(4718,4886,4887,4888,4889,4890)
val DHAROK_BODY = arrayOf(4720,4892,4893,4894,4895,4896)
val DHAROK_LEGS = arrayOf(4722,4898,4899,4900,4901,4902)
val GUTHAN_HELM = arrayOf(4724,4904,4905,4906,4907,4908)
val GUTHAN_SPEAR = arrayOf(4726,4910,4911,4912,4913,4914)
val GUTHAN_BODY = arrayOf(4728,4916,4917,4918,4919,4920)
val GUTHAN_SKIRT = arrayOf(4730,4922,4923,4924,4925,4926)
val TORAG_HELM = arrayOf(4745,4952,4953,4954,4955,4956)
val TORAG_HAMMER = arrayOf(4747,4958,4959,4960,4961,4962)
val TORAG_BODY = arrayOf(4749,4964,4965,4966,4967,4968)
val TORAG_LEGS = arrayOf(4751,4970,4971,4972,4973,4974)
val VERAC_HELM = arrayOf(4753,4976,4977,4978,4979,4980)
val VERAC_FLAIL = arrayOf(4755,4982,4983,4984,4985,4986)
val VERAC_BRASS = arrayOf(4757,4988,4989,4990,4991,4992)
val VERAC_SKIRT = arrayOf(4759,4994,4995,4996,4997,4998)
val AHRIM_HOOD = arrayOf(4708,4856,4857,4858,4859,4860)
val AHRIM_STAFF = arrayOf(4710,4862,4863,4864,4865,4866)
val AHRIM_TOP = arrayOf(4712,4868,4869,4870,4871,4872)
val AHRIM_SKIRT = arrayOf(4714,4874,4875,4876,4877,4878)
val KARIL_COIF = arrayOf(4732,4928,4929,4930,4931,4932)
val KARIL_CBOW = arrayOf(4734,4934,4935,4936,4937,4938)
val KARIL_TOP = arrayOf(4736,4940,4941,4942,4943,4944)
val KARIL_SKIRT = arrayOf(4738,4946,4947,4948,4949,4950)
override fun newInstance(arg: Any?): Plugin<Any> { override fun newInstance(arg: Any?): Plugin<Any> {
EquipmentDegrader.registerSet(TICKS, AHRIM_HOOD) BarrowsEquipment.getAllEquipmentSets().forEach {
EquipmentDegrader.registerSet(TICKS, AHRIM_STAFF) degradationSet ->
EquipmentDegrader.registerSet(TICKS, AHRIM_TOP) EquipmentDegrader.registerSet(BarrowsEquipment.DEGRADATION_TICKS_PER_TIER, degradationSet.toTypedArray())
EquipmentDegrader.registerSet(TICKS, AHRIM_SKIRT) }
EquipmentDegrader.registerSet(TICKS, KARIL_COIF)
EquipmentDegrader.registerSet(TICKS, KARIL_CBOW)
EquipmentDegrader.registerSet(TICKS, KARIL_TOP)
EquipmentDegrader.registerSet(TICKS, KARIL_SKIRT)
EquipmentDegrader.registerSet(TICKS, DHAROK_HELM)
EquipmentDegrader.registerSet(TICKS, DHAROK_AXE)
EquipmentDegrader.registerSet(TICKS, DHAROK_BODY)
EquipmentDegrader.registerSet(TICKS, DHAROK_LEGS)
EquipmentDegrader.registerSet(TICKS, GUTHAN_HELM)
EquipmentDegrader.registerSet(TICKS, GUTHAN_SPEAR)
EquipmentDegrader.registerSet(TICKS, GUTHAN_BODY)
EquipmentDegrader.registerSet(TICKS, GUTHAN_SKIRT)
EquipmentDegrader.registerSet(TICKS, TORAG_HELM)
EquipmentDegrader.registerSet(TICKS, TORAG_HAMMER)
EquipmentDegrader.registerSet(TICKS, TORAG_BODY)
EquipmentDegrader.registerSet(TICKS, TORAG_LEGS)
EquipmentDegrader.registerSet(TICKS, VERAC_HELM)
EquipmentDegrader.registerSet(TICKS, VERAC_FLAIL)
EquipmentDegrader.registerSet(TICKS, VERAC_BRASS)
EquipmentDegrader.registerSet(TICKS, VERAC_SKIRT)
return this return this
} }
override fun fireEvent(identifier: String?, vararg args: Any?): Any { override fun fireEvent(identifier: String?, vararg args: Any?): Any {
return Unit return Unit
} }
} }

View file

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

View file

@ -24,9 +24,11 @@ class CrystalKeyCreateListener : InteractionListener {
return@onUseWith false return@onUseWith false
} }
addItem(player, Items.CRYSTAL_KEY_989) if (!addItem(player, Items.CRYSTAL_KEY_989)) {
sendMessage(player, "You join the loop half of a key and the tooth half of a key to make a crystal key.") return@onUseWith false
}
sendMessage(player, "You join the loop half of a key and the tooth half of a key to make a crystal key.")
return@onUseWith true return@onUseWith true
} }
} }

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