Compare commits

...

487 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
Player Name
cf08e700fb Runecrafting pouches now synchronise across bank instances
BoB can no longer be used to smuggle weapons to Entrana
2025-02-18 06:24:15 +00:00
Player Name
d65a53b275 Fixed loss of equippable items when swapped with another item that is dropped in the same tick 2025-02-18 06:03:18 +00:00
Player Name
fb9d6307b3 Corrected diamond bolts (e) effect
Removed inauthentic Verac armour effect of +1 max hit increase
2025-02-18 04:32:21 +00:00
Player Name
45fb89ec73 Hostile random events now take the player's summoning level into account
Random event combat level is now selected authentically resulting in more difficult hostile random events
2025-02-17 10:44:44 +00:00
Oven Bread
50ba3682b5 Corrected fishing contest quest log
Fixed dialogue after fishing contest
2025-02-17 10:42:19 +00:00
Oven Bread
df73f4a171 Fixed child animations for the following NPCs:
Boy (Witch's House quest)
Kanel (Inside Gertrude house)
Philop (Inside Gertrude house)
Shilop (Gertrude's Cat quest)
Wilough (Gertrude's Cat quest)
2025-02-17 10:40:27 +00:00
GregF
9eedfc2336 Added some new regions 2025-02-17 10:37:28 +00:00
Ryan
e25780a4c5 Fixed player status SQLite conversion breaking on usernames with spaces 2025-02-16 11:10:18 +00:00
GregF
b6560c0e3f Implemented Mogre miniquest 2025-02-16 10:42:27 +00:00
Player Name
2d1a626df0 Zamorak robe top and bottom now count as Zamorak god items
Zamorak robe top and bottom now allowed into Entrana
Implemented the right-click take-boat options for the monks of Entrana
Fixed some silly typos in the Monk-of-Entrana dialogue
Removed unused god item definitions
2025-02-16 10:23:21 +00:00
GregF
4f97dbef8c Completed very large refactor of Plague City quest and related functionality 2025-02-16 10:19:20 +00:00
Player Name
be76ca143b Fixed softlock in Priest in Peril and The Fremennik Trials 2025-02-16 10:03:20 +00:00
Elbarto 2
053254b504 Corrected restore for various consumables 2025-02-16 09:48:21 +00:00
Oven Bread
486ca4bb19 Implemented Desert Treasure quest 2025-02-16 09:33:56 +00:00
DeadlyGenga
104533c11d Corrected stats, levels and combat styles of many familiars 2025-02-16 07:40:42 +00:00
Oven Bread
9886049429 Implemented Zogre Flesh Eaters quest 2025-02-16 07:09:36 +00:00
Player Name
f1131b7d00 Made random event teleports more robust, fixing edge cases 2025-02-16 07:00:13 +00:00
Player Name
be47c1d5c9 Added cats raised to ::stats
Added food cooked to ::stats
2025-02-16 05:35:27 +00:00
Player Name
bb860b60e0 Pest control XP formula is now authentic, includes 1% XP bonus if handing in 10 points or more and 10% XP bonus if handing in 100 points or more 2025-02-16 05:32:57 +00:00
Oven Bread
fed309a70b Fixed map areas that caused client crashes in HD 2025-02-16 05:28:53 +00:00
Player Name
1afd4d5328 Fixed bug preventing The Fremennik Trials lyre concert being marked as completed 2025-02-16 05:22:36 +00:00
Player Name
a6eb706358 Corrected many examine texts 2025-02-16 05:20:14 +00:00
Oven Bread
957477b9b0 Fixed Death Plateau softlock in Dunstan dialogue
Fixed Harold not accepting blurberry special
Spiked boots now accessible
2025-02-16 05:17:13 +00:00
Oven Bread
4387b346dc Implemented The Curse of Zaros Miniquest 2025-02-13 12:34:23 +00:00
Player Name
618d39d73c Fixed shooting star resetting on server shutdown 2025-02-13 11:30:02 +00:00
sirdabalot
62a7dd4324 Ported kill stats and rare item drop storage to sqlite from json
This fixes lengthy and memory intensive server shutdowns
Existing global_kill_stats.json will be imported on first run
2025-02-12 12:17:02 +00:00
GregF
212ce57580 Fixed barbarian fishing xp rate manipulation 2025-02-12 11:35:17 +00:00
Player Name
8a4ea5d1f3 Runecrafting skillcape now only consume a charge if the teleport took place
Improved navigation of the runecrafting skillcape teleport menu
Runecrafting skillcape message improvement
2025-02-11 13:17:20 +00:00
MrKingFish
0f14639e9b Added examine text for Ahad, Phingspet and Grimesquit 2025-02-11 13:13:31 +00:00
Player Name
e63c6f523a Fixed bug where ::forcegravedeath could make admins lose admin status
Added ::makeadmin command to promote accounts to admin
Added ::dropadmin command to demote accounts from admin
Added ::setpestpoints to set Pest Control points
Testing commands now take optional player name argument ::max, ::noobme, ::setlevel and ::addxp
2025-02-11 13:06:49 +00:00
Oven Bread
612ccc6776 Implemented Maze random event 2025-02-11 13:03:30 +00:00
Oven Bread
b5784c5782 Implemented Quiz Master random event 2025-02-11 12:59:25 +00:00
Oven Bread
867c332466 Populated Gnome Stronghold area 2025-02-11 12:50:41 +00:00
Player Name
8b1763c3ba Improved inventory handling for Jossik 2025-02-11 12:47:06 +00:00
Elbarto 2
d0fdf08d13 Added Plant Cure, Compost and Supercompost to the ::farmkit admin command 2025-02-11 12:18:58 +00:00
Player Name
d91f77c294 Refactored how quests are referred to internally
Fixed numerous requirement checks for Rag and Bone Man II, The Lost Tribe, The Tourist Trap, Waterfall Quest and The Fremennik Trials
2025-02-09 02:37:14 +00:00
Player Name
c03947e0b0 Cleaned up legacy save code 2025-02-03 00:48:51 +00:00
Oven Bread
acc6c182a5 Implemented Tears of Guthix Quest
Implemented Tears of Guthix Minigame
2025-02-01 14:20:43 +00:00
Player Name
1b85808885 Fixed hostile random events attacking other players
Fixed players being able to attack hostile random events for other players
Hostile random events now authentically only reward 1/16th xp (except for pheasants, which give 0 xp)
2025-02-01 14:15:45 +00:00
Player Name
2cf8392691 Fixed incubator appearing to lose contents 2025-02-01 14:13:26 +00:00
Player Name
4a016d45e5 Fixed farming patches wrongly getting diseased during offline catchup 2025-02-01 14:08:55 +00:00
Player Name
cd43f8d269 Star sprite bonus now drops bonus ore if inventory is full
Rocks mined attribute now takes into account bonus ore
2025-02-01 14:07:03 +00:00
troido
0a26d5039a Aggressive NPCs will no longer always attack the last player to enter the area 2025-02-01 14:04:03 +00:00
Player Name
c3929cf06c Fixed telegrab through walls 2025-02-01 14:00:59 +00:00
Player Name
fcbea5acdc Fixed some incorrect replacement doors in Rellekka
Disabled the unimplemented TzHaar door
Fixed some doors causing buggy player movement
2025-02-01 13:58:55 +00:00
DeadlyGenga
3d7e93b6c2 Refactored Antifire potion effect
Relicym Balm can now cure disease
Antifire potion effect now persists through log out
2025-02-01 13:53:10 +00:00
Ceikry
6e9f3cb8b9 Disabled the ability to create new HCIM accounts
Disabled the ability to select HCIM 10x xp rate
Existing HCIM will turn back to standard players after their next death (all permadeath rules still apply for that death)
Players on HCIM 10x will be reverted to 5x after their next death
If the player is in combat and disconnects via AFK timeout, then their forced logout timer has been reduced to 30 seconds from 15 minutes
If the player is in combat and x-logs or disconnects via network issues, then their forced logout timer has been reduced to 5 minutes from 15 minutes
2025-02-01 13:48:18 +00:00
GregF
0c8efbac7a Added all missing NPCs to config file for future use 2025-02-01 13:42:53 +00:00
Tooze
ccc60b1240 Implemented knife spawn in Sorcerer's Tower 2025-02-01 13:38:50 +00:00
Player Name
818ffc01e7 Removed random events from Tutorial Island 2025-02-01 13:27:04 +00:00
GregF
f37b30749e Iron men can no longer participate in lootshare 2025-02-01 13:25:23 +00:00
Player Name
edc6f9cf07 Implemented Gaze of Saradomin
Fixed respawn bugs
2025-02-01 13:23:42 +00:00
DeadlyGenga
064edfbbe4 Implemented spirit saratrice 2025-02-01 13:20:27 +00:00
GregF
b62f4e9525 Implemented black swan NPC 2025-02-01 13:19:17 +00:00
Player Name
57f5617fe8 Fixed loss of draconic visages if used on an anvil without an anti-dragon shield in the player's inventory
Fixed dragonfire shield and dragon square shield smithing not checking for a hammer in inventory
2025-02-01 13:18:19 +00:00
GregF
6c386e6ed2 Implemented Hunters' Crossbow 2025-02-01 13:15:07 +00:00
GregF
93890769e1 Significantly improved slayer tasks implementation
More authentic tasks
Better dialogue and hints
New tasks added in preparation for when relevant quests are implemented
2025-02-01 13:14:04 +00:00
Oven Bread
4039c0123b Correctly limited quest log and achievement diary scrolling 2025-02-01 13:12:58 +00:00
Player Name
27f2d457ea Fixed issues in Jarvald's dialogue 2025-02-01 13:08:20 +00:00
Oven Bread
c6b508b3ed Lucien now gives a pendant after Temple of Ikov completion 2025-02-01 13:07:49 +00:00
Oven Bread
67b6855370 Implemented Sea Slug quest 2025-02-01 13:07:39 +00:00
GregF
4480618748 Added pirate clothes to store and examine text to Mike 2025-02-01 13:06:53 +00:00
Player Name
9fff4dbb5d Implemented spade pickup in the Rimmington mine
Rewrote the permadeath code to more thoroughly wipe HCIM when they die
HCIM permadeath code destroys items dropped on death
Cleaned up redundant blast furnace player save code
2025-02-01 13:02:22 +00:00
GregF
6a68cf9d7c Fixed issue with trees not being able to be health checked 2025-02-01 12:56:18 +00:00
Oven Bread
e34a81ec6c Implemented Heroes Quest 2025-02-01 12:29:51 +00:00
Oven Bread
00b5a44c31 Added additional dialogue helpers 2025-02-01 12:23:10 +00:00
Player Name
f75577d41d ::itemsearch now usable by everyone 2025-01-20 13:56:18 +00:00
Player Name
3838f01adf Made POH deaths safer, fixing random event bug 2025-01-20 13:54:34 +00:00
Player Name
a932c309b3 Fixed bug where ultimate ironmen could have rewards sent to bank
Fixed the allquest command on new accounts on first login
2025-01-20 13:52:46 +00:00
Player Name
9af776e3c6 Refactored some runecrafting code
Corrected the Ourania altar reward, now fully authentic
2025-01-20 13:49:58 +00:00
gregf36665
39634b6caf Implement penguin egg acquisition 2025-01-20 13:26:56 +00:00
Oven Bread
eb3884180e Signpost improvements
Minor quest log fixes
Implemented map for talismans in Wizard Tower basement
2025-01-20 12:56:20 +00:00
Player Name
d5c7d74767 Fixed a bug where the player could get locked planting while farming 2025-01-20 12:46:57 +00:00
Player Name
d08656021c Fixed pillory random event completion teleport location 2025-01-20 12:35:01 +00:00
Kennynes
9beb7219ea Fixed examine texts for some cabbages and other items 2025-01-20 12:25:25 +00:00
Player Name
deecf136bc Fixed slayer cape perk activation 2025-01-20 12:08:58 +00:00
Player Name
b849de2dab Fixed magic secateurs patch bones not applying 2025-01-20 12:00:38 +00:00
GregF
b4950343ec Fixed bug preventing super restore recovering prayer 2025-01-20 11:49:01 +00:00
Oven Bread
7749e8263f Introduced new dialogue engine compatible with spinoff revision 578 project 2024-11-22 06:59:42 +00:00
Ryan
79c69e3d43 Changed timestamp in logs to ISO standard datetime format 2024-11-14 12:42:48 +00:00
GregF
7d79c9a82a Construction can now be used to fix the ladder to the wilderness beacon 2024-11-14 12:14:31 +00:00
Oven Bread
e216a6366f Use the system update countdown for the daily restart 2024-11-14 12:08:21 +00:00
Player Name
9054e36288 King Bolren now gives back lost gnome amulets 2024-11-14 12:05:47 +00:00
Oven Bread
1a67932351 Implemented Pillory random event (this event occurs while pick-pocketing) 2024-11-14 12:02:37 +00:00
Player Name
7a6adda997 Authenticity improvements to runecrafting pouches. Due to changes in degrade counters, they will degrade within the next 1 or 2 fills after this update; this is a one-time event. Resolve (or prevent) this by repairing via the dark mage 2024-11-14 11:56:16 +00:00
GregF
1da53c448d Rewrote dream spell
Fixed healing rate of dream
Added sound to dream spell
2024-11-14 11:51:34 +00:00
Player Name
53dc169774 Corporeal beast authenticity improvements
Dark core will no longer jump to players in safe area
Adjusted maximum attack hits
Protect from magic now blocks the big dart attack by 40%
Now resummons the dark core when it dies
Made the dark core respawn mechanics more authentic
Dark core now drops ashes
2024-11-14 11:36:09 +00:00
Player Name
b0be48501b Made the following POH hotspots refund their non-plank items when torn down: any quest item, any guild trophy, any armor stand
Refactored some construction code
Removed decorations and hotspots for "Menagerie" rooms, which seem to be inauthentic
Changed the following hotspots to be recursive: decoration, wall chart (study)
Corrected xp for a few construction items
2024-11-14 11:18:25 +00:00
Player Name
98c99e7550 POH telescope now estimates the shooting star time based on its tier 2024-11-14 11:06:41 +00:00
Player Name
ed41f3a228 Bounty Hunter music is now unlockable 2024-11-14 11:02:26 +00:00
Player Name
a2eafa8bc0 Fixed exception on server boot related to a duplicated attempt to register dialogue for Jarvald 2024-11-14 10:44:00 +00:00
Sinipelto
2be5f9eac0 Fixed loss of combat tabs after recruitment drive 2024-11-14 10:22:04 +00:00
Oven Bread
876b87b72a Fixed exception occuring when JohnnyBeard dies 2024-10-12 05:34:12 +00:00
Player Name
32cd17bfa2 Fixed bugs relating to player location and random events
Improved handling of random events when the location of the abducted player is missing from save file
Added per-tick auditing of data relating to player location
2024-10-12 04:21:49 +00:00
Ceikry
393752d77b Fixed vinesweeper point exchange ratio bug
Disabled spirit kalphite scroll until bug is fixed
2024-10-11 04:52:08 +00:00
Player Name
2b460b64f2 Thread now correctly disappears every 5 items crafted, including bug fixes related to the fact
Ring of forging now correctly disappears every 140 iron ores smelt, including bug fixes related to the fact
2024-10-10 07:14:48 +00:00
Player Name
59075798ea Adventure bot improvements
Adjusted max pulse count for bots from 50 -> 75
Adjusted max skill baseline by +4 for adventure bots to 69
Added 500 lines of unique
Added 45000 bot names
Added recovery methods for bots that get stuck
Added multiple random number functions to help add more variance
Added function to handle checking if a bot is near/in a Bank
Added function to handle getting a new city
Added function to add variability to locations given to bots
Added function to check if other players/bots are nearby
Added function to handle bots banking their inventories if a bank booth is nearby
Improved random number parameters
Improved how bots are spawned & added variance to spawn location
Improved how bots interact & handle the Grand Exchange location
Improved how bots handle starting in Lumbridge
Fixed bots referencing themselves in dialogue
Fixed bots talking when they are by themselves
Fixed multiple cases where bots would get stuck in a state
Fixed multiple logic errors
Fixed issues with bots banking but not switching states
2024-10-10 07:08:57 +00:00
DeadlyGenga
034c05f512 Fixed Mystic Lava staff not counting as earth runes 2024-10-08 07:19:23 +00:00
Tobias H.
01b5e59250 Fixed missing space in pottery messages 2024-10-08 06:57:51 +00:00
Oven Bread
7d32e77860 Removed unnecessary server console debug prints 2024-10-08 06:39:25 +00:00
Oven Bread
f11149ebe2 Corrected quest log for Creatures of Fenkenstrain
Corrected quest log for Troll Stronghold
Corrected quest log for The Dig Site
Corrected quest log for Witch's House
Corrected quest log for Scorpion Catcher
Corrected quest log for Wolf Whistle
Corrected quest log for Nature Spirit
Corrected quest log for What Lies Below
Populated NPCs in Lucien's Camp (Next to Wildy Chaos Temple hut) (Inaccessible)
Populated NPCs in Black knight catacombs (WGS) (Inaccessible)
Populated NPCs in 1st level of Pollnivneach Slayer Dungeon (Smoking Kills) (Accessible)
2024-10-07 11:30:02 +00:00
Oliver Fawcett
ba1e190cdb Typo fixes for dialogue in enter the abyss and dragon slayer 2024-10-07 11:26:03 +00:00
GregF
1c9fbc79aa Fixed up wordwrap for debugging unhandled interactions 2024-10-07 11:24:01 +00:00
zsrv
218a040f8b Major farming improvements including (but not limited to):
Farming animation corrections
Farming message updates and additions
Gardeners will chop down fully grown trees for 200 gp
Gardeners will give farming advice
Compost bin debugging admin command ::finishbins restored (finishes any in-progress compost bins)
Compost bin debugging admin command ::resetbins added (resets the player's compost bins to their initial states)
Players can no longer pay gardeners to protect diseased or dead farming patches
Can no longer water dead patches
Weeds will now grow in farming patches as part of the offline catch-up
Trees that are not fully grown can now be dug up
2024-10-07 11:15:52 +00:00
Bonesy
cc8dd4edb4 Rewrote some Varrock plugins
Removed duplicated handlers for many Varrock related stairs and ladders
Fixed the Champions' Guild trapdoor being unable to be closed
Changed the model ID for the logs outside of Seth Groats's house when the axe is taken
The drawers in Guidor's house will no longer disappear. There doesn't appear to be a related open object, so they just won't open
The Benny NPC yells about newspapers again
Knocking on the door in the Varrock bank will start the dialogue with the bankers
The Varrock Census object in the Varrock castle will now open the Varrock Census interface
Added sounds for opening/closing drawers, wardrobes, and cupboards and animations for wardrobes
Added the Kudos overlay in the Varrock Museum
Corrected the spawns for archeologists in the Varrock Museum dig site area
Implemented the Varrock museum map interface to open from the objects and item
The tool shelf in the museum dig site area will now give items
Looking at the displays in the in the Natural History area of the museum will open the interface for the exam and provided some notes
2024-10-06 13:12:33 +00:00
Player Name
3982258500 Corrected iron-ore-smelting success rate 2024-10-06 13:06:07 +00:00
Kennynes
2be422e7da Reverted some tutorial island dialogue 2024-10-06 12:49:54 +00:00
Ceikry
5abe50430d Improved bank updates, likely fix for bank UI delay 2024-10-06 12:47:54 +00:00
Oven Bread
97b8ed19a6 Fixed the Priest in Peril items not showing up in HD 2024-10-06 12:45:10 +00:00
GregF
9d38357c4e Corrected Lighthouse Dagannoth drop table 2024-10-06 12:43:22 +00:00
Player Name
64fa1d89c3 Players are now rescued out of the unimplemented high-level Bounty Hunter crater 2024-10-06 12:35:49 +00:00
Player Name
e31397b42f Corrected summoning point drain rate 2024-10-06 12:29:07 +00:00
Doggo
9f61ffb153 Rewrote the swing/attack handler for authenticity:
Fixed a lot of off-by-1 miscalculations
Fixed the void ranger bonus, which should be 20%
Fixed granite maul spec not giving xp and ignoring protection prayers
Fixed accuracy being too high
Fixed set bonuses that boost attack or defence being applied twice or to all attacks
Fixed ranged attacks not taking into account prayers that boost defence or defensive attack styles
Fixed red chinchompa having the same damage as normal chinchompas
Fixed some specs being boosted by offensive prayers
::calcmaxhit now has better formatting
::calc_accuracy renamed to ::calcaccuracy for consistency with other commands, and now also gives the actual hit chance
2024-10-06 12:23:24 +00:00
Player Name
b2f7f86d6a Fixed blessing of graves belonging to ironmen
Fixed POH teleport issue
Fixed charter requirements
Fixed entrana weapon check bypass
Small authenticity improvements
2024-10-06 11:14:56 +00:00
Player Name
4799176c14 Fix bugs with familiars
Fixed a bug where familiars would sometimes not respond to the 'Call' button
Fixed random events not spawning when standing in front of the Lumbridge furnace
Fixed incorrect restrictions on familiars and random events inside POHs
2024-10-06 11:03:33 +00:00
Player Name
0a89439c80 Fixed saving of prayer points & hitpoints, dynamic level is now tracked separately to current hit/prayer points 2024-10-06 10:58:18 +00:00
Player Name
9c202aa47a Rewrote pet back end to use a more authentic system
Pets can now stack
Fixes a bug where a pet could get reset to 0 hunger and growth when dropped
Player save version migration messages are no longer shown
Pets now morph into adults in-place
2024-10-06 10:47:36 +00:00
Ceikry
6b0f942598 Fairy ring refactor
Reimplemented the travel log, fixes the issue where all the travel log interface text collapses in on itself
Travel log now displays the relevant code
Log sorting implemented
Fairy ring now remembers the last entered code and automatically re-enters it when opened
Fairy ring no longer skips letters
Direction clicks in quick succession now turn the wheel multiple times
2024-10-06 10:21:58 +00:00
Oven Bread
8db9060a40 Implemented the ogres in combat training camp 2024-10-06 09:59:03 +00:00
Player Name
f94221918f Fixed the unlocking of region-wide music tracks 2024-10-06 09:32:57 +00:00
DeadlyGenga
cc47f4b488 Fixed cockatrice, godtrice and spirit cobra egg implementation 2024-09-11 07:11:14 +00:00
GregF
5c027e2649 Corrected fletching arrow xp 2024-09-11 07:09:46 +00:00
GregF
4156f28b93 Corrected many potion effects 2024-09-11 07:07:55 +00:00
Oliver Fawcett
c271d4e74b Fixed typo in Straven dialogue 2024-08-25 03:50:33 +00:00
DeadlyGenga
97464ef1d2 Corrected All Fired Up item requirements 2024-08-23 01:29:44 +00:00
A F (Hawk)
518b5d91dd Fixed woad leaf typo in Wyson dialogue 2024-08-22 08:19:08 +00:00
Oven Bread
e25c7d7824 Implemented Recruitment Drive quest 2024-08-21 14:04:44 +00:00
DeadlyGenga
29fa9a5a21 Rune hasta requirements fix 2024-08-21 13:25:11 +00:00
Roderik
083df1aae2 Superheat ore order of precedence has been corrected 2024-08-21 13:13:15 +00:00
Jared Thorne
3a73c98e19 Improved server music config loading logging 2024-08-21 13:08:46 +00:00
Ceikry
80cb2d9ba4 Reverted fix for issue where the player could be given stacks of 0 items as it causes other regressions 2024-08-17 01:41:17 +00:00
Ryan
317b4e9b5c Reverted erroroneous config changes (fixes bots missing on single player) 2024-08-10 13:17:11 +00:00
Roderik
24143f5d20 Crafting guild sink can now be used 2024-08-10 11:27:23 +00:00
GregF
209e1ae8cf Implemented taxidermist 2024-08-10 11:13:56 +00:00
Player Name
37836ae992 Improved lootshare so that drops are awarded to clan members near a slain NPC, participation in combat is not necessary
Reconnecting in combat will no longer cause lost drops
2024-08-10 11:09:43 +00:00
Player Name
d15b47fc65 Rewrote the music system to use regions 2024-08-03 08:00:36 +00:00
Kamja Imo
58d9101ef6 Rewrote Lumbridge swamp hole handling 2024-08-03 07:24:47 +00:00
Player Name
ca8bfeab64 Trimmed crafting cape can now be used to enter the crafting guild 2024-08-03 07:20:38 +00:00
Player Name
957b1c2944 Rewrote (un)holy symbol blessing handling 2024-08-03 07:18:10 +00:00
DeadlyGenga
92fcd0ec32 Corrected granite crab pouch crafting experience from 31.6 to 21.6 2024-08-03 07:05:28 +00:00
DeadlyGenga
db3079271e Removed slayer staff from H.A.M. drop tables 2024-08-03 07:03:10 +00:00
Kamja Imo
9d6ad223cb Added frogspawn and cave eel fishing spots in Lumbridge swamp cave 2024-08-03 07:02:43 +00:00
GregF
3837bd3c26 Corrected option handling on GE interface 2024-08-03 06:59:49 +00:00
GregF
18d5d80fba Fixed issue where green dragons are called Elvargs in slayer tasks 2024-08-03 06:19:31 +00:00
GregF
9d2e173f71 Implemented ground guam as a tar recipe 2024-08-03 05:40:34 +00:00
Player Name
68c1e572b9 Changed the script processor code to no longer incorrectly close interfaces on SOFT queue scripts
Rewrote Jarvald
2024-07-18 09:39:09 +00:00
Ceikry
806680517b Halt tick processing if the server isn't able to reach the internet when watchdog is enabled (configurable via server config options connectivity_check_url and connectivity_timeout) 2024-07-18 08:07:35 +00:00
GregF
53357d20f3 Rewrote Canifis warewolf handling, fixed stats
Fixed bandit aggression
2024-07-13 06:13:31 +00:00
Dark Sage
a44472e559 Added missing sounds
Added equipping sounds to all Kitesheilds & sq shields that are currently available 
Added equipping sounds to combat Melee Boots that are currently available 
Added equipping sounds to combat Melee Gloves that are currently available 
Added equipping sounds to all Coifs that are currently available 
Added equipping sounds to all D'hide bodies that are currently available 
Added equipping sounds to all D'hide chaps that are currently available 
Added equipping sounds to all D'hide vambracers that are currently available 
Added equipping sounds to all Bows that are currently available 
Added equipping sounds to all Cross bows that are currently available 
Added equipping sounds to all Javelins that are currently available 
Added equipping sounds to all Knifes that are currently available 
Added equipping sounds to all Darts that are currently available 
Added equipping sounds to all Throwing axes that are currently available 
Added equipping sounds to all Arrows that are currently available 
Added equipping sounds to all Claws that are currently available 
Added equipping sounds to all Halbergs that are currently available 
Added equipping sounds to all Hastae that are currently available 
Added equiping sounds to all Daggers that are currently available 
Added equipping sounds to all Swords that are currently available 
Added equipping sounds to all Longswords that are currently available 
Added equipping sounds to all Scimitars that are currently available 
Added equipping sounds to all 2H swords that are currently available 
Added equipping sounds to all War-hammers that are currently available 
Corrected the incorrect equipping sounds to all staves to the correct sound
Added equipping sound to the Easter ring
Added equipping sound to the Jack lantern mask
Added the correct red nose light animation to the Reindeer hat
Corrected the Chocatrice cape to be the real one in game with the logo in the back and also added the emote to it
Added sounds to the Scythe and corrected its combat animations
Added the Rubber chicken emote "dance" with its music jingle and the chicken "bawk" sound
Added the Ice amulet and the Wintumber tree to Diangos item return since they were missing
Added the correct jingle to the Air guitar emote
2024-07-13 05:46:28 +00:00
Player Name
6b152bcc8c Wilderness improvements
Added an extra option to the deep wilderness gate warning: "I wish to proceed, and don't ask me again"
Reused the same warning, with appropriate changes, for the edge/ardy levers due to the pvp mechanics
Removed the interface warning when crossing the ditch until doomsayer is implemented
Removed the inauthentic threat revenant and restricted brawler/pvp drops to revenants and chaos elemental only
Now require 100k risk to obtain the boosted deep-wildy drop rates
Hid our inauthentic mechanics behind a new server config option enhanced_deep_wilderness
2024-07-13 05:46:18 +00:00
Bonesy
30f1cbf710 Rewrote unpowered orb charging
Added Seers' Village diary tasks for ranging tickets, talking to Thermac about staves and charging orbs
Corrected explorer's ring alchemy graphics
2024-07-13 04:37:24 +00:00
Bonesy
0165d373bd Rewrote altar praying
Added the Tai Bwo Wannai Trio as quest requirement for praying at the tribal statue
2024-07-13 04:37:21 +00:00
Player Name
6f9a975f7a Added Waterbirth Island and the Dagannoth Kings' lair to admin ::to teleport destinations 2024-07-13 04:37:19 +00:00
Player Name
21a07841f6 Fixed construction door and wall placement
Fixed the bug where some hotspots were still visible even in non-building mode
2024-07-13 04:37:04 +00:00
Player Name
81495ab8a8 ::ge commands now use book interface to support more than 300 listings 2024-07-13 04:24:13 +00:00
GregF
5ed3cafc4a Cuffs, Narf, Jeff and Rusty now have correct examine information
Corrected Narf's stats
Added examine text for all implings and Balnea
2024-07-13 03:33:28 +00:00
GregF
0b95cfdb8f Fixed incorrect reward amount from stronghold of player safety 2024-07-13 03:31:24 +00:00
Player Name
e8527ff506 Your organs will no longer be stolen. Also fixed unexpected disappearance of beds, big plants, bookcases in study, fireplaces in bedroom and costume box in costume room
Fixed incorrect coordinates for the study crystal ball hotspot
2024-07-13 03:21:22 +00:00
Player Name
ef90d24bdc Improved handling of construction bookcase building 2024-07-13 03:16:29 +00:00
Oven Bread
a2b0548c62 Better handling of quest varp/varbit and values to set the quest color to red/yellow/green 2024-07-13 03:15:17 +00:00
Player Name
611660cbc3 Fixed fishing trawler bugs
Optimised fishing trawler reward logic
2024-07-13 02:58:24 +00:00
Kamja Imo
370d9ef423 Removed quest completion check on fairy ring exit from Zanaris 2024-06-27 14:11:43 +00:00
Doggo
8d2b454b1c Fixed salamander attack style 2024-06-23 13:11:23 +00:00
Doggo
28b168e742 Fixed 1 tick movement delay on some actions 2024-06-08 12:23:06 +00:00
Player Name
98c0698097 Fixed random events occurring at kalphite queen and tormented demons
Fixed bots trying to speak unicode
2024-06-08 12:17:37 +00:00
Player Name
80a5c3a85e Enabled Lunar Isle and Miscellania coal mine star locations
Fixed requirements checking for some star locations
2024-06-08 12:15:46 +00:00
thelemir
ca3bc9cd70 Rewrote Rimmington
Enabled pickpocketing of Anja and Hengel
2024-06-08 12:13:22 +00:00
Player Name
2c3b5cb5a4 Fixed MTA telekinetic theatre statue path check 2024-06-08 11:55:23 +00:00
Oven Bread
5f62047aff Fixed the Druidic Ritual quest log rendering
Implemented two bank noticeboards
2024-06-08 11:25:03 +00:00
Oven Bread
d0f24afc2e Implemented White Wolf Mountain & Ice Queen 2024-06-08 11:24:25 +00:00
Bonesy
1f6b0e900f Fixed bug causing loss of xp when interrupted burying bones 2024-06-08 11:14:03 +00:00
Doggo
ddb9b6f0b0 Fixed NPCs pathing around safespots when standing adjacent to the safespot 2024-06-08 10:17:07 +00:00
Ceikry
45c21767d5 Reduced price of fighter torso to 4.5M (until barbarian assault is implemented) 2024-06-08 10:17:01 +00:00
João Victor
f01a5cfe40 Fixed incorrect description on a fairy ring 2024-06-08 10:15:53 +00:00
Ann
36d8186458 Added drop announcement for dragon platelegs, skirt and black mask (10) 2024-05-31 12:41:17 +00:00
Ceikry
52cf984540 Refactored bank logic
Removed some unnecessary complexity from bank logic
Improved handling of banking actions
Now correctly tracks the active bank tab
2024-05-31 11:38:00 +00:00
Legendary Rare
082d3a561b Fixed Draynor fishing bots not interacting 2024-05-31 11:34:29 +00:00
GregF
dd9f2a34c8 Fixed animations and stats for an ogre
Fixed bone club and butterfly net animations
Fixed black halberd requirements
Fixed stats on unobtainable corrupted pvp equipment
2024-05-31 11:32:53 +00:00
Player Name
49a10d192a Implemented save file versioning
Players who likely bought their crafting capes back when the hood was not obtainable will be given the complementary hood
Unlocked Surok's Theme for players who are eligible
Fixed some bugs relating to the handling of edge cases for random events
Fixed tutorial island quest completion
Made it possible to collapse interface stones in resizable HD
2024-05-31 11:32:48 +00:00
Player Name
2776270c7f Added the basement area of Tutorial 2 (Learning the Ropes) for the lore 2024-05-31 10:16:28 +00:00
Player Name
a184b4ce2f POH room rotation now correctly updates clipping flags 2024-05-31 10:11:38 +00:00
Player Name
76d31a68ad Fixed duplicated runecrafting messages 2024-05-31 10:09:21 +00:00
GregF
51929277ac Fixed issue where vodka was called wine
Fixed drinking wine
Fixed stealing wine in Draynor
2024-05-31 09:53:55 +00:00
thelemir
07c6eab4af Swapped kalphite guardians for soldiers in side room 2024-05-31 09:52:49 +00:00
GregF
dc3daebb59 Implemented Scorpion Catcher quest 2024-05-31 09:50:54 +00:00
thelemir
da6f05f8ce Converted tanners to Kotlin
Fixed snake hide tanning
Fixed interaction with Canifis tanner
2024-05-31 09:49:31 +00:00
GregF
66b1efdaa3 Fixed Vinesweeper exploit
Fixed Vinesweeper server crash
2024-05-31 09:33:32 +00:00
suichi
aed73183d1 Switching interface tabs no longer closes dialogue 2024-05-18 09:14:08 +00:00
GregF
66978b23ee Fixed Family Crest Chronozon Spawn issue 2024-05-13 15:22:45 +00:00
Player Name
f501468ead Fixed ironman mode being stuck after permadeath 2024-05-13 15:13:23 +00:00
GregF
a63867627e Removed slayer tasks from NPC config file
Fixed tutorial island text showing for level 3 skills
2024-05-13 15:12:27 +00:00
GregF
5d54ef56b3 Fixed slayer task bugs
Fixed Elvarg not counting as a green dragon
Fixed some trolls not counting
Fixed some ogres not counting
Fixed some turoths not counting
Fixed kalphite queen not counting correctly
2024-05-13 15:08:56 +00:00
GregF
acf27dada5 Fixed bug at end of Fremennik Trials requiring 10 free inventory slots
Fixed typos
2024-05-13 15:02:44 +00:00
GregF
73102d8f79 Added jungle tree to the list of 1 chop trees 2024-05-13 15:01:33 +00:00
Player Name
158cf41fd3 Fixed Bork/Surok instanced area music 2024-05-13 15:00:37 +00:00
GregF
cdead88473 Corrected ammo usable on each crossbow 2024-05-13 14:59:36 +00:00
Player Name
5d21ab74c0 Corrected NPC IDs for the Keldagrim carts 2024-05-13 14:55:58 +00:00
h h
782a70a582 Fixed granite lobster foraging 2024-05-13 14:54:51 +00:00
Player Name
38a580a431 Corrected music varps, fixes some music unlocks 2024-05-13 14:51:38 +00:00
Oven Bread
4c736e5aef Fixed all fired up quest log 2024-05-13 14:50:04 +00:00
GregF
0dcdc84f79 Refactored the Player Safety Stronghold 2024-04-17 07:45:55 +00:00
Player Name
6deadc6f90 Fixed an off-by-one error that made cooking brawlers unobtainable
Reworked the ::npc admin command to take an optional amount argument. Usage: ::npc id [amount] [shouldWalk]
Summoning points now no longer regenerate automatically
Rewrote the ring of life
Reverting a slayer ring to an enchanted gem no longer destroys the item if inventory is full
The inauthentic mounted glory in a POH now respects teleblock
Fixed revenents infinite healing
Winkins' farm exit message is now split correctly
Added egg spawn in front of the chicken shrine in Zanaris and added its authentic use handler to the shrine
2024-04-17 07:34:12 +00:00
GregF
50eb295fda Rewrote grappling, fixes Yanille south shortcut, Catherby skill check and requirements text getting cut off 2024-04-15 00:27:30 +00:00
GregF
24b314426e Refactored Seer NPC 2024-04-15 00:20:29 +00:00
GregF
a342f91156 Red feedback text is now used when issued commands are invalid
Yellow feedback text is now used when legacy commands are issued
2024-04-15 00:18:04 +00:00
GregF
64b40fbcf4 Improved handling of achievement diary rewards 2024-04-15 00:10:56 +00:00
Ceikry
0ade8bdf02 Fixed issue where eggs would occasionally spawn out-of-bounds
Added admin command to test egg spawning ::eggspawntest
2024-04-02 11:49:37 +00:00
Trident101
68cf133955 Added Padulah dialogue 2024-03-31 14:39:37 +00:00
Player Name
7190c3eda7 Fixed some construction hotspots for south-facing rooms 2024-03-31 14:29:27 +00:00
Player Name
ee9d386bc9 Added ::permadeath [player] admin command to wipe a player's save
Fixed some HCIM death bugs where state was not cleared
2024-03-31 14:29:26 +00:00
GregF
2da47d8353 Implemented thieving candles on Entrana 2024-03-31 14:29:25 +00:00
Player Name
5c977c0522 Better handling of full inventories
Made it possible to alch when inventory is full with non-coin items, if the alch would free up the necessary space
Made it possible to receive a kitten from Gertrude when inventory is full,  if the transaction would free the space for the kitten
Made it possible to receive a kitten from Gertrude when inventory is full even with more than 100 gp, if the pet can be summoned immediately
Gertrude's Quest completion - fixed bug causing loss of kitten with full inventory
Fixed a bug where Gertrude's kitten-giving dialogue will hang if spoken to while having a non-pet familiar out
Fixed typos
2024-03-31 14:17:25 +00:00
Player Name
2948d58934 Fixed possible softlock at Evil Bob event 2024-03-31 14:14:04 +00:00
Player Name
cde2dcc93f Replaced player name with player username in the Digsite examination certificates
Fixed some typos in the Grand Tree quest dialogue
Replaced unicode with ascii in the Grand Tree quest & Plague City quest
2024-03-31 14:13:23 +00:00
Player Name
4ae1448800 In non-building mode, construction objects that have not been built now no longer leave behind clipping flags
Added command ::drawclipping to visualize construction clipping flags
2024-03-31 14:11:46 +00:00
Ceikry
b1e6c9fe8c 2024 Easter Event
Added Easter event
Refactored event code
Added support for forced-global ground items
2024-03-31 03:43:26 +00:00
downthecrop
a7516f2d6e Fixed Nettle Tea wrong return item
Fixed Yak Hide crafting swapped items
Fixed mining bot dropped ore ironman restrictions
Fixed Ardy teleport tab requirements
Fixed Alice's husband not requiring ghostspeak
Fixed Fishing Trawler stuck on boat bug
Fixed POH debug region info showing in non-debug mode
2024-03-26 01:51:16 +00:00
Bonesy
1d4d380e93 Added missing Master Crafter dialogue 2024-03-26 01:48:50 +00:00
Ann
3b967791a4 Glass making now returns the correct type of bucket 2024-03-26 01:47:42 +00:00
Player Name
c96fa24999 Reformatted JSON config for migration to Zaros tool 2024-03-21 23:56:04 +00:00
GregF
bbfa1bb1e7 Smithing interface fixes
Now handles blurite correctly
Updated title
Fixed bullseye lanterns
Fixed bronze wire
Fixed glass lantern
2024-03-18 12:22:49 +00:00
GregF
675f0c1e37 Fixed Family Crest getting stuck when the drop from Chronozon is not picked up (fight is now repeatable if item is lost) 2024-03-17 09:01:42 +00:00
Bonesy
b8a887b319 Fixed crafting guild tanning interface
Rewrote master crafter dialogue
Added missing master crafter dialogues
Fixed issue preventing crafting guild entry with trimmed crafting cape
2024-03-17 08:59:11 +00:00
Jordan Christiansen
a1fc0ba7cc Fixed line that should be spoken by player in Philop dialogue 2024-03-17 08:27:32 +00:00
Oven Bread
a11b783c39 Fixed the organ animation in Lumbridge 2024-03-17 08:15:39 +00:00
GregF
b22c6057a3 Changed ::allow_aggro admin command to ::allowaggro true/false for consistency with other commands
Added message for ::allowaggro activation
Can now check ::allowaggro without toggling it by running it without a trailing true/false
2024-03-17 08:14:06 +00:00
GregF
6e9183ea8f Fixed unnoting items failing to unnote correctly when quantity is equal to free slots 2024-03-17 08:01:20 +00:00
GregF
ed47883bea Al Kharid warriors now help each other in combat 2024-03-17 07:58:17 +00:00
GregF
60e6049971 Fixed level 25 black guard stats and animations 2024-03-17 07:56:51 +00:00
Oven Bread
06038dbbdc Implemented The Dig Site quest 2024-03-17 07:53:59 +00:00
Jordan Christiansen
ca53059131 Improved ::ge interface handling 2024-03-16 12:31:22 +00:00
Jordan Christiansen
6cb4f118ea Bats now only drop bat wings during Rag and Bone Man quest 2024-03-16 12:17:22 +00:00
Oven Bread
6856d75d88 Corrected contents of Varrock newspaper and refactored related code 2024-03-16 12:10:19 +00:00
Player Name
8729f93d01 Added teleblock message for ancient magicks 2024-03-16 12:09:42 +00:00
Bonesy
dbbcf5601e Rewrote bone burying and corrected xp rates 2024-03-16 12:05:46 +00:00
ipkpjersi
d9355ec85f Fixed rock crab spawns on Waterbirth island 2024-03-16 09:05:37 +00:00
Oven Bread
43c8f43c49 Reverted Askeladden's spawn to the previous location 2024-03-05 01:49:13 +00:00
Patrick W.
28b7a75538 Added docker-compose file 2024-03-03 06:05:03 +00:00
Bonesy
0158d753f0 Karamja bug fixes and improvements
Improved Brimhaven NPC interactions
Both NPCs right click options now function
Dialogue converted to Kotlin for both NPCs
Minor dialogue modifications
Converted the Karamja Option Plugin to a Karamja Listener and Brimhaven Listener
Removed some duplicated handlers such at the ship yard gate and cart
Corrected the coins shown when paying to enter the Brimhaven dungeon
The palm tree now drops the leaf to the ground when shaken and has an animation
2024-03-03 05:49:59 +00:00
Player Name
3df5097442 Cleaned up more server name references and related strings 2024-03-03 05:47:37 +00:00
Bonesy
866372ad54 Fletching now checks for inventory space before fletching darts, headless arrows, and arrows 2024-03-03 05:44:25 +00:00
Jordan Christiansen
9ca9f01ca3 Fixed bank guard dialog typo 2024-03-03 05:32:57 +00:00
Jordan
2714448c61 Added Zanaris Evil Chicken Lair 2024-03-03 05:23:34 +00:00
GregF
98ee184652 Fixed issue with Man (ID 1086) not being able to be pick pocketed 2024-03-03 05:19:42 +00:00
Jordan
6b9a06d175 Stronghold of Player Safety now checks if inventory is full before awarding lamp rewards 2024-03-03 05:19:09 +00:00
zsrv
9068874556 Fixed issue where some scripts weren't cleared when the player moves 2024-03-03 05:18:22 +00:00
GregF
4f5d753104 Ported Peksa from Java to Kotlin 2024-03-03 05:17:18 +00:00
Player Name
ae53116fee Music fixes
Corrected music locations for Tolna's rift
The Digsite and Exam Centre now correctly play Lullaby and Venture all the time
Corrected borders for Venture 2, which now correctly plays in the dungeons underneath the Digsite
Corrected borders for Chain of Command, which now correctly plays in all of the Temple of Ikov dungeon (and the two versions of the boots of lightness dungeon)
Added a new track, the brine rat cave now plays Rising Damp
2024-02-21 02:06:15 +00:00
Jordan
9e5a7aefc8 Fixed issue where the player could be given stacks of 0 items 2024-02-21 02:03:41 +00:00
Jordan
6e2f8c6f30 Fixed fletching blurite c'bow 2024-02-14 22:45:44 +00:00
Bonesy
affb2e58e9 Making sets of bolts, arrows and headless arrows no longer continues indefinitely 2024-02-14 11:41:27 +00:00
Player Name
fff1476714 Replaced item IDs in construction code with constants 2024-02-14 11:36:35 +00:00
Player Name
08241eb1db Implemented pet shoo-away 2024-02-14 11:33:56 +00:00
zsrv
1d12dd741f Implemented auto splitting of excessively long dialogue lines
Many new farming-related player messages added, and some existing messages updated
Raking animation updated
Herb picking animation updated
Digging up farming patch animation updated
Plant cure animation updated
A scarecrow can be retrieved from a flower patch by digging it up with a spade
Picking fruit/berries stops when running out of inventory space
The player can no longer dig up a tree they have planted before chopping it down
2024-02-14 11:33:13 +00:00
Oven Bread
38c50c465d Implemented Temple of Ikov quest 2024-02-14 11:26:53 +00:00
Oven Bread
7804dfe791 Failing to clean herb message is now authentic 2024-02-03 11:19:16 +00:00
Bart Ribbers
37a874f471 Updated release script to use new website update post layout 2024-02-03 11:10:44 +00:00
ipkpjersi
b33517632e Fixed fish caught statistic not saving 2024-01-31 00:12:43 +00:00
Zerken
ed199e1478 Fixed Santa giving 0 coal 2024-01-29 10:02:24 +00:00
ipkpjersi
435ec3b1b6 Removed unused bosses from boss kill counter 2024-01-29 09:50:53 +00:00
Oven Bread
451fa73e3e Fixed the Death Plateau quest log
Fixed Druidic Ritual completion message
2024-01-29 09:49:23 +00:00
Player Name
2255238554 Fixed issue preventing some dragonstone jewellery teleports working at level 30 wilderness 2024-01-29 09:48:28 +00:00
Bonesy
9a5f1e85e2 Fixed text for quest cape removal
Quest cape can now be retrieved from the wise old man if both inventory and bank are full when quests are implemented
2024-01-29 09:47:20 +00:00
Bonesy
020d5a9c05 Fixed inconsistent and inauthentic messages for fishing
Fixed item grinding consuming the whole stack sometimes
Fixed incorrect Fremennik diary cheese task
Fixed Seer's diary candle task
2024-01-29 09:31:30 +00:00
h h
a7b5e77318 Adjusted Varrock armour bonus to be more authentic - 4% for ores up to coal, 3% for ores gold to mithril with tier 2 or 3 and 2% for adamantite with tier 3 2024-01-29 09:14:42 +00:00
Ryan L
66445f61a5 Corrected slayer hint text message formatting 2024-01-29 09:07:22 +00:00
Ryan L
13e5bf1666 Corrected typo in Grand Tree quest 2024-01-20 12:28:52 +00:00
Player Name
dff56510da Fixed music for Zanaris, Puro Puro, Lunar Isle and little cave of horrors 2024-01-20 12:05:49 +00:00
Trident101
2449bfe241 Rewrote Lilly dialogue
Rewrote Eadburg dialogue
Added examine texts for Achietties, Wizard Cromperty and Obli
Corrected seaweed spawn
2024-01-20 12:02:42 +00:00
Bonesy
4ec0f4aa27 Rewrote molten glass blowing
Fixed animations
Timing has been corrected, now takes 2 ticks instead of 3
2024-01-20 12:00:30 +00:00
zsrv
0f9e264788 Improved authenticity of many messages
Fixed explorer's ring using a charge when already at 100% energy
2024-01-20 11:34:51 +00:00
Player Name
86973b6d36 Added message when running out of prayer points
Improved handling of running out of prayer points
2024-01-20 11:31:18 +00:00
Oven Bread
6763758196 Added some missing XTEA keys 2024-01-20 11:23:24 +00:00
Player Name
4fc5e088ad Fixed bug that could result in players losing Christmas event rewards if their inventory is full 2024-01-19 09:50:26 +00:00
Zerken
12daa614bb Implemented news message for achieving max level in all skills 2024-01-09 03:53:39 +00:00
Kennynes
9b484d337c Replaced current rune kite (h#) shield hard clue rewards with the correct shield items 2024-01-09 03:53:07 +00:00
Ryan L
a13b38d6c1 Corrected typo in Tree Gnome Village quest 2024-01-09 03:41:35 +00:00
Player Name
1218ee000f Corrected examine for dragon bones 2024-01-03 04:54:45 +00:00
Bonesy
0a6b607700 Refactored battlestaff crafting to follow authentic interfaces and timing 2023-12-29 01:15:59 +00:00
Player Name
279cfb8b42 Improved pet handling and fixed some bugs
Players with merged pets will have the merge resolved next time they are dropped
2023-12-29 01:09:55 +00:00
Jordan
ee88bfe3f0 Fixed Bogrog spirit shard pouch exchange rounding 2023-12-29 00:55:35 +00:00
Dan Ginovker
04ce0879c8 Fixed stairs around Castle Wars 2023-12-29 00:53:08 +00:00
Player Name
85ee81a42a Fixed pack yak scroll deleting items when bank is full 2023-12-29 00:52:26 +00:00
Player Name
81fd565b4f Corrected music for Tolna's rift and Sorceress's Garden 2023-12-29 00:51:28 +00:00
Player Name
ece16af7ab Bot dialogue now always starts with uppercase character
Fixed hard-coded server name references
Replaced incorrect use of "Keldagrim" with "Gielinor"
2023-12-29 00:50:26 +00:00
fake name
9d19ce2355 Fixed issue where Halgrive does not replace lost poisoned feed 2023-12-13 12:16:47 +00:00
Player Name
cecb937145 Players now kicked out of unimplemented werewolf agility course 2023-12-13 12:13:48 +00:00
Player Name
0cad82029d Authenticity improvements for the dramen tree
The dramen tree now has the highest possible chop speed
Chopping the dramen tree now aborts once the branch has been obtained
The tree spirit no longer uses the rare seed drop table, instead drops nothing
The tree spirit can now be attacked by other players
2023-12-13 12:09:57 +00:00
Bonesy
25e9104375 Pet rock animations & fixes
Made the Pet rock two-handed
Changed Pet rock weight to 1 kg
Edited dialogue for the Talk option to be more authentic
Added animation for the Stroke option & a delay for the second message to wait for the animation to finish
Edited dialogue for the Fetch option to be more authentic, added animations & graphics, and added the projectile with graphics
Added animations & graphics for the Stay option
2023-12-13 12:08:10 +00:00
Oven Bread
6c28a82ebb NPC fixes at:
Mountain Camp (next to Troll Stronghold)
Jiggig
Gu'Tanoth
Oo'glog
2023-12-13 12:06:14 +00:00
Trident101
7a4c2159a4 Dialogue and examine fixes
Converted Lidio dialogue to Kotlin
Converted Anton dialogue to Kotlin
Added Achietties and updated dialogue file
Updated servant dialogue
Updated Wistan dialogue
Changed examine text of Scrying orb, uncharged & charged
Added examine text to wizard Cromperty
Changed bucket examine text
Updated Unferth dialogue
2023-12-13 12:04:46 +00:00
Trident101
ae22b99888 Added missing Zanaris examines
Fixed temple, north staircase interaction
2023-12-13 11:59:41 +00:00
Player Name
7fb90f5afe Corrected examine for Dagannoth Bonemeal 2023-11-25 14:46:26 +00:00
Player Name
d3f1914117 Added music for Chaos Tunnels & Tunnel of Chaos 2023-11-25 14:46:19 +00:00
Player Name
c70c292943 Abyss obstacle success rate is now 100% at level 99 (instead of 99%) 2023-11-25 14:36:50 +00:00
Player Name
8f7683aee4 Skillcape dailies reset with other dailies at midnight server time 2023-11-25 14:35:49 +00:00
Oven Bread
26245dfb10 Bug fixes for getting stuck in Creature of Fenkenstrain 2023-11-12 13:43:26 +00:00
Avi Weinstock
b2eb9cfdc9 Fixed rapid heal bug
Improved reliability of runecrafting unit tests
2023-11-11 05:52:09 +00:00
Oven Bread
2dce4fe98c Implemented Rag and Bone Man quest (part 1) 2023-11-11 05:09:54 +00:00
LostMyPhat
6d0ca0d6fc Fixed male/female dialogue in Druidic Ritual 2023-11-11 04:08:08 +00:00
Zerken
cd4d0ec20b Implemented 7 Christmas Holiday randoms:
Snowman
Snowman Fight
Santa
Jack Frost
Choir
Snowstorm
Cook
2023-11-11 03:49:04 +00:00
Woahscam
8ef5d8bce4 Fixed numerous interfaces, including Puro puro, Destroy item, Equipment, kept on death, Cooking (single prompts i.e. raw fish -> range), Fletching (make set i.e. fletching arrows, bow)
Rewrote herb cleaning to listener
Fixed studded leather crafting level requirement and xp
Fixed bow stringing stealing strings
::quest <player> can now be used to look up a player's completed quests
2023-11-11 03:16:35 +00:00
Oven Bread
098d947d87 Fixed Creature of Fenkenstrain quest point reward 2023-11-05 13:12:10 +00:00
Wouter Standaert
5a6a148cfc Rewrote MysteriousRuinPlugin to a listener
Fixed Varrock earth tiara easy diary task
2023-11-05 09:37:41 +00:00
LostMyPhat
18fa8357a8 Fixed amulet of glory wilderness teleport level 2023-11-05 08:42:48 +00:00
Player Name
e1b7eeaf22 Fencing ring now requires 8 oak planks rather than 8 steel kiteshields 2023-11-05 08:41:33 +00:00
Wouter Standaert
b834ff7404 Fixed gender specific dialogue for Hadley 2023-11-05 08:20:12 +00:00
Player Name
a04c36f5cd Improved accuracy of barrows rewards 2023-11-05 08:20:10 +00:00
Player Name
04882136f8 POH slayer trophy now obtainable, added all heads as tertiary drops 2023-11-05 08:20:09 +00:00
Player Name
d08882cf58 Added optional player argument to ::setlevel 2023-11-05 08:20:08 +00:00
Player Name
f28076f3a4 Fixed bug involving kitten/cat deletion 2023-11-05 08:20:06 +00:00
Player Name
978d70ad0c Fixed typo in Chaos Tunnels portal
Fixed typo in gnome glider to digsite
Fixed a few typos in the random phrases uttered by the Bork minions
Added missing Bork minion phrase
2023-11-05 08:20:04 +00:00
Zachary Terwillegar
af4a316fa1 Fixed failed sheep shearing movement 2023-11-03 15:08:58 +00:00
Zerken
dbb8b5a133 Implemented Strange Plant Random Event 2023-11-03 14:55:41 +00:00
Oven Bread
0eecab4057 Implemented Creature of Fenkenstrain quest 2023-11-02 08:33:02 +00:00
Oven Bread
8316a492c9 Added tool leprechaun dialogue (excluding goth) 2023-11-02 08:28:49 +00:00
LostMyPhat
2ab3c34402 Fixed drill sergeant completion reward drop bug 2023-11-02 08:26:48 +00:00
Oven Bread
70a47aeb5d Implemented Tolna Rift
Improved ::npcanim admin command
2023-11-02 08:26:27 +00:00
Wouter Standaert
7d1a16f7f7 Fixed examine text, slayer tip and drops of vampires 2023-11-02 08:26:25 +00:00
h h
eb18fef53d Corrected typos in Denulth's Troll Stronghold dialogues
Corrected typo in Drezel's Nature Spirit dialogue
Corrected typos in Blaze Sharpeye's All Fired Up dialogues
Corrected typo in Dragon Slayer chest dialogue
2023-10-28 01:39:51 +00:00
Zerken
b7851e7671 Implemented swarm random event 2023-10-27 12:49:26 +00:00
Avi Weinstock
fee56ae528 Backported probabilistic runes. Can now toggle between revision 581, 573 and 570 behavior via runecrafting_formula_revision in server config 2023-10-27 12:41:17 +00:00
Player Name
a74583b13b Big bass, shark, and swordfish are now obtainable from fishing
The message for catching shark now ends with an authentic exclamation mark
The fishing skill cape perk now logs catching a second fish in player stats
2023-10-27 12:37:13 +00:00
Zerken
4942ae0079 Added the correct animation/graphics for emptying the ectophial
Rewrote ectophial
2023-10-27 12:33:11 +00:00
Player Name
9445a2bae5 Death's message for the holiday random event now uses the correct type of player name 2023-10-24 13:35:09 +00:00
Creamy Goodness
3c9dea2830 Sheep now face player when sheared 2023-10-24 13:34:37 +00:00
Player Name
1f2bd0f9fc Corrected linked construction hotspots for shelves, thrones and statues 2023-10-20 23:21:31 +00:00
Trident101
ae0b384e44 Refactored some dialogues in the Ardougne area
Remapped Kortan's shop
Fixed stock of Aemad's shop
2023-10-20 23:20:39 +00:00
Player Name
b640ab7373 Leaving the fight caves now also clears poison, disease and restores run energy (QoL fix) 2023-10-20 07:09:43 +00:00
Kennynes
48e09a3f8a Added examine texts to bob shirts (obtained from easy clues) 2023-10-20 07:03:02 +00:00
Trident101
5f4450c7d2 Several additions and changes to Zanaris
Added fairy queen dialogue
Added movement to the cows
Added a spawnpoint for Blaec
Added examine texts
2023-10-20 06:57:18 +00:00
Kennynes
3b150660b1 Fixed incorrect adamant shield (h#) in medium clue reward pool 2023-10-20 06:56:59 +00:00
Zerken
2bcb05ee6c Fixed rune consumption when teleblocked 2023-10-20 06:56:54 +00:00
Jedediah Orne
e2a13465b6 Fixed wilderness zoning near KBD lever 2023-10-20 06:56:52 +00:00
Player Name
0779a550a3 Updated README.md with working link to Thanos tool + java 11 reminder 2023-10-20 00:48:48 +00:00
ryannathans
c03fa76ea1 Deleted obsolete GE tool 2023-10-18 00:38:19 +00:00
Memzak
874c3883e6 Charlie now says 2009Scape in The Grand Tree 2023-10-17 11:07:03 +00:00
Von
a190544519 Corrected moss giant drop table 2023-10-17 11:02:36 +00:00
Von
102cc65fd2 Corrected fire giant drop table 2023-10-17 11:02:26 +00:00
Zerken
0e6b4ad816 Fixed fishing trawler teleport and random event issues 2023-10-17 11:02:12 +00:00
Player Name
5237051e71 Fixed construction requirement for combat rings 2023-10-17 11:01:47 +00:00
Player Name
0eaa6000e0 Made firemaking skillcape a valid light source for the giant mole 2023-10-14 01:27:08 +00:00
Zerken
4e1ddaeec5 Implemented Rick Turpentine and Drunken Dwarf random events 2023-10-12 23:34:25 +00:00
Von
b308e488f9 Corrected Skeletal Wyvern drop table 2023-10-12 01:48:31 +00:00
Oven Bread
264f78eb11 Added the two NPCs above the furnace in Falador 2023-10-12 01:47:04 +00:00
bushtail
9989ee9905 Rewrote Stat Spy
Refactored lunar spell handlers
2023-10-12 01:43:43 +00:00
Von
1913d0c83f Corrected Waterbirth Island Dagannoth drop tables 2023-10-12 01:40:42 +00:00
Woahscam
0f083bcaaa Fixed incorrect index for statuette rotation attribute used in the Golem quest 2023-10-12 01:32:34 +00:00
Zerken
150e0619c1 Fixed empty item regression breaking rune pouches and ectophial 2023-10-08 12:10:03 +00:00
Von
663558cc8c Corrected Cockatrice drop table 2023-10-07 00:41:57 +00:00
Von
44f7c7bd78 Corrected Ice Giant drop table 2023-10-07 00:36:42 +00:00
Von
3638cf60f7 Corrected Ogre drop table
Corrected Ogress drop table
Corrected Ogress Warrior drop table
Corrected Ogress Champion drop table
2023-10-07 00:34:07 +00:00
Von
d429d3023b Corrected Dark Beast drop table 2023-10-07 00:33:23 +00:00
Oven Bread
ba1807c76f Huge wilderness data audit and correction, including the following areas
Frozen Waste Plateau (Within members gate)
Agility Course
Pirate Cove
Mage Arena Area
Mage Arena
Inside Mage Arena
Deserted Keep
Magic Axe Hut
Near Deserted Keep below Magic Axe Hut
Scorpion Pit
Chaos Elemental
Rogues' Castle
Top Right Volcano
Lava Maze
Red dragon Isle
Mining Hobgoblin Area
Canoe area
Wilderness Volcano
Forgotten Cemetery
West of Stealing Creation
Stealing Creation
Ruins right side
Front of Ruins
Demonic Ruins
Near Corp Cave
Ruins left side
Graveyard of Shadows
Bandit Camp
Spider Mound near Sapphire Gems
Dark Warrior Fortress
Clan Wars
Ruins south of clan wars
Chaos Altar
Bottom East
2023-10-05 01:18:23 +00:00
Von
aaebd7478d Corrected Dagannoth Prime drop table 2023-10-05 00:22:17 +00:00
Von
6325ffefbb Corrected Dagannoth Supreme drop table 2023-10-05 00:15:10 +00:00
Von
25e944f37c Corrected Dagannoth Rex drop table 2023-10-05 00:13:13 +00:00
Von
7f9617554a Corrected Gargoyle drop table 2023-10-05 00:12:50 +00:00
Von
7ced5ae031 Corrected TzHaar-Xil drop table 2023-10-05 00:07:55 +00:00
Trevor
0e87138789 Implemented eating of frog spawn 2023-10-05 00:03:35 +00:00
Player Name
ee42a4b82d The name of the location where the shooting star has dropped is now no longer lowercased 2023-10-05 00:03:32 +00:00
Von
4d3d6e59e1 Corrected TzHaar-Mej drop table 2023-10-05 00:00:00 +00:00
Von
5b1e6de903 Corrected TzHaar-Hur drop table 2023-10-04 23:58:26 +00:00
Trevor
94a55190ee Barbarian potion refactor
Fixed barbarian potions that can take either a roe or caviar from consuming both
Corrected level requirement and product potion id for hunter and antifire mixes
Corrected input potion id for fishing mix
Implemented antidote+ mix
Fixed level requirement for super energy mix
Fixed duration of antipoison mix (now 90 seconds)
2023-10-04 23:48:51 +00:00
downthecrop
708d5bb507 Rewrote Captain Barnaby and Shilo Cart interactions 2023-10-04 23:35:24 +00:00
Oven Bread
e9fd74b379 Refactored canoe handling
Canoe station should now have the full animation suite
Canoe making now scales with axe and level of woodcutting
Interfaces are now fully updated with proper hide/show/animation
Canoes now sink at the end of the journey
Added a black screen backdrop overlay seen only in HD
2023-10-04 23:30:51 +00:00
Ryan
b87a3821dd Corrected Vesta's longsword damage 2023-10-04 23:26:42 +00:00
Player Name
7c38339e16 Rewrote pet management
Fixed being unable to remove pets
Removed redundant pet messaging
2023-10-04 23:19:57 +00:00
Von
e5afeed6db Corrected TzHaar-Ket drop table 2023-10-04 23:17:02 +00:00
Ceikry
cc989d5844 Added support for tertiary drop tables 2023-10-04 23:17:01 +00:00
1687 changed files with 134105 additions and 56312 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

@ -72,7 +72,7 @@ There are many ways everyone can contribute! From the most seasoned programmers
* **Wiki Editors**: Did you know we have a wiki? Well it's always in need of people to fill it out and stay on top of it. Editing the wiki is one of the easiest ways you can contribute to 2009Scape! If you're an active player and have the will, there's so much you could be helping out with over at the wiki. [Click here to go to the wiki](https://cdn.2009scape.org/wiki/doku.php?id=start). * **Wiki Editors**: Did you know we have a wiki? Well it's always in need of people to fill it out and stay on top of it. Editing the wiki is one of the easiest ways you can contribute to 2009Scape! If you're an active player and have the will, there's so much you could be helping out with over at the wiki. [Click here to go to the wiki](https://cdn.2009scape.org/wiki/doku.php?id=start).
* **JSON editors**: We could always use more JSON editors! Please note that JSON editing **must** be done using the [Thanos Tool](https://gitlab.com/2009scape/rs09-thanos-tool/-/jobs/artifacts/master/raw/build/libs/thanostool.jar?job=build). * **JSON editors**: We could always use more JSON editors! Please note that JSON editing **must** be done using the [Thanos Tool](https://gitlab.com/2009scape/tools/rs09-thanos-tool/-/jobs/5153567519/artifacts/file/build/libs/zaros.jar). **This does not run on modern Java** and requires **Java 11** to run (using the usual 'java -jar zaros.jar').
* **Authenticity Auditors**: As a remake, authenticity is central to our core values! We could always use someone to go through the game and create large lists of simple tasks that can be done to bring us closer to the authentic 2009 game! The preferred way to do this is one-area-at-a-time. If you want to see an example of some audits we've done in the past, take a look [here](https://gitlab.com/2009scape/2009scape/-/issues/46). * **Authenticity Auditors**: As a remake, authenticity is central to our core values! We could always use someone to go through the game and create large lists of simple tasks that can be done to bring us closer to the authentic 2009 game! The preferred way to do this is one-area-at-a-time. If you want to see an example of some audits we've done in the past, take a look [here](https://gitlab.com/2009scape/2009scape/-/issues/46).
@ -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.**
@ -149,4 +221,4 @@ These credits can be spent in the 2009Scape Reward Shop. It's important to be cl
Testers are not the only people who can gain credits - other ways of earning credits can be found on [the 2009Scape website](https://2009scape.org/site/game_guide/credits.html). Testers are not the only people who can gain credits - other ways of earning credits can be found on [the 2009Scape website](https://2009scape.org/site/game_guide/credits.html).
Please be patient! The Credit system is not fully complete yet, so it will take a long time for credits to be awarded. Please be patient! The Credit system is not fully complete yet, so it will take a long time for credits to be awarded.

1
Server/.gitignore vendored
View file

@ -2,6 +2,7 @@ bin/**
out/** out/**
data/logs/** data/logs/**
data/profile/** data/profile/**
data/playerstats/**
.idea/** .idea/**
/bin /bin
.DS_Store** .DS_Store**

View file

@ -13,7 +13,7 @@
"This is my own dialogue", "This is my own dialogue",
"@name run.", "@name run.",
"@name you cant hide from me.", "@name you cant hide from me.",
"jajajajajaja", "Jajajajajaja",
"How do i get to Varrock @name?", "How do i get to Varrock @name?",
"How do i get to Camelot @name?", "How do i get to Camelot @name?",
"How do i get to Taverly @name?", "How do i get to Taverly @name?",
@ -21,17 +21,17 @@
"How do i get to Yanille @name?", "How do i get to Yanille @name?",
"How do i get to Catherby @name?", "How do i get to Catherby @name?",
"Gotta go srry.", "Gotta go srry.",
"wiggle wiggle wiggle yeah", "Wiggle wiggle wiggle yeah",
"@name lookin goofy", "@name lookin goofy",
"@name lookin stoopid", "@name lookin stoopid",
"@name lookin like a red bracket", "@name lookin like a red bracket",
"@name get yo weasel lookin ass outta here", "@name get yo weasel lookin ass outta here",
"@name lookin like some sort of twocan sam", "@name lookin like some sort of twocan sam",
" /hop world 1 got a noob here!", " /hop world 1 got a noob here!",
"woot", "Woot",
"Hows your day been @name?", "Hows your day been @name?",
"heyy @name :)", "Heyy @name :)",
"gtg srry", "Gtg srry",
"I wont answer your questions @name", "I wont answer your questions @name",
"Stop asking questions @name", "Stop asking questions @name",
"Roflmao", "Roflmao",
@ -48,7 +48,7 @@
"Nice Armor @name!", "Nice Armor @name!",
"Nice Weapon @name!", "Nice Weapon @name!",
"Venezuela #1", "Venezuela #1",
"2009Scape and chill @name?", "2009scape and chill @name?",
"@name is my girlfriend", "@name is my girlfriend",
"Buying gf", "Buying gf",
"Bank sale pm me for info", "Bank sale pm me for info",
@ -61,14 +61,14 @@
"Fuckin sit @name.", "Fuckin sit @name.",
"Error: Botting client broken tell Evilwaffles.", "Error: Botting client broken tell Evilwaffles.",
"@name bots all the time", "@name bots all the time",
"report @name", "Report @name",
"apparently @name bots", "Apparently @name bots",
"@name hates kermit", "@name hates kermit",
"There are no mods on to help you", "There are no mods on to help you",
"Report me, you wont", "Report me, you wont",
"Yes, Im botting. And?", "Yes, Im botting. And?",
"ERROR: BOTSCRIPT 404. REPORT TO BOT OWNER (Evilwaffles)", "ERROR: BOTSCRIPT 404. REPORT TO BOT OWNER (Evilwaffles)",
"flash2:wave: FUCK", "Flash2:wave: FUCK",
"I love 2009Scape!", "I love 2009Scape!",
"Ja Ja Ja Ja", "Ja Ja Ja Ja",
"This is fun!", "This is fun!",
@ -105,9 +105,9 @@
"Trade me @name", "Trade me @name",
"LOL", "LOL",
"How do I get to lumbrich", "How do I get to lumbrich",
"bruh", "Bruh",
"poggers", "Poggers",
"shitpost", "Shitpost",
"I wish i could find an RS Gf", "I wish i could find an RS Gf",
"Where do you find runite ore @name?", "Where do you find runite ore @name?",
"Where is the best coal location @name?", "Where is the best coal location @name?",
@ -135,33 +135,33 @@
"Im not a bot", "Im not a bot",
"Nah Im a real person", "Nah Im a real person",
"Bruh are you even a real person lol?", "Bruh are you even a real person lol?",
"e", "E",
"Hellooooo @name", "Hellooooo @name",
"wc lvl @name?", "Wc lvl @name?",
"fletching level @name?", "Fletching level @name?",
"firemaking level @name?", "Firemaking level @name?",
"Have you seen the dude in the ge?", "Have you seen the dude in the ge?",
"Wonderful weather today @name", "Wonderful weather today @name",
"Lowkey drunk af rn", "Lowkey drunk af rn",
"I am so tired", "I am so tired",
"Wassup @name", "Wassup @name",
"follow me @name!", "Follow me @name!",
"Server goes brrrr", "Server goes brrrr",
"bruh i am not a bot", "Bruh i am not a bot",
"I think @name is a bot", "I think @name is a bot",
"Are you a bot @name?", "Are you a bot @name?",
"insert spiderman meme here", "Insert spiderman meme here",
"pot calling the kettle black etc", "Pot calling the kettle black etc",
"ooh, a piece of candy", "Ooh, a piece of candy",
"I love woodcutting", "I love woodcutting",
"Im going to go level up later", "Im going to go level up later",
"I love mining shooting stars", "I love mining shooting stars",
" /this @name looks dumb", " /this @name looks dumb",
"AAAAAAAAAAAAAAAAAAAAAAAAHHHHHH!!!", "AAAAAAAAAAAAAAAAAAAAAAAAHHHHHH!!!",
"como estas @name", "Como estas @name",
"so how about that ceikry guy", "So how about that ceikry guy",
"so how about that kermit dude", "So how about that kermit dude",
"woah is an abusive mod", "Woah is an abusive mod",
"I heard Woah and Ceikry are dating now", "I heard Woah and Ceikry are dating now",
"House party in Yanille!", "House party in Yanille!",
"Can i have some gp @name?", "Can i have some gp @name?",
@ -188,33 +188,33 @@
"NobodyCLP has big feet", "NobodyCLP has big feet",
"Chicken tendies for dindin", "Chicken tendies for dindin",
"Spicey Chicken tendies is litty as a mf titty", "Spicey Chicken tendies is litty as a mf titty",
"red bracket stinky", "Red bracket stinky",
"ra ra rasputin", "Ra ra rasputin",
"lover of the russian queen", "Lover of the russian queen",
"Whens the next update coming out?", "Whens the next update coming out?",
"How many players are maxed?", "How many players are maxed?",
"I dont use discord @name", "I dont use discord @name",
"I dont use the CC @name", "I dont use the CC @name",
"Why should i use discord?", "Why should i use discord?",
"2009Scape is life", "2009Scape is life",
"brb gotta make dinner", "Brb gotta make dinner",
"I need to go to the GE", "I need to go to the GE",
"@name can i have a ge tele?", "@name can i have a ge tele?",
"lol @name shut up", "Lol @name shut up",
"Where are teak trees?", "Where are teak trees?",
"How do i make planks @name?", "How do i make planks @name?",
"Idk about that scraggley ass alex guy.", "Idk about that scraggley ass alex guy.",
"Rusty? More like Crusty af lmfao.", "Rusty? More like Crusty af lmfao.",
"I need to sell some stuff on the ge", "I need to sell some stuff on the ge",
"I have so many logs to sell lol", "I have so many logs to sell lol",
"nah", "Nah",
"yes", "Yes",
"Where can i mine iron?", "Where can i mine iron?",
"Where can i mine tin?", "Where can i mine tin?",
"Where can i mine copper?", "Where can i mine copper?",
"Where can i mine clay?", "Where can i mine clay?",
"Where can i mine coal?", "Where can i mine coal?",
"no", "No",
"We are no strangers to love", "We are no strangers to love",
"You know the rules and so do I", "You know the rules and so do I",
"A full commitment's what I'm thinking of", "A full commitment's what I'm thinking of",
@ -228,10 +228,10 @@
"Never gonna make you cry", "Never gonna make you cry",
"Never gonna say goodbye", "Never gonna say goodbye",
"Never gonna tell a lie and hurt you", "Never gonna tell a lie and hurt you",
"why", "Why",
"why", "Why",
"why", "Why",
"why", "Why",
"Why does it not show your messages in the chatbox?", "Why does it not show your messages in the chatbox?",
"Why do you not show up in chat?", "Why do you not show up in chat?",
"Why do you not show up in chat @name?", "Why do you not show up in chat @name?",
@ -239,7 +239,7 @@
"When did you start playing @name?", "When did you start playing @name?",
"When did you start on this server @name?", "When did you start on this server @name?",
"When did you first get here @name?", "When did you first get here @name?",
"russias greatest love machine", "Russias greatest love machine",
"Never gonna run around and desert you", "Never gonna run around and desert you",
"Two things are infinite, the universe & @names stupidity", "Two things are infinite, the universe & @names stupidity",
"If you tell the truth, you dont have to remember anything.", "If you tell the truth, you dont have to remember anything.",
@ -257,7 +257,7 @@
"What do you think @name?", "What do you think @name?",
"How does that sound @name?", "How does that sound @name?",
"That sounds great @name.", "That sounds great @name.",
"Im learning English.", "I'm learning English.",
"I don't understand.", "I don't understand.",
"Could you repeat that please @name?", "Could you repeat that please @name?",
"Could you please talk slower @name?", "Could you please talk slower @name?",
@ -281,26 +281,26 @@
"@name?", "@name?",
"@name how long have you played", "@name how long have you played",
"@name world 1 or world 2?", "@name world 1 or world 2?",
"what is your main world @name?", "What is your main world @name?",
"I prefer world 1 tbh", "I prefer world 1 tbh",
"I prefer world 2 tbh", "I prefer world 2 tbh",
"@name world 1 for life", "@name world 1 for life",
"@name fog bots when?", "@name fog bots when?",
"damn somalian pirates", "Damn somalian pirates",
"bracket more like brrrrrr acket", "Bracket more like brrrrrr acket",
"why the racket bracket", "Why the racket bracket",
"Hi @name I am dad", "Hi @name I am dad",
"@name likes dad jokes", "@name likes dad jokes",
"ur nuts @name", "Ur nuts @name",
"lootshare go brr", "Lootshare go brr",
"partay with froggay", "Partay with froggay",
"Know what else is lame? Not being able to play 2009scape right now", "Know what else is lame? Not being able to play 2009scape right now",
"Can you even grind on osrs", "Can you even grind on osrs",
"i botted to 88 fishing", "I botted to 88 fishing",
"Do not forget to vote in running polls!", "Do not forget to vote in running polls!",
"Always check announcments", "Always check announcments",
"we thrivin", "We thrivin",
"ship @name", "Ship @name",
"Dont forget to vote 2009scape!", "Dont forget to vote 2009scape!",
"Kermit is too legit 2 quit", "Kermit is too legit 2 quit",
"Out here on the range we are having fun", "Out here on the range we are having fun",
@ -310,11 +310,11 @@
"I dont like him @name", "I dont like him @name",
"I dont like it @name", "I dont like it @name",
"Im an American.", "Im an American.",
"ima go pickup my lady ting", "Ima go pickup my lady ting",
"that portuguese dude is something else", "That portuguese dude is something else",
"@name!! @name!!", "@name!! @name!!",
"bowdi boy", "Bowdi boy",
"i love bowdi... sometimes", "I love bowdi... sometimes",
"@name = @name", "@name = @name",
"I'm bacon.. go on dad... say it", "I'm bacon.. go on dad... say it",
"I'm going to leave.", "I'm going to leave.",
@ -338,7 +338,7 @@
"I couldn't agree more @name", "I couldn't agree more @name",
"It cost me a fortune @name", "It cost me a fortune @name",
"I am dog tired", "I am dog tired",
"Dont take it personally", "Don't take it personally",
"We will be having a good time", "We will be having a good time",
"Same as always @name", "Same as always @name",
"No problem", "No problem",
@ -360,40 +360,23 @@
"530 gang for life", "530 gang for life",
"@name, have you read the rules?", "@name, have you read the rules?",
"@name, have you checked out the forums?", "@name, have you checked out the forums?",
"why are the leprechauns moving?", "Why are the leprechauns moving?",
"I am beyond the point of no return!", "I am beyond the point of no return!",
"Nothin' personnel, kid.", "Nothin' personnel, kid.",
"All your base are belong to us", "All your base are belong to us",
"May Guthix bring you balance.", "May Guthix bring you balance.",
"May Guthix bring you balance.", "May Guthix bring you balance.",
"May Guthix bring you balance.", "May Guthix bring you balance.",
"Thy death was not in vain, for it brought some balance to the world. May Guthix bring you rest.",
"May you walk the path, and never fall, for Guthix walks beside thee on thy journey. May Guthix bring you peace.",
"All things must end, as all begin; Only Guthix knows the role thou must play. May Guthix bring you balance.",
"In life, in death, in joy, in sorrow: May thine experience show thee balance. May Guthix bring you balance.",
"Thou must do as thou must, no matter what. Thine actions bring balance to this world. May Guthix bring you balance.",
"The river flows, the sun ignites, May you stand with Guthix in thy fights. May Guthix bring you balance.",
"A journey of a single step, May take thee over a thousand miles. May Guthix bring you balance.", "A journey of a single step, May take thee over a thousand miles. May Guthix bring you balance.",
"Zamorak give me strength!", "Zamorak give me strength!",
"Zamorak give me strength!", "Zamorak give me strength!",
"Zamorak give me strength!", "Zamorak give me strength!",
"May your bloodthirst never be sated, and may all your battles be glorious. Zamorak bring you strength.",
"There is no opinion that cannot be proven true...by crushing those who choose to disagree with it. Zamorak give me strength!",
"Battles are not lost and won; They simply remove the weak from the equation. Zamorak give me strength!",
"Those who fight, then run away, shame Zamorak with their cowardice. Zamorak give me strength!",
"Battle is by those who choose to disagree with it. Zamorak give me strength!",
"Strike fast, strike hard, strike true: The strength of Zamorak will be with you. Zamorak give me strength!",
"The weak deserve to die, so the strong may flourish. This is the creed of Zamorak.", "The weak deserve to die, so the strong may flourish. This is the creed of Zamorak.",
"This is Saradomin's wisdom.", "This is Saradomin's wisdom.",
"This is Saradomin's wisdom.", "This is Saradomin's wisdom.",
"This is Saradomin's wisdom.", "This is Saradomin's wisdom.",
"Go in peace in the name of Saradomin; may his glory shine upon you like the sun.", "Go in peace in the name of Saradomin; may his glory shine upon you like the sun.",
"Thy cause was false, thy skills did lack; See you in Lumbridge when you get back.", "Thy cause was false, thy skills did lack; See you in Lumbridge when you get back.",
"Protect your self, protect your friends. Mine is the glory that never ends. This is Saradomin's wisdom.",
"The darkness in life may be avoided, by the light of wisdom shining. This is Saradomin's wisdom.",
"Show love to your friends, and mercy to your enemies, and know that the wisdom of Saradomin will follow. This is Saradomin's wisdom.",
"A fight begun, when the cause is just, will prevail over all others. This is Saradomin's wisdom.",
"The currency of goodness is honour; It retains its value through scarcity. This is Saradomin's wisdom.",
"For Camelot!", "For Camelot!",
"Firmly grasp it!", "Firmly grasp it!",
"My legs!", "My legs!",
@ -410,7 +393,7 @@
"Fluff", "Fluff",
"Bwuh", "Bwuh",
"I'm literally just mothin' bro", "I'm literally just mothin' bro",
"Certified 2009scape classic.", "Certified 2009Scape Classic.",
"Make sure to like, comment and subscribe @name it really helps", "Make sure to like, comment and subscribe @name it really helps",
"Real 2009scape hours!!! Murder that like if you up!!!!", "Real 2009scape hours!!! Murder that like if you up!!!!",
"W00t!", "W00t!",
@ -424,32 +407,32 @@
"Drip check", "Drip check",
"Uhuhuhuhuhuhuhuhu", "Uhuhuhuhuhuhuhuhu",
"Ahhhhhhhhhhhhhhhh", "Ahhhhhhhhhhhhhhhh",
"yall got any deez?", "Yall got any deez?",
"Deez nuts", "Deez nuts",
"When she give you that yoinky sploinky", "When she give you that yoinky sploinky",
"Sir, this is a 2009scape.", "Sir, this is a 2009Scape.",
"Oh dear! You are dead!", "Oh dear! You are dead!",
"Cor blimey, mate! What are ye doing in me pockets?", "Cor blimey, mate! What are ye doing in me pockets?",
"yeah i got funnies", "Yeah i got funnies",
"read muv luv", "Read muv luv",
"Why doesn't she love me bros?", "Why doesn't she love me bros?",
"@name is off the goop don't listen to the clown", "@name is off the goop don't listen to the clown",
"do yall got laptops", "Do yall got laptops",
"cfunny play the alien warp sound effect", "Cfunny play the alien warp sound effect",
"Ware to all whom doom hither, where cope is all yet constant.", "Ware to all whom doom hither, where cope is all yet constant.",
"Who wants to come G W D?", "Who wants to come G W D?",
"How do I make money?", "How do I make money?",
"Ironmen stand alone together!", "Ironmen stand alone together!",
"based", "Based",
"where is she", "Where is she",
"*S N I I I I I I I I I F F F F F F F F F F F*", "*S N I I I I I I I I I F F F F F F F F F F F*",
"Hey @name, who was in Paris?", "Hey @name, who was in Paris?",
"Huh whuh?", "Huh whuh?",
"who's lone?", "Who's lone?",
"who *is* he?", "Who *is* he?",
"Hi @name, I'm Dad!", "Hi @name, I'm Dad!",
"anyone wanna play melty blood after I high alch these bows?", "Anyone wanna play melty blood after I high alch these bows?",
"buru nyaaaa", "Buru nyaaaa",
"Number 15, Taverley Dungeon Black Dragons.", "Number 15, Taverley Dungeon Black Dragons.",
"House party at Rimmington! Host: @name!", "House party at Rimmington! Host: @name!",
"Spending 200m! Trade me, no junk!", "Spending 200m! Trade me, no junk!",
@ -459,19 +442,19 @@
"Nice outfit @name, does it come in children's size 12?", "Nice outfit @name, does it come in children's size 12?",
":)", ":)",
":D", ":D",
"die screaming", "Die screaming",
"Only on Tuesdays", "Only on Tuesdays",
"we stan 2009scape", "We stan 2009scape",
"There is no spoon", "There is no spoon",
"Where's the cow level?", "Where's the cow level?",
"Join 2009scape Clan Chat!", "Join 2009scape Clan Chat!",
"Join 2009scape Cc!", "Join 2009scape Cc!",
"Chop chop!", "Chop chop!",
"Runescape rox my sox!!!!!!1", "2009Scape rox my sox!!!!!!1",
"Type ::scripts for all 99s", "Type ::scripts for all 99s",
"Help I just died to Evil Chicken and I lost my stuff!", "Help I just died to Evil Chicken and I lost my stuff!",
"Can you fight Bandos in this game?", "Can you fight Bandos in this game?",
"one bad gloop", "One bad gloop",
"@name is not cute or funny", "@name is not cute or funny",
"You have committed crimes against Gielinor and her people. What say you?", "You have committed crimes against Gielinor and her people. What say you?",
"Barrows trauma", "Barrows trauma",
@ -486,7 +469,7 @@
"Praise Andrew Gower", "Praise Andrew Gower",
"Please help me I can't stop playing 2009scape", "Please help me I can't stop playing 2009scape",
"Are you ignoring me, @name?!", "Are you ignoring me, @name?!",
"i agree with this rfc can we put it in the game please", "I agree with this rfc can we put it in the game please",
"@name, we've been trying to reach you about your car's extended warranty", "@name, we've been trying to reach you about your car's extended warranty",
"Trimming armour, 25k gp", "Trimming armour, 25k gp",
"Hey why does my furniture disappear?", "Hey why does my furniture disappear?",
@ -496,21 +479,525 @@
"Shlisshalpshlaap", "Shlisshalpshlaap",
"Somebody call for an exterminator?", "Somebody call for an exterminator?",
"Decisive action. Should work.", "Decisive action. Should work.",
"R E A D Y T O R A I S E S O M E H E L L",
"Darkness overpowering.", "Darkness overpowering.",
"Got any questions about propane? Or propane accessories?", "Got any questions about propane? Or propane accessories?",
"When someone asks me if I am a god, I say Y E S!!!", "When someone asks me if I am a god, I say Y E S!!!",
"You run out of Marines?", "You run out of Marines?",
"Goliath Online",
"I'm escaping to the one place that hasn't been corrupted by Capitalism. Lunar Isle!",
"Selling wildy protection, 100k gp", "Selling wildy protection, 100k gp",
"Cant we get you on Mastermind, @name? Next contestant @name from Lumbridge. Special subject the bleedin obvious.", "Can't we get you on Mastermind, @name?",
"Oh, youre German! Im sorry, I thought there was something wrong with you.", "Listen, don't mention the war! I mentioned it once, but I think I got away with it all right.",
"Listen, dont mention the war! I mentioned it once, but I think I got away with it all right.",
"Cunnilingus and psychiatry brought us to this.", "Cunnilingus and psychiatry brought us to this.",
"Oh, poor baby. What do you want, a Brimstail's Sampler?", "Ah, the Wilderness... where dreams of riches meet a swift demise.",
"There's an old TzHarrian saying, you fuck up once, you lose two teeth.", "Who needs a quest guide? I've got the whole wiki memorized.",
"The lineup consisted simply of six hydrocoptic marzelvanes so fitted to the ambifacient lunar waneshaft that sidefumbling was prevented." "Buying GF 10k coins. Must have at least 70 Agility.",
"I swear, the goblins in Goblin Village have it out for me.",
"Why do wizards always hang out in towers? Is it a zoning thing?",
"I'm training my Construction skill. My house is gonna be lit!",
"The GE is like the stock market, but with dragon bones.",
"Why do we need a cabbage patch in Draynor? Seriously.",
"I've been mining rune essence for hours. My pickaxe hates me.",
"@name hit 99 Cooking. Time to open a gourmet restaurant in Varrock.",
"I'm convinced the @name is actually a time-traveling wizard.",
"Anyone up for a Castle Wars match? I need that decorative armor.",
"Accidentally clicked Attack on a guard. Now I'm a wanted criminal.",
"Why do we even have a Duel Arena? It's just a fancy boxing ring.",
"I've got a stack of burnt lobsters. Anyone want to buy them?",
"Greetings, @name! Looking for a quest?",
"Just got a rare drop! The RNG gods are smiling upon me!",
"Anyone need help with a boss fight? I've got my dragon dagger ready.",
"Buying feathers! Will pay top price!",
"The Lumbridge cows are my favorite training spot.",
"Who needs a teleport? I've got my magic runes stocked.",
"@name hit 99 Woodcutting. Time to chop some yews!",
"Anyone seen the Wise Old Man lately? I owe him a visit.",
"Selling lobsters! Freshly caught from Catherby.",
"Swear, the Wilderness is scarier than my nightmares.",
"Looking for a clan to join. Any takers?",
"I'm an ironman, so no trading for me!",
"Anyone up for a Castle Wars match?",
"The Grand Exchange prices are crashing. Panic sell!",
"Who else remembers the Falador Massacre?",
"I'm saving up for a party hat. Wish me luck!",
"Barrows runs are my addiction. Those crypts are spooky.",
"I'm convinced the Wise Old Man is secretly Zamorak.",
"I'm a completionist, so I'm grinding out all the achievements.",
"The music in this game is surprisingly epic.",
"Tried to trade with a tree... It didn't go well.",
"My bank is like a black hole. Items disappear forever.",
"I'm convinced the Wise Old Man is just a confused tourist.",
"My character's fashion sense? Let's just say it's 'unique.'",
"Challenged a cow to a dance-off. It won.",
"Why does the Lumbridge Guide always look so lost?",
"I'm training Agility, but my real-life agility is zero.",
"Tried to fish in the desert. Sandfish are elusive.",
"The Grand Exchange is like a chaotic stock market.",
"I'm a master at clicking 'Continue' during quests.",
"I'm convinced the chickens are plotting world domination.",
"I'm a woodcutter, but I've never seen a talking tree.",
"I'm a vegetarian, except when it comes to killing dragons.",
"Why do wizards wear pointy hats? Is it a fashion statement?",
"Challenged a guard to a staring contest. He won.",
"I'm collecting cabbage. It's a noble pursuit.",
"Accidentally set my cat on fire. It's now a firecat.",
"I'm convinced the Wise Old Man is secretly a time traveler.",
"I'm a quest completionist, but I still can't find my keys.",
"I'm convinced the ducks are spying on us.",
"I'm a pro at avoiding the Lumbridge swamp. Too many frogs.",
"Hey, can someone lend me 10k? I promise I'll pay it back... eventually.",
"Why do I always find the one square where the random event spawns?",
"I'm training Prayer by burying bones. It's like a spiritual workout.",
"The Wise Old Man's fashion sense is questionable.",
"I'm convinced the ducks are secretly plotting world domination.",
"Why do wizards wear pointy hats? Is it a dress code?",
"I'm collecting cabbage. It's a noble pursuit, really.",
"I'm a vegetarian, except when it comes to killing dragons.",
"Why does the Lumbridge Guide always look so lost?",
"Training Agility, but my real-life agility is zero.",
"I'm convinced the Wise Old Man is secretly a time traveler.",
"Tried to mine air. It's an untapped resource.",
"I'm a quest completionist, but I still can't find my keys.",
"Challenged a guard to a staring contest. He won.",
"I'm saving up for a party hat. Priorities, you know?",
"Why do goblins drop coins? Do they moonlight as accountants?",
"I'm convinced the chickens are plotting something.",
"Clicked 'Attack' on a chicken. Now I'm a poultry murderer.",
"My character's fashion sense? Let's just say it's 'unique.'",
"Do you know where I can find the entrance to the Taverley Dungeon?",
"Hey, anyone here familiar with the Barrows? I need some tips.",
"Is there a bank nearby? My inventory is overflowing with loot",
"I'm clueless about clue scrolls",
"Where's the best spot to catch sharks? I'm aiming for 99 Fishing.",
"Is there a shortcut to the Karamja Volcano?",
"Can someone explain the mechanics of the Jad fight in the Fight Caves?",
"I'm stuck on the Elemental Workshop quest. Any hints?",
"Where can I find a loom to spin flax into bowstrings?",
"What's the best gear setup for killing dragons? I want that visage drop!",
"I'm trying to unlock the fairy rings",
"How do I recharge my amulet of glory?",
"Why do goblins drop coins?",
"The Grand Exchange is like the stock market",
"My real-life agility is more like a lumbering tortoise.",
"The Wise Old Man's fashion sense is like Woahs",
"I challenged a cow to a dance off, surprisingly smooth mooves.",
"Why does the Lumbridge Guide always look lost?",
"I'm convinced the ducks in Lumbridge are plotting world domination!",
"I accidentally ate my prayer potion I'm blessed with heartburn",
"I'm a vegetarian, except when it comes to slaying dragons.",
"Why do wizards wear pointy hats? Is it a magical dress code?",
"I'm a quest completionist, but I still can't find my keys in real life.",
"I challenged a guard to a staring contest. He won.",
"I'm saving up for a party hat. Priorities, ya know?",
"What's the deal with the Wilderness?",
"I'm convinced the chickens are secretly plotting world domination!",
"Accidentally clicked 'Attack' on a guard. Now I'm on a watchlist.",
"My character's fashion sense? Let's just say it's 'unique'",
"Lobsters heal my soul",
"Trimmed armor or bust!",
"Wilderness: Where friendships go to die",
"Buying gf 10k",
"Dancing for coins at Lumbridge",
"Wearing full rune like a boss",
"Teleporting to Camelot for quests",
"Fishing for hours at Catherby",
"PKing with a rune 2h",
"World 1 Falador Park parties",
"Staking my bank at the Duel Arena",
"Dying to Elvarg's fiery breath sums up my life",
"Got the Quest cape finally on my main!",
"Wearing a party hat with pride",
"Castle Wars: Red vs Blue",
"Trading in Varrock Square",
"Barrows runs for that sweet loot",
"Spending hours in Pest Control is life",
"Killing cows for leather armor is a good start",
"Farming herbs in Ardougne can be good money",
"Clan chat drama LOL",
"Mining rune essence endlessly",
"Agility courses: A love-hate relationship",
"Dueling for honor.... and GP",
"Buying runes from Aubury is decent money",
"Chasing the Easter Bunny like a scam",
"Wearing a skillcape with pride",
"Fletching yew longbows for profit",
"Going to implings in Puro-Puro",
"Castle Wars barricade wars",
"Dropping party hats at drop parties like pennies",
"Killing lesser demons in Karamja is part of my holy conquest",
"@name lures noobs into the Wilderness",
"Farming ranarrs for cash",
"Getting lost in the Underground Pass",
"Selling coal at the Grand Exchange",
"Fighting the Kalphite Queen",
"Picking flax in Seers' Village",
"Begging for free stuff in Lumbridge",
"Smithing rune platebodies for profit",
"Logging out in Lumbridge Castle",
"Hey @name, how do I get to the Grand Exchange?",
"Veteran here! @name, what's your favorite quest?",
"@name, how do I make money fast?",
"Hey @name, what's the best combat style for bossing?",
"@name, always carry an emergency teleport!",
"New player here! @name, what's the Wilderness like?",
"Hey @name, how do I join a clan?",
"@name, prioritize Prayer levels!",
"@name, what's the best way to train Agility?",
"Hey @name, what's your favorite minigame?",
"@name, never trust a PKer in Lumbridge!",
"@name, how do I get a fire cape?",
"Hey @name, what's the fastest way to level up Magic?",
"@name, try the Barrows tunnels!",
"@name, what's the deal with Pest Control?",
"Hey @name, how do I unlock the Fairy Rings?",
"@name, remember the old random events?",
"@name, should I train Strength or Attack first?",
"Hey @name, what's your favorite skillcape?",
"@name, can't do the Fight Caves!",
"@name, how do I get a pet?",
"Hey @name, what's the best food for boss fights?",
"@name, Castle Wars or Clan Wars?",
"@name, what's a clue scroll?",
"Hey @name, how do I defeat Jad?",
"@name, use Protect from Melee at KBD!",
"@name, should I train Ranged or Magic?",
"Hey @name, what's the best way to level up Crafting?",
"@name, don't forget your anti-dragon shield!",
"@name, what's the Stronghold of Security?",
"Hey @name, how do I access the Legends' Guild?",
"@name, remember the old PvP worlds?",
"@name, how do I get a dragon defender?",
"Hey @name, what's the best way to level up Herblore?",
"@name, always carry a charged amulet of glory!",
"@name, should I train Fishing or Cooking?",
"Hey @name, how do I defeat the Chaos Elemental?",
"@name, try the TzHaar Fight Pit!",
"@name, what's the best way to level up Smithing?",
"Hey @name, what's your favorite Slayer master?",
"@name, use the Ardougne cloak teleports!",
"@name, what's the Legends' Quest about?",
"Hey @name, how do I unlock the Ancient Magicks?",
"@name, remember the old Pest Control boats?",
"@name, what's the best way to level up Construction?",
"Hey @name, what's the fastest way to level up Prayer?",
"@name, the old Duel Arena stakes!",
"@name, what's the Warriors' Guild?",
"Hey @name, how do I defeat the Kalphite Queen?",
"@name, use the fairy ring code BIP!",
"@name, should I train Attack or Defense first?",
"Hey @name, what's the best way to level up Thieving?",
"@name, don't forget your charged glory amulet!",
"@name, what's the Legends' Cape?",
"Hey @name, how do I access the Heroes' Guild?",
"@name, remember the old Pest Control void gear?",
"@name, how do I get a firemaking skillcape?",
"Buying gf 10k",
"Trimming armor for free!",
"Wanna join my clan? We're called The Mighty Cabbages'!",
"I'll meet you at the Falador Party Room!",
"Dancing for coins in Varrock Square!",
"Remember when the Wilderness was dangerous?",
"I got a rune scimitar drop from Lesser Demons!",
"Lumbridge Swamp is haunted!",
"Anyone up for Castle Wars?",
"I miss the old random events!",
"World 2 is the trading hub!",
"I'm going to train my Agility at the Gnome Stronghold!",
"I just got 99 Cooking!",
"Fishing lobsters at Catherby is life!",
"The Legends' Guild is so exclusive!",
"Who needs a quest guide? I'll figure it out!",
"I'm mining rune essence for hours!",
"Barrows armor looks sick!",
"I'm stuck in the Underground Pass!",
"The Stronghold of Security taught me about account security!",
"I'm going to farm herbs in Ardougne!",
"I'm getting my fire cape!",
"I love the music in RuneScape!",
"I'm alching my maple longbows!",
"I'm doing the Recipe for Disaster subquests!",
"I'm going to train my combat stats at the Rock Crabs!",
"I'm going for the Quest Cape!",
"I'm going to mine pure essence!",
"I'm hunting chinchompas in the Feldip Hills!",
"I'm going to train my Woodcutting at Seers' Village!",
"I'm going to fish sharks at the Fishing Guild!",
"I'm going to train my Thieving at Ardougne Knights!",
"I'm going to hunt implings in Puro-Puro!",
"I'm going to train my Hunter at the Falconry!",
"I'm smithing rune platebodies!",
"I'm going to train my Farming at the Tree Gnome Stronghold!",
"I'm going to hunt red chinchompas in the Wilderness!",
"I'm doing the Underground Pass quest!",
"I'm going to fish monkfish in Piscatoris!",
"Meet me in Varrock, @name, for an epic trade",
"@name, join my clan; we'll conquer the Wilderness together!",
"Beware the dragons, @name, they're fiercer than you think",
"Crafting runes with @name, the best mage in Gielinor",
"Fishing lobsters with @name, the sea's no match for us",
"@name, your swordsmanship at Duel Arena is unmatched!",
"Questing through dark caves, @name always leads the way",
"Share your wisdom, @name, how'd you master those spells?",
"Legends speak of @name bravery at the God Wars",
"Need more arrows, @name? I've got plenty to spare",
"Cooking's a breeze when @name around, no burnt lobsters!",
"Mining together, @name and I strike gold every time",
"@name, let's barter; your herbs for my potions?",
"Training agility with @name, leaping like graceful gazelles",
"Heard @name got the best magic beans in town",
"Fletching bows with @name, aiming for perfection",
"Smithing with @name, our anvils never cool down",
"Adventuring with @name, every quest is a thrill",
"Battling demons, @name courage inspires us all",
"Slaying dragons, @name the hero we need",
"Gathering at Falador, @name party room is legendary",
"Hunting chinchompas, @name traps are always full",
"Farming's fun with @name, our crops never fail",
"Brewing potions, @name mixtures are magical",
"Casting spells with @name, we're invincible",
"Building fires, @name flames warm the coldest nights",
"Sailing to Pest Control, @name our fearless captain",
"Trading runes, @name deals are the fairest",
"Exploring dungeons, @name the light in the darkness",
"Charging orbs with @name, our energy knows no bounds",
"Dancing in Draynor, @name moves are enchanting",
"Playing Gnomeball, @name the star player",
"Harvesting willows, @name axe swings true",
"Enchanting jewelry, @name touch turns copper to gold",
"Summoning familiars, @name spirit wolf leads the pack",
"Thieving from stalls, @name hands are lightning-fast",
"Crafting runes, @name essence never runs dry",
"Fishing at Catherby, @name catch feeds us all",
"Cooking feasts, @name dishes delight the gods",
"Mining runite, @name pickaxe strikes rich veins",
"Bartering at Grand Exchange, @name a trading master",
"Training prayer, @name piety moves mountains",
"Fighting revenants, @name valor shines bright",
"Building homes, @name construction is flawless",
"Hunting imps, @name net is always full",
"Brewing ale, @name tavern is the town's favorite",
"Casting high alchemy, @name turns junk into treasure",
"Sailing to Karamja, @name adventures are legendary",
"Forging alliances, @name charisma unites clans",
"Defeating bosses, @name name echoes in legends",
"Are you mewing @name???",
"Check out that gyatt @name",
"Bruhhhhh @name got that rizz",
"@name rizzing up the bots",
"Ironman? More like copperboy LOL",
"What that gyatt do @name",
"He's got the zoomies!",
"@name likes pickles and dipped in mayo",
"Lmaaooooooo",
"Bruh she said she loved me...",
"I caught @name rizzing a mewing teacher",
"What that mouth do bb",
"Ayo tf he say",
"Ayo",
"Ayo @name a freak lowkey",
"Ayo tf",
"@name catch me outside howbout that",
"Wasssssuuuuppppppp",
"Knock knock @name",
"Oh boy howdy do i have a surprise for you",
"Noooooo",
"What do you mean I haven't done anything wtf",
"Redrocket redrocket!!!",
"I made 20,000 crochet sock puppets for ceikry",
"Come on @name",
"Are we rading tonight @name?",
"Why would he say that",
"Penguins are technically reptiles",
"Brb smell something burning",
"Need pest control partner, you handle the portals, i will afk",
"Bruhhhh the skibiddi rizz in my gyatt makes my mewing sesh rough",
"@name jajajajaja",
"Wait, I can't raid tonight @name",
"Brb, pizza's here. Hope they ask why I'm a grown man dressed like an elf",
"Sorry, gotta go AFK. My dog just ate my gaming headset.",
"Brb, my grandma just fell down the stairs",
"Hold on, the baby's crying, aka @name",
"Oops, spilled my drink",
"Guys, I need to log off, my plants are staging a revolt for not watering them",
"AFK a sec, my neighbor's llama is in my backyard again",
"My pizza rolls are ready",
"Lost track of time, i'm late for my own wedding",
"Sorry, can't hear you over the sound of my laundry",
"Turn HDR off in windows @name",
"Www. no one cares .com",
"Hey @name www dot stfu dot com",
"Like pitching a tent in a pair of britches",
"Mad as a bag of ferrets",
"I dont think beavers built the hoover dam",
"How do beavers get the concrete for dams?",
"@name show me the way",
"@name onwards brutha",
"@name eats fried rat tails",
"@name is a rat",
"Why are there so many people farming right now",
"@name fuck the police",
"@name says the like pickles on their hotdogs",
"Fuck the guards, free woah in varrock prison",
"Ayo fuck u mean",
"Woop woop thats da sound of the beast",
"How are you the way that you are",
"She sells seashells by the sea shore",
"@name certified rat",
"@name buys skimmed milk",
"Got milk?",
"Are you JSON because i want you to get array from me",
"@name likes string manipulation",
"@name sells legos",
"JUST DO IT",
"Why are there so many motherfucking options",
"Just hit the fucking auto hide thing",
"Just play",
"Hell no this shit is fuzzy as balls",
"@name is fuzzy as balls",
"Turn your brightness up @name",
"On my pc it runs perfectly",
"I know why mine seems a little jumpy",
"Stream the window not the monitor",
"Discords a bitch",
"Why are there so many handsome people at the ge like @name",
"I'll make you squeel of fortune",
"You will get it in due time @name",
"I was one turn away",
"It do be pipe time @name",
"Sometimes i like to cover myself in vaseline and pretend i'm a slug",
"Woah is a greased pig",
"Sometimes i dig holes in my backyard and pretend i'm a carrot",
"It's pipe time @name",
"If i am not pipe timing i am programming",
"Yes i have thigh high socks, no you cannot have them",
"I scream when i wear my programming socks",
"Anyone wanna buy @name's bathwater?",
"Anyone wanna buy my used socks?",
"@name be getting bags",
"What the fuck is this",
"Hi i noticed you haven't taken a break in hours @name",
"I really am seething rn",
"I am so fucking tilted",
"Go back to your fucking frogs",
"Life is simple as frog farmer",
"A q p",
"Oooooh that's a first",
"Been a minute @name",
"Hey @name",
"Oh shit it's @name",
"Hey @name wyd today?",
"Ayo @name",
"Wyd @name",
"Wbu @name?",
"Good fuck em, that's what they get",
"Deathknight lookin rat ass mf @name",
"@name sucks slugs",
"Brb gotta take a shit",
"@name will brb went to take a shit",
"Tell me when he is coming",
"This guy is being incredibly based",
"@name is based af",
"Taking l's all day today @name",
"That sucks massive dongus",
"Ah i was about to type that",
"Where is stormwind?",
"How do i buy gold",
"@name sells gold",
"@name is a gold digger",
"Ayo @name wanna buy some frog legs?",
"Brb fucking burnt my pizza rolls",
"I swear @name if you need roll again",
"@name you are a hunter you don't need plate armor",
"Dragonriding is satisfying",
"There's an old TzHarrian saying, you fuck up once, you lose two teeth",
"FUCK",
"@name i am ready when you are",
"Anyone selling logs?",
"That is hilarious @name",
"Alright @name",
"I need to go get my quest cape",
"500 barrows runs dry",
"Back to back to back barrows items, easy game",
"@name did you know them?",
"@name sucks eggs",
"@name eats snails",
"Who is that?",
"I've gotta go in 20 minutes",
"Bonk",
"Gtg in 30 minutes",
"They left 50 minutes ago",
"I think it's just gonna be us",
"Who is that?",
"Stop following me",
"@name stop following me",
"I think @name is watching me",
"@name wouldn't let me get a hit in at clan wars",
"Clan wars and chill?",
"Quick mewing sesh",
"Don't you stickbug me",
"Get stick bugged",
"Wtf why are you a dragon",
"Fun fact, woah eats eggs whole like a snake",
"Ceikys there's a rare over there",
"Where is goldshire?",
"How long have you played @name?",
"Wanna quest?",
"TROGDORRRRRR",
"Fuck this shit i'm out",
"Wait till you get your first 99",
"How is that even possible",
"That's the max",
"@name is trying to max",
"Complesionist cape?",
"How can you increase your run speed?",
"@name where is barrows?",
"@name where are rune rocks?",
"@name where is yanille?",
"@name how long have you played for?",
"Yes these quotes were hand typed",
"Kermit was here",
"World of Warcraft died after Wrath",
"Ceikry needs to add talent trees",
"How do you get to the wilderness?",
"Anyone tryna lure @name?",
"@name tried to lure me",
"@name bots all the time",
"Anyone want chicken tendies",
"Brb foods ready",
"Brb",
"Gotta go get food",
"Anyone else from northern alaska?",
"Fishing 4 gp",
"Looking for gf",
"Anyone wanna be my discord kitten?",
"Selling discord kittens",
"@name is a discord kitten",
"Add me on discord",
"Are you in the 09discord",
"Where are you going @name?",
"Idk what i am going to cook today",
"What should i eat tonight",
"He is in the cave",
"Don't forget to save game before logging out",
"American horror story died after season 1",
"Prequels are better than the sequels",
"Disney star wars is the best star wars",
"Halo 5 sucked",
"Selling xbox live gold and 1600 microsoft points for 50k gp",
"Buying gf 25gp and a bucket",
"@name i heard evilwaffles bots",
"@name hopefully ceikry doesn't find out about evilwaffles",
"Honk honk",
"Where is the road to mordor?",
"Golem lookin ass bitch",
"@name rat looking mf",
"@name uses sand paper to wipe",
"@name said Woah is cute",
"You need 25 of 40 to do that",
"Over 1000 unique lines of dialogue",
"What should i get to eat",
"Ge be poppin today",
"Where all the woahs at",
"Ayo woahscam got that gyatt",
"That is one i haven't seen before"
], ],
"halloween": [ "halloween": [
"Trick or treat!!!", "Trick or treat!!!",
@ -521,9 +1008,9 @@
"Costume party at my P O H!! Follow me!", "Costume party at my P O H!! Follow me!",
"Trick, then!", "Trick, then!",
"Brrrainssssssss...", "Brrrainssssssss...",
"'Cause this is thriller, thriller night, and no one's gonna save you from the beast about to strike!", "'Cause this is thriller, thriller night!",
"This is Hallowe'en, this is Hallowe'en, pumpkins scream in the dead of night!", "This is Hallowe'en, this is Hallowe'en!",
"This is Hallowe'en, everybody make a scene, Trick or treat till the neighbors gonna die of fright!", "This is Hallowe'en, everybody make a scene!",
"In this town we call home, everyone hail to the pumpkin song!", "In this town we call home, everyone hail to the pumpkin song!",
"Watch out for Skeleton Jack!", "Watch out for Skeleton Jack!",
"The headless-what-man? Horse? Never heard of those.", "The headless-what-man? Horse? Never heard of those.",
@ -594,7 +1081,7 @@
"Rusty = the grinch, @name = santa", "Rusty = the grinch, @name = santa",
"@name the red nose reindeer", "@name the red nose reindeer",
"Put one foot in front of the other", "Put one foot in front of the other",
"and soon you will be walking out the doooor", "And soon you will be walking out the doooor",
"Elf on the shelf time", "Elf on the shelf time",
"@name loves pinecones", "@name loves pinecones",
"I love the smell of pinecones", "I love the smell of pinecones",
@ -693,21 +1180,21 @@
"Woah got those roofies strapped", "Woah got those roofies strapped",
"Why is my drink cloudy?", "Why is my drink cloudy?",
"@name and woah be wrestlin", "@name and woah be wrestlin",
"bekky want sum fuk?", "Bekky want sum fuk?",
"Damn @name you got an ass", "Damn @name you got an ass",
"Is that a footlong in your pants or are you happy to see me?", "Is that a footlong in your pants or are you happy to see me?",
"@name so hot i gotta change my pants", "@name so hot i gotta change my pants",
"@name is a sex god", "@name is a sex god",
"bruh we hype today", "Bruh we hype today",
"dont be silly wrap the willy @name!", "Dont be silly wrap the willy @name!",
"wrap it before you smack it @name", "Wrap it before you smack it @name",
"can i get a reeeeee @name?", "Can i get a reeeeee @name?",
"valentines day is the best day", "Valentines day is the best day",
"@name shut up before i smack you with my crusty sock", "@name shut up before i smack you with my crusty sock",
"Valentines day, more like me and my hand day smh", "Valentines day, more like me and my hand day smh",
"If you think these quotes are wild just wait @name", "If you think these quotes are wild just wait @name",
"All im saying is we have never seen @name and biden in the same room", "All im saying is we have never seen @name and biden in the same room",
"red rocket, red rocket!", "Red rocket, red rocket!",
"Woahs favourite game is red rocket", "Woahs favourite game is red rocket",
"@name sexy af today", "@name sexy af today",
"Happy Valentines day @name!!!", "Happy Valentines day @name!!!",
@ -752,4 +1239,4 @@
"@name and i are going to look for the easter bunny!!", "@name and i are going to look for the easter bunny!!",
"Hint for anyone who sees this you must dig above eagles peak" "Hint for anyone who sees this you must dig above eagles peak"
] ]
} }

File diff suppressed because it is too large Load diff

BIN
Server/data/cache/main_file_cache.dat2 (Stored with Git LFS) vendored

Binary file not shown.

BIN
Server/data/cache/main_file_cache.idx19 (Stored with Git LFS) vendored

Binary file not shown.

BIN
Server/data/cache/main_file_cache.idx255 (Stored with Git LFS) vendored

Binary file not shown.

BIN
Server/data/cache/main_file_cache.idx5 (Stored with Git LFS) vendored

Binary file not shown.

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

@ -389,31 +389,31 @@
{ {
"minAmount": 1, "minAmount": 1,
"weight": "5", "weight": "5",
"id": 10666, "id": 7334,
"maxAmount": 1 "maxAmount": 1
}, },
{ {
"minAmount": 1, "minAmount": 1,
"weight": "5", "weight": "5",
"id": 10669, "id": 7340,
"maxAmount": 1 "maxAmount": 1
}, },
{ {
"minAmount": 1, "minAmount": 1,
"weight": "5", "weight": "5",
"id": 10672, "id": 7346,
"maxAmount": 1 "maxAmount": 1
}, },
{ {
"minAmount": 1, "minAmount": 1,
"weight": "5", "weight": "5",
"id": 10675, "id": 7352,
"maxAmount": 1 "maxAmount": 1
}, },
{ {
"minAmount": 1, "minAmount": 1,
"weight": "5", "weight": "5",
"id": 10678, "id": 7358,
"maxAmount": 1 "maxAmount": 1
}, },
{ {
@ -949,7 +949,7 @@
{ {
"minAmount": 1, "minAmount": 1,
"weight": "5", "weight": "5",
"id": 10667, "id": 7336,
"maxAmount": 1 "maxAmount": 1
}, },
{ {
@ -961,7 +961,7 @@
{ {
"minAmount": 1, "minAmount": 1,
"weight": "5", "weight": "5",
"id": 10670, "id": 7342,
"maxAmount": 1 "maxAmount": 1
}, },
{ {
@ -973,7 +973,7 @@
{ {
"minAmount": 1, "minAmount": 1,
"weight": "5", "weight": "5",
"id": 10673, "id": 7348,
"maxAmount": 1 "maxAmount": 1
}, },
{ {
@ -985,7 +985,7 @@
{ {
"minAmount": 1, "minAmount": 1,
"weight": "5", "weight": "5",
"id": 10676, "id": 7354,
"maxAmount": 1 "maxAmount": 1
}, },
{ {
@ -997,7 +997,7 @@
{ {
"minAmount": 1, "minAmount": 1,
"weight": "5", "weight": "5",
"id": 10679, "id": 7360,
"maxAmount": 1 "maxAmount": 1
}, },
{ {

View file

@ -73,7 +73,7 @@
}, },
{ {
"id": "92", "id": "92",
"replaceId": "17317", "replaceId": "91",
"fence": "false", "fence": "false",
"metal": "false" "metal": "false"
}, },
@ -301,7 +301,7 @@
}, },
{ {
"id": "2025", "id": "2025",
"replaceId": "1534", "replaceId": "2026",
"fence": "false", "fence": "false",
"metal": "false" "metal": "false"
}, },
@ -312,7 +312,7 @@
"metal": "false" "metal": "false"
}, },
{ {
"id": "2036", "id": "1530",
"replaceId": "1531", "replaceId": "1531",
"fence": "false", "fence": "false",
"metal": "false" "metal": "false"
@ -925,7 +925,7 @@
}, },
{ {
"id": "3747", "id": "3747",
"replaceId": "1534", "replaceId": "3748",
"fence": "false", "fence": "false",
"metal": "false" "metal": "false"
}, },
@ -943,7 +943,7 @@
}, },
{ {
"id": "4148", "id": "4148",
"replaceId": "4248", "replaceId": "4246",
"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",
@ -1759,7 +1765,7 @@
}, },
{ {
"id": "14245", "id": "14245",
"replaceId": "14248", "replaceId": "14246",
"fence": "true", "fence": "true",
"metal": "false" "metal": "false"
}, },
@ -1984,16 +1990,14 @@
"replaceId": "28518", "replaceId": "28518",
"fence": "false", "fence": "false",
"metal": "true", "metal": "true",
"autowalk": "true", "autowalk": "true"
"questRequirement": "Icthlarin's Little Helper"
}, },
{ {
"id": "28514", "id": "28514",
"replaceId": "28518", "replaceId": "28518",
"fence": "false", "fence": "false",
"metal": "true", "metal": "true",
"autowalk": "true", "autowalk": "true"
"questRequirement": "Icthlarin's Little Helper"
}, },
{ {
"id": "21065", "id": "21065",
@ -2187,18 +2191,6 @@
"fence": "false", "fence": "false",
"metal": "false" "metal": "false"
}, },
{
"id": "24560",
"replaceId": "15515",
"fence": "true",
"metal": "false"
},
{
"id": "24561",
"replaceId": "15517",
"fence": "true",
"metal": "false"
},
{ {
"id": "24565", "id": "24565",
"replaceId": "36316", "replaceId": "36316",
@ -2689,7 +2681,7 @@
}, },
{ {
"id": "31815", "id": "31815",
"replaceId": "31816", "replaceId": "31817",
"fence": "false", "fence": "false",
"metal": "false" "metal": "false"
}, },

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
[ [
{ {
"id": "5", "id": "5",
"interfaceType": "1", "interfaceType": "8",
"walkable": "true", "walkable": "true",
"tabIndex": "-1" "tabIndex": "-1"
}, },
@ -25,7 +25,49 @@
}, },
{ {
"id": "24", "id": "24",
"interfaceType": "1", "interfaceType": "8",
"walkable": "true",
"tabIndex": "-1"
},
{
"id": "34",
"interfaceType": "8",
"walkable": "true",
"tabIndex": "-1"
},
{
"id": "38",
"interfaceType": "8",
"walkable": "true",
"tabIndex": "-1"
},
{
"id": "42",
"interfaceType": "8",
"walkable": "true",
"tabIndex": "-1"
},
{
"id": "46",
"interfaceType": "8",
"walkable": "true",
"tabIndex": "-1"
},
{
"id": "57",
"interfaceType": "8",
"walkable": "true",
"tabIndex": "-1"
},
{
"id": "58",
"interfaceType": "8",
"walkable": "true",
"tabIndex": "-1"
},
{
"id": "59",
"interfaceType": "8",
"walkable": "true", "walkable": "true",
"tabIndex": "-1" "tabIndex": "-1"
}, },
@ -53,6 +95,30 @@
"walkable": "false", "walkable": "false",
"tabIndex": "-1" "tabIndex": "-1"
}, },
{
"id": "68",
"interfaceType": "4",
"walkable": "false",
"tabIndex": "-1"
},
{
"id": "69",
"interfaceType": "4",
"walkable": "false",
"tabIndex": "-1"
},
{
"id": "70",
"interfaceType": "4",
"walkable": "false",
"tabIndex": "-1"
},
{
"id": "71",
"interfaceType": "4",
"walkable": "false",
"tabIndex": "-1"
},
{ {
"id": "74", "id": "74",
"interfaceType": "4", "interfaceType": "4",
@ -125,6 +191,12 @@
"walkable": "true", "walkable": "true",
"tabIndex": "-1" "tabIndex": "-1"
}, },
{
"id": "139",
"interfaceType": "8",
"walkable": "true",
"tabIndex": "-1"
},
{ {
"id": "140", "id": "140",
"interfaceType": "4", "interfaceType": "4",
@ -137,6 +209,12 @@
"walkable": "true", "walkable": "true",
"tabIndex": "3" "tabIndex": "3"
}, },
{
"id": "169",
"interfaceType": "8",
"walkable": "true",
"tabIndex": "-1"
},
{ {
"id": "172", "id": "172",
"interfaceType": "4", "interfaceType": "4",
@ -197,15 +275,33 @@
"walkable": "true", "walkable": "true",
"tabIndex": "6" "tabIndex": "6"
}, },
{
"id": "194",
"interfaceType": "8",
"walkable": "true",
"tabIndex": "-1"
},
{ {
"id": "195", "id": "195",
"interfaceType": "1", "interfaceType": "8",
"walkable": "true",
"tabIndex": "-1"
},
{
"id": "196",
"interfaceType": "8",
"walkable": "true", "walkable": "true",
"tabIndex": "-1" "tabIndex": "-1"
}, },
{ {
"id": "198", "id": "198",
"interfaceType": "1", "interfaceType": "8",
"walkable": "true",
"tabIndex": "-1"
},
{
"id": "209",
"interfaceType": "8",
"walkable": "true", "walkable": "true",
"tabIndex": "-1" "tabIndex": "-1"
}, },
@ -263,6 +359,12 @@
"walkable": "false", "walkable": "false",
"tabIndex": "-1" "tabIndex": "-1"
}, },
{
"id": "240",
"interfaceType": "3",
"walkable": "true",
"tabIndex": "-1"
},
{ {
"id": "241", "id": "241",
"interfaceType": "4", "interfaceType": "4",
@ -287,6 +389,36 @@
"walkable": "false", "walkable": "false",
"tabIndex": "-1" "tabIndex": "-1"
}, },
{
"id": "245",
"interfaceType": "4",
"walkable": "false",
"tabIndex": "-1"
},
{
"id": "246",
"interfaceType": "4",
"walkable": "false",
"tabIndex": "-1"
},
{
"id": "247",
"interfaceType": "4",
"walkable": "false",
"tabIndex": "-1"
},
{
"id": "248",
"interfaceType": "4",
"walkable": "false",
"tabIndex": "-1"
},
{
"id": "256",
"interfaceType": "8",
"walkable": "true",
"tabIndex": "-1"
},
{ {
"id": "259", "id": "259",
"interfaceType": "2", "interfaceType": "2",
@ -377,6 +509,12 @@
"walkable": "false", "walkable": "false",
"tabIndex": "-1" "tabIndex": "-1"
}, },
{
"id": "328",
"interfaceType": "8",
"walkable": "true",
"tabIndex": "-1"
},
{ {
"id": "336", "id": "336",
"interfaceType": "3", "interfaceType": "3",
@ -401,6 +539,12 @@
"walkable": "true", "walkable": "true",
"tabIndex": "-1" "tabIndex": "-1"
}, },
{
"id": "377",
"interfaceType": "8",
"walkable": "true",
"tabIndex": "-1"
},
{ {
"id": "380", "id": "380",
"interfaceType": "1", "interfaceType": "1",
@ -455,12 +599,24 @@
"walkable": "true", "walkable": "true",
"tabIndex": "4" "tabIndex": "4"
}, },
{
"id": "418",
"interfaceType": "8",
"walkable": "true",
"tabIndex": "-1"
},
{ {
"id": "421", "id": "421",
"interfaceType": "4", "interfaceType": "4",
"walkable": "false", "walkable": "false",
"tabIndex": "-1" "tabIndex": "-1"
}, },
{
"id": "428",
"interfaceType": "8",
"walkable": "true",
"tabIndex": "-1"
},
{ {
"id": "430", "id": "430",
"interfaceType": "2", "interfaceType": "2",
@ -479,6 +635,30 @@
"walkable": "true", "walkable": "true",
"tabIndex": "-1" "tabIndex": "-1"
}, },
{
"id": "485",
"interfaceType": "8",
"walkable": "true",
"tabIndex": "-1"
},
{
"id": "486",
"interfaceType": "8",
"walkable": "true",
"tabIndex": "-1"
},
{
"id": "487",
"interfaceType": "8",
"walkable": "true",
"tabIndex": "-1"
},
{
"id": "488",
"interfaceType": "8",
"walkable": "true",
"tabIndex": "-1"
},
{ {
"id": "498", "id": "498",
"interfaceType": "0", "interfaceType": "0",
@ -499,7 +679,7 @@
}, },
{ {
"id": "532", "id": "532",
"interfaceType": "1", "interfaceType": "8",
"walkable": "true", "walkable": "true",
"tabIndex": "-1" "tabIndex": "-1"
}, },
@ -611,9 +791,15 @@
"walkable": "false", "walkable": "false",
"tabIndex": "-1" "tabIndex": "-1"
}, },
{
"id": "653",
"interfaceType": "8",
"walkable": "true",
"tabIndex": "-1"
},
{ {
"id": "656", "id": "656",
"interfaceType": "1", "interfaceType": "8",
"walkable": "true", "walkable": "true",
"tabIndex": "-1" "tabIndex": "-1"
}, },
@ -727,7 +913,7 @@
}, },
{ {
"id": "809", "id": "809",
"interfaceType": "1", "interfaceType": "8",
"walkable": "true", "walkable": "true",
"tabIndex": "-1" "tabIndex": "-1"
} }

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,62 @@
[
{
"id": "98",
"borders": "{3072,3456,3135,3519,[3076,3456,3085,3458]~,[3082,3459,3085,3460]}"
},
{
"id": "141",
"borders": "{3072,3392,3135,3455,[3076,3452,3085,3455]}"
},
{
"id": "228",
"borders": "{2896,5446,2919,5462}"
},
{
"id": "229",
"borders": "{2921,5456,2937,5479}"
},
{
"id": "230",
"borders": "{2904,5481,2927,5497}"
},
{
"id": "231",
"borders": "{2886,5464,2902,5487}"
},
{
"id": "386",
"borders": "{2820,5312,2849,5369}-{2849,5349,2880,5374}"
},
{
"id": "391",
"borders": "{2879,5340,2944,5366}-{2909,5316,2944,5340}"
},
{
"id": "399",
"borders": "{2816,5248,2943,5375,[2823,5250,2844,5310]~,[2844,5250,2878,5280]~,[2879,5340,2944,5366]~,[2909,5316,2944,5340]~,[2820,5312,2849,5369]~,[2849,5349,2880,5374]~,[2885,5253,2934,5278]~,[2913,5278,2937,5306]}"
},
{
"id": "404",
"borders": "{2823,5250,2844,5310}-{2844,5250,2878,5276}"
},
{
"id": "408",
"borders": "{2885,5253,2934,5278}-{2913,5278,2937,5306}"
},
{
"id": "459",
"borders": "{3137,5442,3192,5564}-{3193,5442,3198,5472}-{3193,5507,3198,5564}"
},
{
"id": "467",
"borders": "{3199,5441,3262,5564}-{3193,5482,3198,5497}"
},
{
"id": "488",
"borders": "{3263,5441,3327,5566}"
},
{
"id": "492",
"borders": "{3076,3452,3085,3460,[3076,3459,3081,3460]}"
}
]

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -968,7 +968,7 @@
"ids": "573" "ids": "573"
}, },
{ {
"examine": "A carving of a figure from the history of RuneScape.", "examine": "A carving of a figure from the history of 2009Scape.",
"ids": "574,575,576,577,578" "ids": "574,575,576,577,578"
}, },
{ {
@ -1753,7 +1753,7 @@
}, },
{ {
"examine": "Danger!", "examine": "Danger!",
"ids": "1032,5127,29373" "ids": "1032,5127"
}, },
{ {
"examine": "This tells you which way is which.", "examine": "This tells you which way is which.",
@ -2148,7 +2148,7 @@
"ids": "1231" "ids": "1231"
}, },
{ {
"examine": "One of the most common trees in RuneScape.", "examine": "One of the most common trees in 2009Scape.",
"ids": "1276" "ids": "1276"
}, },
{ {
@ -3584,7 +3584,7 @@
"ids": "2375" "ids": "2375"
}, },
{ {
"examine": "Soil", "examine": "Soil. Dug up!",
"ids": "2376,2377,2378" "ids": "2376,2377,2378"
}, },
{ {
@ -4964,7 +4964,7 @@
"ids": "3032" "ids": "3032"
}, },
{ {
"examine": "One of the most common trees in RuneScape.", "examine": "One of the most common trees in 2009Scape.",
"ids": "3033,3034,3035,3036" "ids": "3033,3034,3035,3036"
}, },
{ {
@ -6384,12 +6384,12 @@
"ids": "4131" "ids": "4131"
}, },
{ {
"examine": "These doors look very ominous. A sign says 'To the tombs'.", "examine": "This tells you which way is which.",
"ids": "4132,4133" "ids": "4132,4133,4134,4135"
}, },
{ {
"examine": "Large doors set into the hillside.", "examine": "These doors look very ominous. A sign says 'To the tombs'.",
"ids": "4134,4135,4136,4137" "ids": "4136,4137"
}, },
{ {
"examine": "Items are for sale here.", "examine": "Items are for sale here.",
@ -8592,7 +8592,7 @@
"ids": "5789,5790" "ids": "5789,5790"
}, },
{ {
"examine": "A carving of a figure from the history of RuneScape.", "examine": "A carving of a figure from the history of 2009Scape.",
"ids": "5791,36749,36751" "ids": "5791,36749,36751"
}, },
{ {
@ -12788,7 +12788,7 @@
"ids": "8972" "ids": "8972"
}, },
{ {
"examine": "One of the most common trees in RuneScape.", "examine": "One of the most common trees in 2009Scape.",
"ids": "8973" "ids": "8973"
}, },
{ {
@ -14100,7 +14100,7 @@
"ids": "10080" "ids": "10080"
}, },
{ {
"examine": "One of the most common trees in RuneScape.", "examine": "One of the most common trees in 2009Scape.",
"ids": "10081" "ids": "10081"
}, },
{ {
@ -15964,7 +15964,7 @@
"ids": "11354,11355" "ids": "11354,11355"
}, },
{ {
"examine": "A gateway back to RuneScape.", "examine": "A gateway back to 2009Scape.",
"ids": "11356" "ids": "11356"
}, },
{ {
@ -16324,7 +16324,7 @@
"ids": "11629" "ids": "11629"
}, },
{ {
"examine": "South to Falador :: West to Taverley :: East to Varrock.", "examine": "This tells you which way is which.",
"ids": "11630,11631,11632,11633" "ids": "11630,11631,11632,11633"
}, },
{ {
@ -16564,7 +16564,7 @@
"ids": "11759" "ids": "11759"
}, },
{ {
"examine": "A carving of a figure from the history of RuneScape.", "examine": "A carving of a figure from the history of 2009Scape.",
"ids": "11761" "ids": "11761"
}, },
{ {
@ -16741,7 +16741,7 @@
}, },
{ {
"examine": "Better not eat them!", "examine": "Better not eat them!",
"ids": "12003" "ids": "12003,12128"
}, },
{ {
"examine": "It's going to be a tight squeeze!", "examine": "It's going to be a tight squeeze!",
@ -16881,7 +16881,7 @@
}, },
{ {
"examine": "A wall jutting out into the path.", "examine": "A wall jutting out into the path.",
"ids": "12127,12128,12129,12130" "ids": "12127,12129,12130"
}, },
{ {
"examine": "Spooky.", "examine": "Spooky.",
@ -18728,7 +18728,7 @@
"ids": "13409,13410" "ids": "13409,13410"
}, },
{ {
"examine": "One of the most common trees in RuneScape.", "examine": "One of the most common trees in 2009Scape.",
"ids": "13411,13412" "ids": "13411,13412"
}, },
{ {
@ -18996,11 +18996,11 @@
"ids": "13525" "ids": "13525"
}, },
{ {
"examine": "A map of RuneScape.", "examine": "A map of 2009Scape.",
"ids": "13526" "ids": "13526"
}, },
{ {
"examine": "A map of RuneScape including major cave systems.", "examine": "A map of 2009Scape including major cave systems.",
"ids": "13527" "ids": "13527"
}, },
{ {
@ -20007,6 +20007,46 @@
"examine": "Why do I never take time to look at the grass?", "examine": "Why do I never take time to look at the grass?",
"ids": "14003" "ids": "14003"
}, },
{
"examine": "Well, I have the logs in place, now to get something to boil.",
"ids": "14005"
},
{
"examine": "Covered in a thick layer of grease.",
"ids": "14006"
},
{
"examine": "I'm glad this isn't for dinner.",
"ids": "14007"
},
{
"examine": "This smells so very, very bad...",
"ids": "14008"
},
{
"examine": "It seems to have all boiled away.",
"ids": "14009"
},
{
"examine": "Stop examining signs! You're in the Wilderness now!",
"ids": "14503"
},
{
"examine": "Danger, Wilderness up ahead. Last chance to turn back...",
"ids": "14504"
},
{
"examine": "Danger, Wilderness up ahead. Watch out for the Beast!",
"ids": "14505"
},
{
"examine": "Danger, Wilderness up ahead. Beware of stray magma.",
"ids": "14506"
},
{
"examine": "Danger, Wilderness up ahead. Almost certain death!",
"ids": "14507"
},
{ {
"examine": "Home sweet home?", "examine": "Home sweet home?",
"ids": "15477" "ids": "15477"
@ -20015,14 +20055,38 @@
"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"
}, },
{
"examine": "Danger - Possibly deadly creatures below!",
"ids": "16083,16151,16117"
},
{
"examine": "Large urn.",
"ids": "17362"
},
{ {
"examine": "A large fish.", "examine": "A large fish.",
"ids": "18482" "ids": "18482"
}, },
{
"examine": "A sign on a cactus.",
"ids": "18876"
},
{
"examine": "Dead and half-buried.",
"ids": "19996"
},
{
"examine": "Dead animal head. Lovely.",
"ids": "19997"
},
{ {
"examine": "Might be worth opening?", "examine": "Might be worth opening?",
"ids": "21299" "ids": "21299"
@ -20123,14 +20187,34 @@
"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"
}, },
{
"examine": "An interesting sign.",
"ids": "31297,31298,31299,31300,31301"
},
{ {
"examine": "I wonder what this spooky contains.", "examine": "I wonder what this spooky contains.",
"ids": "37051" "ids": "37051"
}, },
{
"examine": "The mine has collapsed.",
"ids": "37634"
},
{ {
"examine": "It really was this big!", "examine": "It really was this big!",
"ids": "40043" "ids": "40043"
@ -20195,6 +20279,14 @@
"examine": "A wooden crate.", "examine": "A wooden crate.",
"ids": "15031" "ids": "15031"
}, },
{
"examine": "A sealed barrel with a warning sign on it.",
"ids": "17296"
},
{
"examine": "A barrel with a warning sign on it.",
"ids": "17297"
},
{ {
"examine": "A beautiful landscape.", "examine": "A beautiful landscape.",
"ids": "24184" "ids": "24184"
@ -20275,6 +20367,10 @@
"examine": "Technically a bed.", "examine": "Technically a bed.",
"ids": "32031" "ids": "32031"
}, },
{
"examine": "Now that's what I call slimline!",
"ids": "32072"
},
{ {
"examine": "A really bad portrait of the King.", "examine": "A really bad portrait of the King.",
"ids": "32326" "ids": "32326"
@ -20293,7 +20389,7 @@
}, },
{ {
"examine": "A wooden barrel for storage.", "examine": "A wooden barrel for storage.",
"ids": "31136,36798" "ids": "17308,31136,36798"
}, },
{ {
"examine": "A home for baby creatures.", "examine": "A home for baby creatures.",
@ -20519,10 +20615,6 @@
"examine": "Popular on sandy beaches where fruity cocktails may be found.", "examine": "Popular on sandy beaches where fruity cocktails may be found.",
"ids": "18856" "ids": "18856"
}, },
{
"examine": "Stop examining signs! You're in the Wilderness now!",
"ids": "14503"
},
{ {
"examine": "Looks like part of the entrance is blocked by rubble.", "examine": "Looks like part of the entrance is blocked by rubble.",
"ids": "15767" "ids": "15767"
@ -20603,6 +20695,10 @@
"examine": "Keeps the puppies out of trouble.", "examine": "Keeps the puppies out of trouble.",
"ids": "28341" "ids": "28341"
}, },
{
"examine": "Warning! Danger of death.",
"ids": "29373"
},
{ {
"examine": "There are some toolboxes on this table.", "examine": "There are some toolboxes on this table.",
"ids": "36573,36580" "ids": "36573,36580"

View file

@ -15,7 +15,7 @@
"weapon_type": "1", "weapon_type": "1",
"animation": "4230", "animation": "4230",
"drop_ammo": "true", "drop_ammo": "true",
"ammunition": "877,878,6061,6062,879,9236,13280" "ammunition": "877,878,6061,6062,879,9236"
}, },
{ {
"itemId": "800", "itemId": "800",
@ -294,7 +294,7 @@
"weapon_type": "1", "weapon_type": "1",
"animation": "4230", "animation": "4230",
"drop_ammo": "true", "drop_ammo": "true",
"ammunition": "877,878,6061,6062,879,9236,13280" "ammunition": "877,878,6061,6062,879,9236"
}, },
{ {
"itemId": "839", "itemId": "839",
@ -1095,7 +1095,7 @@
"weapon_type": "1", "weapon_type": "1",
"animation": "4230", "animation": "4230",
"drop_ammo": "true", "drop_ammo": "true",
"ammunition": "8882,877,878,6061,6062,879,9236" "ammunition": "8882,877,878,6061,6062,879,9236,9139,9286,9293,9300,9140,9287,9294,9237,9145,9301,9292,9299,9306,9335,880,9238"
}, },
{ {
"itemId": "9174", "itemId": "9174",
@ -1104,7 +1104,7 @@
"weapon_type": "1", "weapon_type": "1",
"animation": "4230", "animation": "4230",
"drop_ammo": "true", "drop_ammo": "true",
"ammunition": "877,878,6061,6062,879,9236,13280" "ammunition": "877,878,6061,6062,879,9236"
}, },
{ {
"itemId": "9176", "itemId": "9176",
@ -1113,7 +1113,7 @@
"weapon_type": "1", "weapon_type": "1",
"animation": "4230", "animation": "4230",
"drop_ammo": "true", "drop_ammo": "true",
"ammunition": "877,878,6061,6062,9140,879,9139,9236,13280" "ammunition": "877,878,6061,6062,879,9139,9236,9286,9293,9300,9335,9237"
}, },
{ {
"itemId": "9177", "itemId": "9177",
@ -1122,7 +1122,7 @@
"weapon_type": "1", "weapon_type": "1",
"animation": "4230", "animation": "4230",
"drop_ammo": "true", "drop_ammo": "true",
"ammunition": "877,878,6061,6062,879,9236,9139,9140,9287,9294,9301,880,9238,9145,13280" "ammunition": "877,878,6061,6062,879,9236,9139,9140,9287,9294,9301,880,9238,9145,9286,9293,9300,9292,9299,9306,9335,9237"
}, },
{ {
"itemId": "9179", "itemId": "9179",
@ -1131,7 +1131,7 @@
"weapon_type": "1", "weapon_type": "1",
"animation": "4230", "animation": "4230",
"drop_ammo": "true", "drop_ammo": "true",
"ammunition": "877,878,6061,6062,879,9139,9140,9236,9141,9288,9295,9302,9336,9239,9145,13280" "ammunition": "877,878,6061,6062,879,9139,9140,9236,9141,9288,9295,9302,9336,9239,9145,9286,9293,9300,9287,9294,9301,9292,9299,9306,9335,9237,880,9238"
}, },
{ {
"itemId": "9181", "itemId": "9181",
@ -1140,7 +1140,7 @@
"weapon_type": "1", "weapon_type": "1",
"animation": "4230", "animation": "4230",
"drop_ammo": "true", "drop_ammo": "true",
"ammunition": "877,878,6061,6062,879,9236,9141,9288,9295,9302,9336,9239,13083,13084,13085,13086,9142,9289,9296,9303,9337,9240,9338,9145,9139,9140,9241,13280" "ammunition": "877,878,6061,6062,879,9236,9141,9288,9295,9302,9336,9239,13083,13084,13085,13086,9142,9289,9296,9303,9337,9240,9338,9145,9139,9140,9241,9286,9293,9300,9140,9287,9294,9301,9292,9299,9306,9335,9237,880,9238,13083,13084,13085,13086"
}, },
{ {
"itemId": "9183", "itemId": "9183",
@ -1149,7 +1149,7 @@
"weapon_type": "1", "weapon_type": "1",
"animation": "4230", "animation": "4230",
"drop_ammo": "true", "drop_ammo": "true",
"ammunition": "877,878,6061,6062,879,9236,9139,9141,9288,9295,9302,9336,9239,13083,13084,13085,13086,9142,9289,9296,9303,9337,9240,9338,9241,9145,9143,9290,9297,9304,9339,9242,9340,9243,13280" "ammunition": "877,878,6061,6062,879,9236,9139,9141,9288,9295,9302,9336,9239,13083,13084,13085,13086,9142,9289,9296,9303,9337,9240,9338,9241,9145,9143,9290,9297,9304,9339,9242,9340,9243,9286,9293,9300,9140,9287,9294,9301,9292,9299,9306,9335,9237,880,9238,13083,13084,13085,13086"
}, },
{ {
"itemId": "9185", "itemId": "9185",
@ -1158,7 +1158,7 @@
"weapon_type": "1", "weapon_type": "1",
"animation": "4230", "animation": "4230",
"drop_ammo": "true", "drop_ammo": "true",
"ammunition": "877,878,6061,6062,879,9236,9139,9141,9288,9295,9302,9336,9239,9236,9237,9238,9239,9240,9241,9242,9243,9244,9245,9145,13083,13084,13085,13086,9142,9289,9296,9303,9337,9240,9338,9241,9143,9290,9297,9304,9339,9242,9340,9243,9144,9291,9298,9305,9341,9244,9342,9245,9140,13280" "ammunition": "877,878,6061,6062,879,9236,9139,9141,9288,9295,9302,9336,9239,9236,9237,9238,9239,9240,9241,9242,9243,9244,9245,9145,13083,13084,13085,13086,9142,9289,9296,9303,9337,9240,9338,9241,9143,9290,9297,9304,9339,9242,9340,9243,9144,9291,9298,9305,9341,9244,9342,9245,9140,13280,9139,9286,9293,9300,9287,9294,9301,9292,9299,9306,9335,9237,880,13083,13084,13085,13086"
}, },
{ {
"itemId": "9705", "itemId": "9705",
@ -1293,7 +1293,7 @@
"weapon_type": "1", "weapon_type": "1",
"animation": "4230", "animation": "4230",
"drop_ammo": "true", "drop_ammo": "true",
"ammunition": "877,878,6061,6062,879,9236,9141,9288,9295,9302,9140,9336,9239,13083,13084,13085,13086,13280" "ammunition": "877,878,6061,6062,879,9139,9140,9236,9141,9288,9295,9302,9336,9239,9145,9286,9293,9300,9287,9294,9301,9292,9299,9306,9335,9237,880,9238,13083,13084,13085,13086"
}, },
{ {
"itemId": "13405", "itemId": "13405",

View file

@ -45,22 +45,13 @@
"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": "{1931,30,100}-{1935,30,100}-{1735,10,100}-{1925,10,100}-{1923,10,100}-{1887,10,100}-{590,10,100}-{1755,10,100}-{2347,10,100}-{550,10,100}-{9003,10,100}"
}, },
{ {
"npcs": "590", "npcs": "590,591",
"high_alch": "0", "high_alch": "0",
"currency": "995", "currency": "995",
"general_store": "true", "general_store": "true",
"id": "6", "id": "6",
"title": "Aemad's Adventuring Supplies Store", "title": "Aemad's Adventuring Supplies",
"stock": "{227,300,100}-{1265,10,100}-{1349,10,100}-{2142,10,100}-{590,10,100}-{1759,100,100}-{882,1000,100}-{954,10,100}-{970,10,100}-{946,10,100}-{1935,10,100}" "stock": "{227,10,100}-{1265,10,100}-{1349,10,100}-{2142,10,100}-{590,10,100}-{1759,100,100}-{882,1000,100}-{954,10,100}-{970,10,100}-{946,10,100}-{1935,10,100}"
},
{
"npcs": "591",
"high_alch": "0",
"currency": "995",
"general_store": "true",
"id": "7",
"title": "Kortan General Store",
"stock": "{1931,30,100}-{1935,30,100}-{1735,10,100}-{1925,10,100}-{1923,10,100}-{1887,10,100}-{590,10,100}-{1755,10,100}-{2347,10,100}-{550,10,100}-{9003,10,100}"
}, },
{ {
"npcs": "971", "npcs": "971",
@ -186,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",
@ -573,7 +564,7 @@
"general_store": "false", "general_store": "false",
"id": "65", "id": "65",
"title": "Dodgy Mikes Second-hand Clothing", "title": "Dodgy Mikes Second-hand Clothing",
"stock": "{7114,10,100}" "stock": "{7114,10,100}-{7122,10,100}-{7128,10,100}-{7134,10,100}-{7110,10,100}-{7126,10,100}-{7132,10,100}-{7138,10,100}-{7116,10,100}-{7124,10,100}-{7130,10,100}-{7112,10,100}-{7136,10,100}"
}, },
{ {
"npcs": "2161", "npcs": "2161",
@ -1266,7 +1257,7 @@
"general_store": "false", "general_store": "false",
"id": "143", "id": "143",
"title": "Fortunato's Fine Wine", "title": "Fortunato's Fine Wine",
"stock": "{1993,10,100}-{1937,10,100}-{7919,10,100}-{1935,10,100}" "stock": "{1993,10,100}-{7810,10,100}-{7919,10,100}-{1935,10,100}"
}, },
{ {
"npcs": "558", "npcs": "558",
@ -2186,5 +2177,23 @@
"id": "255", "id": "255",
"title": "Castle Wars Ticket Exchange", "title": "Castle Wars Ticket Exchange",
"stock": "{4068,1,100}-{4069,1,100}-{4070,1,100}-{4071,1,100}-{4072,1,100}-{4503,1,100}-{4504,1,100}-{4505,1,100}-{4506,1,100}-{4507,1,100}-{4508,1,100}-{4509,1,100}-{4510,1,100}-{4511,1,100}-{4512,1,100}-{4513,1,100}-{4514,1,100}-{4515,1,100}-{4516,1,100}" "stock": "{4068,1,100}-{4069,1,100}-{4070,1,100}-{4071,1,100}-{4072,1,100}-{4503,1,100}-{4504,1,100}-{4505,1,100}-{4506,1,100}-{4507,1,100}-{4508,1,100}-{4509,1,100}-{4510,1,100}-{4511,1,100}-{4512,1,100}-{4513,1,100}-{4514,1,100}-{4515,1,100}-{4516,1,100}"
},
{
"npcs": "5111",
"high_alch": "0",
"currency": "995",
"general_store": "false",
"id": "256",
"title": "Leon's Prototype Crossbow",
"stock": "{10156,2,100}"
},
{
"npcs": "2039",
"high_alch": "0",
"currency": "995",
"general_store": "false",
"id": "256",
"title": "Uglug's Stuffsies",
"stock": "{4844,100,10}-{10927,0,100}-{2862,100,100}-{1777,10,200}-{2876,0,500}-{2878,10,100}-{4850,0,100}-{946,5,100}-{4773,0,1000}-{4778,0,1000}-{4783,0,1000}-{4788,0,1500}-{4793,0,2000}-{4798,0,3000}-{4803,0,4000}-{4827,0,2000}"
} }
] ]

File diff suppressed because it is too large Load diff

View file

@ -30,11 +30,6 @@ public enum BossKillCounter {
8355, 8356, 8357, 8358, 8359, 8360, 8355, 8356, 8357, 8358, 8359, 8360,
8361, 8362, 8363, 8364, 8365, 8366, 8361, 8362, 8363, 8364, 8365, 8366,
}, "Tormented demon", -1), }, "Tormented demon", -1),
CALLISTO(new int[] { 8610 }, "Callisto", 14658),
SCORPIA(new int[] { 8611 }, "Scorpia", 14661),
VENENATIS(new int[] { 8612 }, "Venenatis", 14657),
VETION(new int[] { 8613 }, "Vet'ion", 14659),
KRAKEN(new int[] { 8614 }, "Cave Kraken", 14651),
; ;

View file

@ -2,8 +2,11 @@ package content.data
import content.global.skill.magic.TeleportMethod import content.global.skill.magic.TeleportMethod
import content.global.skill.slayer.SlayerManager.Companion.getInstance import content.global.skill.slayer.SlayerManager.Companion.getInstance
import content.global.skill.slayer.SlayerUtils
import core.ServerConstants
import core.api.* import core.api.*
import core.game.event.TeleportEvent import core.game.event.TeleportEvent
import core.game.interaction.QueueStrength
import core.game.node.entity.player.Player import core.game.node.entity.player.Player
import core.game.node.entity.player.link.TeleportManager import core.game.node.entity.player.link.TeleportManager
import core.game.node.item.Item import core.game.node.item.Item
@ -17,8 +20,8 @@ import org.rs09.consts.Sounds
import java.util.* import java.util.*
/** /**
* Represents an enchanted jewellery. * Represents a piece of enchanted jewellery.
* @author Vexia & downthecrop * @author Vexia, downthecrop, Player Name
*/ */
enum class EnchantedJewellery( enum class EnchantedJewellery(
@ -186,6 +189,13 @@ enum class EnchantedJewellery(
Items.RING_OF_WEALTH2_14642, Items.RING_OF_WEALTH2_14642,
Items.RING_OF_WEALTH1_14640, Items.RING_OF_WEALTH1_14640,
Items.RING_OF_WEALTH_14638 Items.RING_OF_WEALTH_14638
),
RING_OF_LIFE(arrayOf<String>(),
arrayOf(
Location.create(ServerConstants.HOME_LOCATION)
),
true,
Items.RING_OF_LIFE_2570
); );
val isCrumble: Boolean = crumble val isCrumble: Boolean = crumble
@ -199,7 +209,7 @@ enum class EnchantedJewellery(
constructor(options: Array<String>, locations: Array<Location>, vararg ids: Int) : this(options, locations, false, *ids) constructor(options: Array<String>, locations: Array<Location>, vararg ids: Int) : this(options, locations, false, *ids)
/** /**
* Method used to teleport the player to the desired location. * Method used when the player "Use"s the jewellery piece.
* @param player the player. * @param player the player.
* @param item the used jewellery item. * @param item the used jewellery item.
* @param buttonID the button id. * @param buttonID the button id.
@ -212,39 +222,52 @@ enum class EnchantedJewellery(
} }
return return
} }
attemptTeleport(player, item, buttonID, isEquipped)
}
/**
* Method used to actually teleport the player to the desired location.
* @param player the player.
* @param item the used jewellery item.
* @param buttonID the button id.
* @param isEquipped If the player is operating.
*/
fun attemptTeleport(player: Player, item: Item, buttonID: Int, isEquipped: Boolean): Boolean {
val itemIndex = getItemIndex(item) val itemIndex = getItemIndex(item)
val nextJewellery = Item(getNext(itemIndex)) val nextJewellery = Item(getNext(itemIndex))
if (canTeleport(player, nextJewellery)) { if (!canTeleport(player, nextJewellery)) {
Pulser.submit(object : Pulse(0) { return false
private var count = 0
private var location = getLocation(buttonID)
override fun pulse(): Boolean {
when (count) {
0 -> {
lock(player,4)
visualize(player, ANIMATION, GRAPHICS)
playGlobalAudio(player.location, Sounds.TELEPORT_ALL_200)
player.impactHandler.disabledTicks = 4
closeInterface(player)
}
3 -> {
teleport(player,location)
resetAnimator(player)
if (isLastItemIndex(itemIndex)) {
if (isCrumble) crumbleJewellery(player, item, isEquipped)
} else {
replaceJewellery(player, item, nextJewellery, isEquipped)
}
unlock(player)
player.dispatch(TeleportEvent(TeleportManager.TeleportType.NORMAL, TeleportMethod.JEWELRY, item, location))
return true
}
}
count += 1
return false
}
})
} }
Pulser.submit(object : Pulse(0) {
private var count = 0
private var location = getLocation(buttonID)
override fun pulse(): Boolean {
when (count) {
0 -> {
lock(player,4)
visualize(player, ANIMATION, GRAPHICS)
playGlobalAudio(player.location, Sounds.TELEPORT_ALL_200)
player.impactHandler.disabledTicks = 4
closeInterface(player)
}
3 -> {
teleport(player,location)
resetAnimator(player)
if (isLastItemIndex(itemIndex)) {
if (isCrumble) crumbleJewellery(player, item, isEquipped)
} else {
replaceJewellery(player, item, nextJewellery, isEquipped)
}
unlock(player)
player.dispatch(TeleportEvent(TeleportManager.TeleportType.NORMAL, TeleportMethod.JEWELRY, item, location))
return true
}
}
count += 1
return false
}
})
return true
} }
private fun replaceJewellery(player: Player, item: Item, nextJewellery: Item, isEquipped: Boolean) { private fun replaceJewellery(player: Player, item: Item, nextJewellery: Item, isEquipped: Boolean) {
@ -262,8 +285,11 @@ enum class EnchantedJewellery(
removeItem(player, item) removeItem(player, item)
} }
if (isSlayerRing(item)) { if (isSlayerRing(item)) {
addItem(player, Items.ENCHANTED_GEM_4155) queueScript(player, 1, QueueStrength.SOFT) {
sendMessage(player, "Your Ring of Slaying reverts back into a regular enchanted gem.") addItemOrDrop(player, Items.ENCHANTED_GEM_4155)
sendMessage(player, "Your Ring of Slaying reverts back into a regular enchanted gem.")
return@queueScript stopExecuting(player)
}
} }
} }
@ -275,11 +301,11 @@ enum class EnchantedJewellery(
val slayerManager = getInstance(player) val slayerManager = getInstance(player)
if (!slayerManager.hasTask()) { if (!slayerManager.hasTask()) {
sendNPCDialogue(player, slayerManager.master!!.npc, "You need something new to hunt. Come and " + sendNPCDialogue(player, slayerManager.master!!.npc, "You need something new to hunt. Come and " +
"see me When you can and I'll give you a new task.", core.game.dialogue.FacialExpression.HALF_GUILTY) "see me when you can and I'll give you a new task.", core.game.dialogue.FacialExpression.HALF_GUILTY)
return return
} }
sendNPCDialogue(player, slayerManager.master!!.npc, "You're currently " + sendNPCDialogue(player, slayerManager.master!!.npc, "You're currently " +
"assigned to kill ${getSlayerTaskName(player).lowercase(Locale.getDefault())}'s; " + "assigned to kill ${SlayerUtils.pluralise(getSlayerTaskName(player))} " +
"only ${getSlayerTaskKillsRemaining(player)} more to go.", core.game.dialogue.FacialExpression.FRIENDLY) "only ${getSlayerTaskKillsRemaining(player)} more to go.", core.game.dialogue.FacialExpression.FRIENDLY)
// Slayer tracker UI // Slayer tracker UI
setVarp(player, 2502, slayerManager.flags.taskFlags shr 4) setVarp(player, 2502, slayerManager.flags.taskFlags shr 4)

View file

@ -100,7 +100,7 @@ public enum GodBook {
* @param page the page. * @param page the page.
*/ */
public void insertPage(Player player, Item book, Item page) { public void insertPage(Player player, Item book, Item page) {
if (!hasRequirement(player, "Horror from the Deep")) if (!hasRequirement(player, Quests.HORROR_FROM_THE_DEEP))
return; return;
if (hasPage(player, book, page)) { if (hasPage(player, book, page)) {
player.sendMessage("The book already has that page."); player.sendMessage("The book already has that page.");

View file

@ -0,0 +1,158 @@
package content.data
enum class Quests(val questName: String) {
MYTHS_OF_THE_WHITE_LANDS("Myths of the White Lands"),
BLACK_KNIGHTS_FORTRESS("Black Knights' Fortress"),
COOKS_ASSISTANT("Cook's Assistant"),
DEMON_SLAYER("Demon Slayer"),
DORICS_QUEST("Doric's Quest"),
DRAGON_SLAYER("Dragon Slayer"),
ERNEST_THE_CHICKEN("Ernest the Chicken"),
GOBLIN_DIPLOMACY("Goblin Diplomacy"),
IMP_CATCHER("Imp Catcher"),
THE_KNIGHTS_SWORD("The Knight's Sword"),
PIRATES_TREASURE("Pirate's Treasure"),
PRINCE_ALI_RESCUE("Prince Ali Rescue"),
THE_RESTLESS_GHOST("The Restless Ghost"),
ROMEO_JULIET("Romeo & Juliet"),
RUNE_MYSTERIES("Rune Mysteries"),
SHEEP_SHEARER("Sheep Shearer"),
SHIELD_OF_ARRAV("Shield of Arrav"),
VAMPIRE_SLAYER("Vampire Slayer"),
WITCHS_POTION("Witch's Potion"),
ANIMAL_MAGNETISM("Animal Magnetism"),
BETWEEN_A_ROCK("Between a Rock..."),
BIG_CHOMPY_BIRD_HUNTING("Big Chompy Bird Hunting"),
BIOHAZARD("Biohazard"),
CABIN_FEVER("Cabin Fever"),
CLOCK_TOWER("Clock Tower"),
CONTACT("Contact!"),
ZOGRE_FLESH_EATERS("Zogre Flesh Eaters"),
CREATURE_OF_FENKENSTRAIN("Creature of Fenkenstrain"),
DARKNESS_OF_HALLOWVALE("Darkness of Hallowvale"),
DEATH_TO_THE_DORGESHUUN("Death to the Dorgeshuun"),
DEATH_PLATEAU("Death Plateau"),
DESERT_TREASURE("Desert Treasure"),
DEVIOUS_MINDS("Devious Minds"),
THE_DIG_SITE("The Dig Site"),
DRUIDIC_RITUAL("Druidic Ritual"),
DWARF_CANNON("Dwarf Cannon"),
EADGARS_RUSE("Eadgar's Ruse"),
EAGLES_PEAK("Eagles' Peak"),
ELEMENTAL_WORKSHOP_I("Elemental Workshop I"),
ELEMENTAL_WORKSHOP_II("Elemental Workshop II"),
ENAKHRAS_LAMENT("Enakhra's Lament"),
ENLIGHTENED_JOURNEY("Enlightened Journey"),
THE_EYES_OF_GLOUPHRIE("The Eyes of Glouphrie"),
FAIRYTALE_I_GROWING_PAINS("Fairytale I - Growing Pains"),
FAIRYTALE_II_CURE_A_QUEEN("Fairytale II - Cure a Queen"),
FAMILY_CREST("Family Crest"),
THE_FEUD("The Feud"),
FIGHT_ARENA("Fight Arena"),
FISHING_CONTEST("Fishing Contest"),
FORGETTABLE_TALE("Forgettable Tale..."),
THE_FREMENNIK_TRIALS("The Fremennik Trials"),
WATERFALL_QUEST("Waterfall Quest"),
GARDEN_OF_TRANQUILITY("Garden of Tranquility"),
GERTRUDES_CAT("Gertrude's Cat"),
GHOSTS_AHOY("Ghosts Ahoy"),
THE_GIANT_DWARF("The Giant Dwarf"),
THE_GOLEM("The Golem"),
THE_GRAND_TREE("The Grand Tree"),
THE_HAND_IN_THE_SAND("The Hand in the Sand"),
HAUNTED_MINE("Haunted Mine"),
HAZEEL_CULT("Hazeel Cult"),
HEROES_QUEST("Heroes' Quest"),
HOLY_GRAIL("Holy Grail"),
HORROR_FROM_THE_DEEP("Horror from the Deep"),
ICTHLARINS_LITTLE_HELPER("Icthlarin's Little Helper"),
IN_AID_OF_THE_MYREQUE("In Aid of the Myreque"),
IN_SEARCH_OF_THE_MYREQUE("In Search of the Myreque"),
JUNGLE_POTION("Jungle Potion"),
LEGENDS_QUEST("Legend's Quest"),
LOST_CITY("Lost City"),
THE_LOST_TRIBE("The Lost Tribe"),
LUNAR_DIPLOMACY("Lunar Diplomacy"),
MAKING_HISTORY("Making History"),
MERLINS_CRYSTAL("Merlin's Crystal"),
MONKEY_MADNESS("Monkey Madness"),
MONKS_FRIEND("Monk's Friend"),
MOUNTAIN_DAUGHTER("Mountain Daughter"),
MOURNINGS_END_PART_I("Mourning's End Part I"),
MOURNINGS_END_PART_II("Mourning's End Part II"),
MURDER_MYSTERY("Murder Mystery"),
MY_ARMS_BIG_ADVENTURE("My Arm's Big Adventure"),
NATURE_SPIRIT("Nature Spirit"),
OBSERVATORY_QUEST("Observatory Quest"),
ONE_SMALL_FAVOUR("One Small Favour"),
PLAGUE_CITY("Plague City"),
PRIEST_IN_PERIL("Priest in Peril"),
RAG_AND_BONE_MAN("Rag and Bone Man"),
RATCATCHERS("Ratcatchers"),
RECIPE_FOR_DISASTER("Recipe for Disaster"),
RECRUITMENT_DRIVE("Recruitment Drive"),
REGICIDE("Regicide"),
ROVING_ELVES("Roving Elves"),
ROYAL_TROUBLE("Royal Trouble"),
RUM_DEAL("Rum Deal"),
SCORPION_CATCHER("Scorpion Catcher"),
SEA_SLUG("Sea Slug"),
THE_SLUG_MENACE("The Slug Menace"),
SHADES_OF_MORTTON("Shades of Mort'ton"),
SHADOW_OF_THE_STORM("Shadow of the Storm"),
SHEEP_HERDER("Sheep Herder"),
SHILO_VILLAGE("Shilo Village"),
A_SOULS_BANE("A Soul's Bane"),
SPIRITS_OF_THE_ELID("Spirits of the Elid"),
SWAN_SONG("Swan Song"),
TAI_BWO_WANNAI_TRIO("Tai Bwo Wannai Trio"),
A_TAIL_OF_TWO_CATS("A Tail of Two Cats"),
TEARS_OF_GUTHIX("Tears of Guthix"),
TEMPLE_OF_IKOV("Temple of Ikov"),
THRONE_OF_MISCELLANIA("Throne of Miscellania"),
THE_TOURIST_TRAP("The Tourist Trap"),
WITCHS_HOUSE("Witch's House"),
TREE_GNOME_VILLAGE("Tree Gnome Village"),
TRIBAL_TOTEM("Tribal Totem"),
TROLL_ROMANCE("Troll Romance"),
TROLL_STRONGHOLD("Troll Stronghold"),
UNDERGROUND_PASS("Underground Pass"),
WANTED("Wanted!"),
WATCHTOWER("Watchtower"),
COLD_WAR("Cold War"),
THE_FREMENNIK_ISLES("The Fremennik Isles"),
TOWER_OF_LIFE("Tower of Life"),
THE_GREAT_BRAIN_ROBBERY("The Great Brain Robbery"),
WHAT_LIES_BELOW("What Lies Below"),
OLAFS_QUEST("Olaf's Quest"),
ANOTHER_SLICE_OF_HAM("Another Slice of H.A.M"),
DREAM_MENTOR("Dream Mentor"),
GRIM_TALES("Grim Tales"),
KINGS_RANSOM("King's Ransom"),
THE_PATH_OF_GLOUPHRIE("The Path of Glouphrie"),
BACK_TO_MY_ROOTS("Back to my Roots"),
LAND_OF_THE_GOBLINS("Land of the Goblins"),
DEALING_WITH_SCABARAS("Dealing with Scabaras"),
WOLF_WHISTLE("Wolf Whistle"),
AS_A_FIRST_RESORT("As a First Resort..."),
CATAPULT_CONSTRUCTION("Catapult Construction"),
KENNITHS_CONCERNS("Kennith's Concerns"),
LEGACY_OF_SEERGAZE("Legacy of Seergaze"),
PERILS_OF_ICE_MOUNTAIN("Perils of Ice Mountain"),
TOKTZ_KET_DILL("TokTz-Ket-Dill"),
SMOKING_KILLS("Smoking Kills"),
ROCKING_OUT("Rocking Out"),
SPIRIT_OF_SUMMER("Spirit of Summer"),
MEETING_HISTORY("Meeting History"),
ALL_FIRED_UP("All Fired Up"),
SUMMERS_END("Summer's End"),
DEFENDER_OF_VARROCK("Defender of Varrock"),
SWEPT_AWAY("Swept Away"),
WHILE_GUTHIX_SLEEPS("While Guthix Sleeps"),
IN_PYRE_NEED("In Pyre Need"),
TEST_QUEST("Test Quest");
override fun toString(): String {
return questName
}
}

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

@ -30,36 +30,36 @@ public enum Consumables {
HERRING(new Food(new int[] {347}, new HealingEffect(5))), HERRING(new Food(new int[] {347}, new HealingEffect(5))),
MACKEREL(new Food(new int[] {355}, new HealingEffect(6))), MACKEREL(new Food(new int[] {355}, new HealingEffect(6))),
ROAST_BIRD_MEAT(new Food(new int[] {9980}, new HealingEffect(6))), ROAST_BIRD_MEAT(new Food(new int[] {9980}, new HealingEffect(6))),
THIN_SNAIL(new Food(new int[] {3369}, new HealingEffect(5))), THIN_SNAIL(new Food(new int[] {3369}, new RandomHealthEffect(5, 7))),
TROUT(new Food(new int[] {333}, new HealingEffect(7))), TROUT(new Food(new int[] {333}, new HealingEffect(7))),
SPIDER_ON_STICK(new Food(new int[] {6297, 6305}, new HealingEffect(7))), SPIDER_ON_STICK(new Food(new int[] {6297, 6305}, new RandomHealthEffect(7, 11))),
SPIDER_ON_SHAFT(new Food(new int[] {6299}, new HealingEffect(7))), SPIDER_ON_SHAFT(new Food(new int[] {6299}, new HealingEffect(7))),
ROAST_RABBIT(new Food(new int[] {7223}, new HealingEffect(7))), ROAST_RABBIT(new Food(new int[] {7223}, new HealingEffect(7))),
LEAN_SNAIL(new Food(new int[] {3371}, new HealingEffect(8))), LEAN_SNAIL(new Food(new int[] {3371}, new RandomHealthEffect(6, 8))),
COD(new Food(new int[] {339}, new HealingEffect(7))), COD(new Food(new int[] {339}, new HealingEffect(7))),
PIKE(new Food(new int[] {351}, new HealingEffect(8))), PIKE(new Food(new int[] {351}, new HealingEffect(8))),
ROAST_BEAST_MEAT(new Food(new int[] {9988}, new HealingEffect(8))), ROAST_BEAST_MEAT(new Food(new int[] {9988}, new HealingEffect(8))),
COOKED_CRAB_MEAT(new Food(new int[] {7521, 7523, 7524, 7525, 7526}, new HealingEffect(2))), COOKED_CRAB_MEAT(new Food(new int[] {7521, 7523, 7524, 7525, 7526}, new HealingEffect(2))),
FAT_SNAIL(new Food(new int[] {3373}, new HealingEffect(9))), FAT_SNAIL(new Food(new int[] {3373}, new RandomHealthEffect(7, 9))),
SALMON(new Food(new int[] {329}, new HealingEffect(9))), SALMON(new Food(new int[] {329}, new HealingEffect(9))),
SLIMY_EEL(new Food(new int[] {3381}, new HealingEffect(6))), SLIMY_EEL(new Food(new int[] {3381}, new RandomHealthEffect(6, 10))),
TUNA(new Food(new int[] {361}, new HealingEffect(10))), TUNA(new Food(new int[] {361}, new HealingEffect(10))),
COOKED_KARAMBWAN(new Food(new int[] {3144}, new HealingEffect(18)), true), COOKED_KARAMBWAN(new Food(new int[] {3144}, new HealingEffect(18)), true),
COOKED_CHOMPY(new Food(new int[] {2878}, new HealingEffect(10))), COOKED_CHOMPY(new Food(new int[] {2878}, new HealingEffect(10))),
RAINBOW_FISH(new Food(new int[] {10136}, new HealingEffect(11))), RAINBOW_FISH(new Food(new int[] {10136}, new HealingEffect(11))),
CAVE_EEL(new Food(new int[] {5003}, new HealingEffect(7))), CAVE_EEL(new Food(new int[] {5003}, new RandomHealthEffect(8, 12))),
LOBSTER(new Food(new int[] {379}, new HealingEffect(12))), LOBSTER(new Food(new int[] {379}, new HealingEffect(12))),
COOKED_JUBBLY(new Food(new int[] {7568}, new HealingEffect(15))), COOKED_JUBBLY(new Food(new int[] {7568}, new HealingEffect(15))),
BASS(new Food(new int[] {365}, new HealingEffect(13))), BASS(new Food(new int[] {365}, new HealingEffect(13))),
SWORDFISH(new Food(new int[] {373}, new HealingEffect(14))), SWORDFISH(new Food(new int[] {373}, new HealingEffect(14))),
LAVA_EEL(new Food(new int[] {2149}, new HealingEffect(14))), LAVA_EEL(new Food(new int[] {2149}, new HealingEffect(11))),
MONKFISH(new Food(new int[] {7946}, new HealingEffect(16))), MONKFISH(new Food(new int[] {7946}, new HealingEffect(16))),
SHARK(new Food(new int[] {385}, new HealingEffect(20))), SHARK(new Food(new int[] {385}, new HealingEffect(20))),
SEA_TURTLE(new Food(new int[] {397}, new HealingEffect(21))), SEA_TURTLE(new Food(new int[] {397}, new HealingEffect(21))),
MANTA_RAY(new Food(new int[] {391}, new HealingEffect(22))), MANTA_RAY(new Food(new int[] {391}, new HealingEffect(22))),
KARAMBWANJI(new Food(new int[] {3151}, new HealingEffect(3))), KARAMBWANJI(new Food(new int[] {3151}, new HealingEffect(3))),
STUFFED_SNAKE(new Food(new int[] {7579}, new HealingEffect(20), "You eat the stuffed snake-it's quite a meal! It tastes like chicken.")), STUFFED_SNAKE(new Food(new int[] {7579}, new HealingEffect(20), "You eat the stuffed snake-it's quite a meal! It tastes like chicken.")),
CRAYFISH(new Food(new int[] {13433}, new HealingEffect(2))), CRAYFISH(new Food(new int[] {13433}, new HealingEffect(1))),
GIANT_FROG_LEGS(new Food(new int [] {4517}, new HealingEffect(6))), GIANT_FROG_LEGS(new Food(new int [] {4517}, new HealingEffect(6))),
/** Breads */ /** Breads */
@ -110,8 +110,8 @@ public enum Consumables {
MINT_CAKE(new Food(new int[] {9475}, new EnergyEffect(50))), MINT_CAKE(new Food(new int[] {9475}, new EnergyEffect(50))),
/** Vegetables */ /** Vegetables */
POTATO(new Food(new int[] {1942}, new HealingEffect(1))), POTATO(new Food(new int[] {1942}, new HealingEffect(1), "You eat the potato. Yuck!")),
BAKED_POTATO(new Food(new int[] {6701}, new HealingEffect(2))), BAKED_POTATO(new Food(new int[] {6701}, new HealingEffect(4))),
SPICY_SAUCE(new Food(new int[] {7072, 1923}, new HealingEffect(2))), SPICY_SAUCE(new Food(new int[] {7072, 1923}, new HealingEffect(2))),
CHILLI_CON_CARNE(new Food(new int[] {7062, 1923}, new HealingEffect(5))), CHILLI_CON_CARNE(new Food(new int[] {7062, 1923}, new HealingEffect(5))),
SCRAMBLED_EGG(new Food(new int[] {7078, 1923}, new HealingEffect(5))), SCRAMBLED_EGG(new Food(new int[] {7078, 1923}, new HealingEffect(5))),
@ -128,8 +128,8 @@ public enum Consumables {
MUSHROOM_POTATO(new Food(new int[] {7058}, new HealingEffect(20))), MUSHROOM_POTATO(new Food(new int[] {7058}, new HealingEffect(20))),
TUNA_AND_CORN(new Food(new int[] {7068, 1923}, new HealingEffect(13))), TUNA_AND_CORN(new Food(new int[] {7068, 1923}, new HealingEffect(13))),
TUNA_POTATO(new Food(new int[] {7060}, new HealingEffect(22))), TUNA_POTATO(new Food(new int[] {7060}, new HealingEffect(22))),
ONION(new Food(new int[] {1957}, new HealingEffect(2), "It's always sad to see a grown man/woman cry.")), ONION(new Food(new int[] {1957}, new HealingEffect(1), "It's always sad to see a grown man/woman cry.")),
CABBAGE(new Food(new int[] {1965}, new HealingEffect(2), "You eat the cabbage. Yuck!")), CABBAGE(new Food(new int[] {1965}, new HealingEffect(1), "You eat the cabbage. Yuck!")),
DRAYNOR_CABBAGE(new Food(new int[] {1967}, new DraynorCabbageEffect(), "You eat the cabbage.", "It seems to taste nicer than normal.")), DRAYNOR_CABBAGE(new Food(new int[] {1967}, new DraynorCabbageEffect(), "You eat the cabbage.", "It seems to taste nicer than normal.")),
EVIL_TURNIP(new Food(new int[] {12134, 12136, 12138}, new HealingEffect(6))), EVIL_TURNIP(new Food(new int[] {12134, 12136, 12138}, new HealingEffect(6))),
SPINACH_ROLL(new Food(new int[] {1969}, new HealingEffect(2))), SPINACH_ROLL(new Food(new int[] {1969}, new HealingEffect(2))),
@ -147,16 +147,16 @@ public enum Consumables {
ORANGE(new Food(new int[] {2108}, new HealingEffect(2))), ORANGE(new Food(new int[] {2108}, new HealingEffect(2))),
ORANGE_CHUNKS(new Food(new int[] {2110}, new HealingEffect(2))), ORANGE_CHUNKS(new Food(new int[] {2110}, new HealingEffect(2))),
ORANGE_SLICES(new Food(new int[] {2112}, new HealingEffect(2))), ORANGE_SLICES(new Food(new int[] {2112}, new HealingEffect(2))),
PAPAYA_FRUIT(new Food(new int[] {5972}, new HealingEffect(2))), PAPAYA_FRUIT(new Food(new int[] {5972}, new MultiEffect(new EnergyEffect(5), new HealingEffect(8)))),
TENTI_PINEAPPLE(new FakeConsumable(1851, new String[] {"Try using a knife to slice it into pieces."})), TENTI_PINEAPPLE(new FakeConsumable(1851, new String[] {"Try using a knife to slice it into pieces."})),
PINEAPPLE(new FakeConsumable(2114, new String[] {"Try using a knife to slice it into pieces."})), PINEAPPLE(new FakeConsumable(2114, new String[] {"Try using a knife to slice it into pieces."})),
PINEAPPLE_CHUNKS(new Food(new int[] {2116}, new HealingEffect(2))), PINEAPPLE_CHUNKS(new Food(new int[] {2116}, new HealingEffect(2))),
PINEAPPLE_RING(new Food(new int[] {2118}, new HealingEffect(2))), PINEAPPLE_RING(new Food(new int[] {2118}, new HealingEffect(2))),
DWELLBERRIES(new Food(new int[] {2126}, new HealingEffect(2))), DWELLBERRIES(new Food(new int[] {2126}, new HealingEffect(2))),
JANGERBERRIES(new Food(new int[] {247}, new MultiEffect(new SkillEffect(Skills.ATTACK, 2, 0), new SkillEffect(Skills.STRENGTH, 1, 0), new PrayerEffect(1, 0), new SkillEffect(Skills.DEFENCE, -1, 0)))), JANGERBERRIES(new Food(new int[] {247}, new MultiEffect(new SkillEffect(Skills.ATTACK, 2, 0), new SkillEffect(Skills.STRENGTH, 1, 0), new PrayerEffect(1, 0), new SkillEffect(Skills.DEFENCE, -1, 0)), "You eat the jangerberries.", "They taste very bitter.")),
STRAWBERRY(new Food(new int[] {5504}, new MultiEffect(new HealingEffect(1), new PercentageHealthEffect(6)))), STRAWBERRY(new Food(new int[] {5504}, new MultiEffect(new HealingEffect(1), new PercentageHealthEffect(6)))),
TOMATO(new Food(new int[] {1982}, new HealingEffect(2))), TOMATO(new Food(new int[] {1982}, new HealingEffect(2))),
WATERMELON(new FakeConsumable(5982, new String[] {"Try using a knife to slice it into pieces."})), WATERMELON(new FakeConsumable(5982, new String[] {"You can't eat it whole; maybe you should cut it up."})),
WATERMELON_SLICE(new Food(new int[] {5984}, new PercentageHealthEffect(5))), WATERMELON_SLICE(new Food(new int[] {5984}, new PercentageHealthEffect(5))),
LEMON(new Food(new int[] {2102}, new HealingEffect(2))), LEMON(new Food(new int[] {2102}, new HealingEffect(2))),
LEMON_CHUNKS(new Food(new int[] {2104}, new HealingEffect(2))), LEMON_CHUNKS(new Food(new int[] {2104}, new HealingEffect(2))),
@ -169,8 +169,8 @@ public enum Consumables {
STRANGE_FRUIT(new Food(new int[] {464}, new MultiEffect(new RemoveTimerEffect("poison"), new EnergyEffect(30)))), STRANGE_FRUIT(new Food(new int[] {464}, new MultiEffect(new RemoveTimerEffect("poison"), new EnergyEffect(30)))),
/** Gnome Cooking */ /** Gnome Cooking */
TOAD_CRUNCHIES(new Food(new int[] {2217}, new HealingEffect(12))), TOAD_CRUNCHIES(new Food(new int[] {2217}, new HealingEffect(8))),
PREMADE_TD_CRUNCH(new Food(new int[] {2243}, new HealingEffect(12))), PREMADE_TD_CRUNCH(new Food(new int[] {2243}, new HealingEffect(8))),
SPICY_CRUNCHIES(new Food(new int[] {2213}, new HealingEffect(7))), SPICY_CRUNCHIES(new Food(new int[] {2213}, new HealingEffect(7))),
PREMADE_SY_CRUNCH(new Food(new int[] {2241}, new HealingEffect(7))), PREMADE_SY_CRUNCH(new Food(new int[] {2241}, new HealingEffect(7))),
WORM_CRUNCHIES(new Food(new int[] {2205}, new HealingEffect(8))), WORM_CRUNCHIES(new Food(new int[] {2205}, new HealingEffect(8))),
@ -272,11 +272,11 @@ public enum Consumables {
BRAINDEATH_RUM(new Drink(new int[] {7157}, new MultiEffect(new SkillEffect(Skills.DEFENCE, 0, -0.1), new SkillEffect(Skills.ATTACK, 0, -0.05), new SkillEffect(Skills.PRAYER, 0, -0.05), new SkillEffect(Skills.RANGE, 0, -0.05), new SkillEffect(Skills.MAGIC, 0, -0.05), new SkillEffect(Skills.HERBLORE, 0, -0.05), new SkillEffect(Skills.STRENGTH, 3, 0), new SkillEffect(Skills.MINING, 1, 0)), "With a sense of impending doom you drink the 'rum'. You try very hard not to die.")), BRAINDEATH_RUM(new Drink(new int[] {7157}, new MultiEffect(new SkillEffect(Skills.DEFENCE, 0, -0.1), new SkillEffect(Skills.ATTACK, 0, -0.05), new SkillEffect(Skills.PRAYER, 0, -0.05), new SkillEffect(Skills.RANGE, 0, -0.05), new SkillEffect(Skills.MAGIC, 0, -0.05), new SkillEffect(Skills.HERBLORE, 0, -0.05), new SkillEffect(Skills.STRENGTH, 3, 0), new SkillEffect(Skills.MINING, 1, 0)), "With a sense of impending doom you drink the 'rum'. You try very hard not to die.")),
RUM_TROUBLE_BREWING_RED(new Drink(new int[] {8940, 8940}, new TroubleBrewingRumEffect("Oh gods! It tastes like burning!"), new Animation(9605))), RUM_TROUBLE_BREWING_RED(new Drink(new int[] {8940, 8940}, new TroubleBrewingRumEffect("Oh gods! It tastes like burning!"), new Animation(9605))),
RUM_TROUBLE_BREWING_BLUE(new Drink(new int[] {8941, 8941}, new TroubleBrewingRumEffect("My Liver! My Liver is melting!"), new Animation(9604))), RUM_TROUBLE_BREWING_BLUE(new Drink(new int[] {8941, 8941}, new TroubleBrewingRumEffect("My Liver! My Liver is melting!"), new Animation(9604))),
VODKA(new Drink(new int[] {2015}, new MultiEffect(new SkillEffect(Skills.STRENGTH, 3, 0), new SkillEffect(Skills.ATTACK, -3, 0)))), VODKA(new Drink(new int[] {2015}, new MultiEffect(new HealingEffect(2), new SkillEffect(Skills.ATTACK, -4, 0), new SkillEffect(Skills.STRENGTH, 4, 0)))),
GIN(new Drink(new int[] {2019}, new MultiEffect(new SkillEffect(Skills.STRENGTH, 1, 0), new SkillEffect(Skills.ATTACK, 4, 0), new RandomHealthEffect(3, 4)))), GIN(new Drink(new int[] {2019}, new MultiEffect(new SkillEffect(Skills.STRENGTH, 1, 0), new SkillEffect(Skills.ATTACK, 4, 0), new RandomHealthEffect(3, 4)))),
BRANDY(new Drink(new int[] {2021}, new MultiEffect(new HealingEffect(5), new SkillEffect(Skills.ATTACK, 4, 0)))), BRANDY(new Drink(new int[] {2021}, new MultiEffect(new HealingEffect(5), new SkillEffect(Skills.ATTACK, 4, 0)))),
WHISKY(new Drink(new int[] {2017}, new MultiEffect(new HealingEffect(5), new SkillEffect(Skills.STRENGTH, 3, 0), new SkillEffect(Skills.ATTACK, -4, 0)))), WHISKY(new Drink(new int[] {2017}, new MultiEffect(new HealingEffect(5), new SkillEffect(Skills.STRENGTH, 3, 0), new SkillEffect(Skills.ATTACK, -4, 0)))),
BOTTLE_OF_WINE(new Drink(new int[] {2015, 7921}, new MultiEffect(new HealingEffect(14), new SkillEffect(Skills.ATTACK, -3, 0)))), BOTTLE_OF_WINE(new Drink(new int[] {7919, 7921}, new MultiEffect(new HealingEffect(14), new SkillEffect(Skills.ATTACK, -3, 0)))),
/** Wine */ /** Wine */
JUG_OF_WINE(new Drink(new int[] {1993, 1935}, new MultiEffect(new HealingEffect(11), new SkillEffect(Skills.ATTACK, -2, 0)))), JUG_OF_WINE(new Drink(new int[] {1993, 1935}, new MultiEffect(new HealingEffect(11), new SkillEffect(Skills.ATTACK, -2, 0)))),
@ -287,7 +287,7 @@ public enum Consumables {
CUP_OF_TEA(new Drink(new int[] {712, 1980}, new MultiEffect(new HealingEffect(3), new SkillEffect(Skills.ATTACK, 3, 0)), "Aaah, nothing like a nice cuppa tea!")), CUP_OF_TEA(new Drink(new int[] {712, 1980}, new MultiEffect(new HealingEffect(3), new SkillEffect(Skills.ATTACK, 3, 0)), "Aaah, nothing like a nice cuppa tea!")),
CUP_OF_TEA_NETTLE(new Drink(new int[] {4242, 1980}, new EnergyEffect(10))), CUP_OF_TEA_NETTLE(new Drink(new int[] {4242, 1980}, new EnergyEffect(10))),
CUP_OF_TEA_MILKY_NETTLE(new Drink(new int[] {4243, 1980}, new EnergyEffect(10))), CUP_OF_TEA_MILKY_NETTLE(new Drink(new int[] {4243, 1980}, new EnergyEffect(10))),
NETTLE_TEA(new Drink(new int[] {4239, 1980}, new NettleTeaEffect())), NETTLE_TEA(new Drink(new int[] {4239, 1923}, new NettleTeaEffect())),
NETTLE_TEA_MILKY(new Drink(new int[] {4240, 1980}, new NettleTeaEffect())), NETTLE_TEA_MILKY(new Drink(new int[] {4240, 1980}, new NettleTeaEffect())),
CUP_OF_TEA_CLAY(new Drink(new int[] {7730, 7728}, new SkillEffect(Skills.CONSTRUCTION, 1, 0), "You feel refreshed and ready for more building.")), CUP_OF_TEA_CLAY(new Drink(new int[] {7730, 7728}, new SkillEffect(Skills.CONSTRUCTION, 1, 0), "You feel refreshed and ready for more building.")),
CUP_OF_TEA_CLAY_MILKY(new Drink(new int[] {7731, 7728}, new SkillEffect(Skills.CONSTRUCTION, 1, 0))), CUP_OF_TEA_CLAY_MILKY(new Drink(new int[] {7731, 7728}, new SkillEffect(Skills.CONSTRUCTION, 1, 0))),
@ -307,8 +307,9 @@ public enum Consumables {
OOMLIE_WRAP(new Food(new int[] {Items.COOKED_OOMLIE_WRAP_2343}, new MultiEffect(new HealingEffect(14), new AchievementEffect(DiaryType.KARAMJA, 2, 2)))), OOMLIE_WRAP(new Food(new int[] {Items.COOKED_OOMLIE_WRAP_2343}, new MultiEffect(new HealingEffect(14), new AchievementEffect(DiaryType.KARAMJA, 2, 2)))),
ROE(new Food(new int[]{11324}, new HealingEffect(3))), ROE(new Food(new int[]{11324}, new HealingEffect(3))),
EQUA_LEAVES(new Food(new int[]{2128}, new HealingEffect(1))), EQUA_LEAVES(new Food(new int[]{2128}, new HealingEffect(1))),
CHOC_ICE(new Food(new int[]{6794}, new HealingEffect(6))), CHOC_ICE(new Food(new int[]{6794}, new HealingEffect(7))),
EDIBLE_SEAWEED(new Food(new int[] {403}, new HealingEffect(4))), EDIBLE_SEAWEED(new Food(new int[] {403}, new HealingEffect(4))),
FROG_SPAWN(new Food(new int[] {5004}, new RandomHealthEffect(3, 7), "You eat the frogspawn. Yuck.")),
/** Special Events */ /** Special Events */
PUMPKIN(new Food(new int[] {1959}, new HealingEffect(14))), PUMPKIN(new Food(new int[] {1959}, new HealingEffect(14))),
@ -318,44 +319,44 @@ public enum Consumables {
STRENGTH(new Potion(new int[] {113, 115, 117, 119}, new SkillEffect(Skills.STRENGTH, 3, 0.1))), STRENGTH(new Potion(new int[] {113, 115, 117, 119}, new SkillEffect(Skills.STRENGTH, 3, 0.1))),
ATTACK(new Potion(new int[] {2428, 121, 123, 125}, new SkillEffect(Skills.ATTACK, 3, 0.1))), ATTACK(new Potion(new int[] {2428, 121, 123, 125}, new SkillEffect(Skills.ATTACK, 3, 0.1))),
DEFENCE(new Potion(new int[] {2432, 133, 135, 137}, new SkillEffect(Skills.DEFENCE, 3, 0.1))), DEFENCE(new Potion(new int[] {2432, 133, 135, 137}, new SkillEffect(Skills.DEFENCE, 3, 0.1))),
RANGING(new Potion(new int[] {2444, 169, 171, 173}, new SkillEffect(Skills.RANGE, 3, 0.1))), RANGING(new Potion(new int[] {2444, 169, 171, 173}, new SkillEffect(Skills.RANGE, 4, 0.1))),
MAGIC(new Potion(new int[] {3040, 3042, 3044, 3046}, new SkillEffect(Skills.MAGIC, 3, 0.1))), MAGIC(new Potion(new int[] {3040, 3042, 3044, 3046}, new SkillEffect(Skills.MAGIC, 4, 0))),
SUPER_STRENGTH(new Potion(new int[] {2440, 157, 159, 161}, new SkillEffect(Skills.STRENGTH, 3, 0.2))), SUPER_STRENGTH(new Potion(new int[] {2440, 157, 159, 161}, new SkillEffect(Skills.STRENGTH, 5, 0.15))),
SUPER_ATTACK(new Potion(new int[] {2436, 145, 147, 149}, new SkillEffect(Skills.ATTACK, 3, 0.2))), SUPER_ATTACK(new Potion(new int[] {2436, 145, 147, 149}, new SkillEffect(Skills.ATTACK, 5, 0.15))),
SUPER_DEFENCE(new Potion(new int[] {2442, 163, 165, 167}, new SkillEffect(Skills.DEFENCE, 3, 0.2))), SUPER_DEFENCE(new Potion(new int[] {2442, 163, 165, 167}, new SkillEffect(Skills.DEFENCE, 5, 0.15))),
ANTIPOISON(new Potion(new int[] {2446, 175, 177, 179}, new AddTimerEffect("poison:immunity", secondsToTicks(90)))), ANTIPOISON(new Potion(new int[] {2446, 175, 177, 179}, new AddTimerEffect("poison:immunity", secondsToTicks(90)))),
ANTIPOISON_(new Potion(new int[] {5943, 5945, 5947, 5949}, new AddTimerEffect("poison:immunity", minutesToTicks(9)))), ANTIPOISON_(new Potion(new int[] {5943, 5945, 5947, 5949}, new AddTimerEffect("poison:immunity", minutesToTicks(9)))),
ANTIPOISON__(new Potion(new int[] {5952, 5954, 5956, 5958}, new AddTimerEffect("poison:immunity", minutesToTicks(12)))), ANTIPOISON__(new Potion(new int[] {5952, 5954, 5956, 5958}, new AddTimerEffect("poison:immunity", minutesToTicks(12)))),
SUPER_ANTIP(new Potion(new int[] {2448, 181, 183, 185}, new AddTimerEffect("poison:immunity", minutesToTicks(6)))), SUPER_ANTIP(new Potion(new int[] {2448, 181, 183, 185}, new AddTimerEffect("poison:immunity", minutesToTicks(6)))),
RELICYM(new Potion(new int[] {4842, 4844, 4846, 4848}, new MultiEffect(new SetAttributeEffect("disease:immunity", 300), new RemoveTimerEffect("disease")))), RELICYM(new Potion(new int[] {4842, 4844, 4846, 4848}, new CureDiseaseEffect())),
AGILITY(new Potion(new int[] {3032, 3034, 3036, 3038}, new SkillEffect(Skills.AGILITY, 3, 0))), AGILITY(new Potion(new int[] {3032, 3034, 3036, 3038}, new SkillEffect(Skills.AGILITY, 3, 0))),
HUNTER(new Potion(new int[] {9998, 10000, 10002, 10004}, new SkillEffect(Skills.HUNTER, 3, 0))), HUNTER(new Potion(new int[] {9998, 10000, 10002, 10004}, new SkillEffect(Skills.HUNTER, 3, 0))),
RESTORE(new Potion(new int[] {2430, 127, 129, 131}, new RestoreEffect(10, 0.3))), RESTORE(new Potion(new int[] {2430, 127, 129, 131}, new RestoreEffect(10, 0.3))),
SARA_BREW(new Potion(new int[] {6685, 6687, 6689, 6691}, new MultiEffect(new PercentHeal(2, .15), new SkillEffect(Skills.ATTACK, 0, -0.10), new SkillEffect(Skills.STRENGTH, 0, -0.10), new SkillEffect(Skills.MAGIC, 0, -0.10), new SkillEffect(Skills.RANGE, 0, -0.10), new SkillEffect(Skills.DEFENCE, 2, 0.2)))), SARA_BREW(new Potion(new int[] {6685, 6687, 6689, 6691}, new MultiEffect(new PercentHeal(0, .15), new SkillEffect(Skills.ATTACK, 0, -0.10), new SkillEffect(Skills.STRENGTH, 0, -0.10), new SkillEffect(Skills.MAGIC, 0, -0.10), new SkillEffect(Skills.RANGE, 0, -0.10), new SkillEffect(Skills.DEFENCE, 0, 0.25)))),
SUMMONING(new Potion(new int[] {12140, 12142, 12144, 12146}, new MultiEffect(new RestoreSummoningSpecial(), new SummoningEffect(7, 0.25)))), SUMMONING(new Potion(new int[] {12140, 12142, 12144, 12146}, new MultiEffect(new RestoreSummoningSpecial(), new SummoningEffect(7, 0.25)))),
COMBAT(new Potion(new int[] {9739, 9741, 9743, 9745}, new MultiEffect(new SkillEffect(Skills.STRENGTH, 3, .1), new SkillEffect(Skills.ATTACK, 3, .1)))), COMBAT(new Potion(new int[] {9739, 9741, 9743, 9745}, new MultiEffect(new SkillEffect(Skills.STRENGTH, 3, .1), new SkillEffect(Skills.ATTACK, 3, .1)))),
ENERGY(new Potion(new int[] {3008, 3010, 3012, 3014}, new MultiEffect(new EnergyEffect(10), new HealingEffect(3)))), ENERGY(new Potion(new int[] {3008, 3010, 3012, 3014}, new EnergyEffect(10))),
FISHING(new Potion(new int[] {2438, 151, 153, 155}, new SkillEffect(Skills.FISHING, 3, 0))), FISHING(new Potion(new int[] {2438, 151, 153, 155}, new SkillEffect(Skills.FISHING, 3, 0))),
PRAYER(new Potion(new int[] {2434, 139, 141, 143}, new PrayerEffect(7, 0.25))), PRAYER(new Potion(new int[] {2434, 139, 141, 143}, new PrayerEffect(7, 0.25))),
SUPER_RESTO(new Potion(new int[] {3024, 3026, 3028, 3030}, new MultiEffect(new RestoreEffect(8, 0.25), new PrayerEffect(8, 0.25), new SummoningEffect(8, 0.25)))), SUPER_RESTO(new Potion(new int[] {3024, 3026, 3028, 3030}, new RestoreEffect(8, 0.25, true))),
ZAMMY_BREW(new Potion(new int[] {2450, 189, 191, 193}, new MultiEffect(new DamageEffect(10, true), new SkillEffect(Skills.ATTACK, 0, 0.15), new SkillEffect(Skills.STRENGTH, 0, 0.25), new SkillEffect(Skills.DEFENCE, 0, -0.1), new RandomPrayerEffect(0, 10)))), 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 SetAttributeEffect("fire:immune", 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), new PrayerEffect(8,0.25), new RemoveTimerEffect("poison"), 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."})),
/** Barbarian Mixes */ /** Barbarian Mixes */
PRAYERMIX(new BarbarianMix(new int[] {11465, 11467}, new MultiEffect(new PrayerEffect(7, 0.25), new HealingEffect(6)))), PRAYERMIX(new BarbarianMix(new int[] {11465, 11467}, new MultiEffect(new PrayerEffect(7, 0.25), new HealingEffect(6)))),
ZAMMY_MIX(new BarbarianMix(new int[] {11521, 11523}, new MultiEffect(new DamageEffect(10, true), new SkillEffect(Skills.ATTACK, 0, 0.15), new SkillEffect(Skills.STRENGTH, 0, 0.25), new SkillEffect(Skills.DEFENCE, 0, -0.1), new RandomPrayerEffect(0, 10)))), ZAMMY_MIX(new BarbarianMix(new int[] {11521, 11523}, new MultiEffect(new DamageEffect(10, true), new SkillEffect(Skills.ATTACK, 0, 0.15), new SkillEffect(Skills.STRENGTH, 0, 0.25), new SkillEffect(Skills.DEFENCE, 0, -0.1)))),
ATT_MIX(new BarbarianMix(new int[] {11429, 11431}, new MultiEffect(new SkillEffect(Skills.ATTACK, 3, 0.1), new HealingEffect(3)))), ATT_MIX(new BarbarianMix(new int[] {11429, 11431}, new MultiEffect(new SkillEffect(Skills.ATTACK, 3, 0.1), new HealingEffect(3)))),
ANTIP_MIX(new BarbarianMix(new int[] {11433, 11435}, new MultiEffect(new AddTimerEffect("poison:immunity", 143), new HealingEffect(3)))), ANTIP_MIX(new BarbarianMix(new int[] {11433, 11435}, new MultiEffect(new AddTimerEffect("poison:immunity", secondsToTicks(90)), new HealingEffect(3)))),
RELIC_MIX(new BarbarianMix(new int[] {11437, 11439}, new MultiEffect(new RemoveTimerEffect("disease"), new SetAttributeEffect("disease:immunity", 300), new HealingEffect(3)))), RELIC_MIX(new BarbarianMix(new int[] {11437, 11439}, new MultiEffect(new CureDiseaseEffect(), new HealingEffect(3)))),
STR_MIX(new BarbarianMix(new int[] {11443, 11441}, new MultiEffect(new SkillEffect(Skills.STRENGTH, 3, 0.1), new HealingEffect(3)))), STR_MIX(new BarbarianMix(new int[] {11443, 11441}, new MultiEffect(new SkillEffect(Skills.STRENGTH, 3, 0.1), new HealingEffect(3)))),
RESTO_MIX(new BarbarianMix(new int[] {11449, 11451}, new MultiEffect(new RestoreEffect(10, 0.3), new HealingEffect(3)))), RESTO_MIX(new BarbarianMix(new int[] {11449, 11451}, new MultiEffect(new RestoreEffect(10, 0.3), new HealingEffect(3)))),
SUPER_RESTO_MIX(new BarbarianMix(new int [] {11493, 11495}, new MultiEffect(new RestoreEffect(8,0.25), new PrayerEffect(8, 0.25), new SummoningEffect(8, 0.25), new HealingEffect(6)))), SUPER_RESTO_MIX(new BarbarianMix(new int [] {11493, 11495}, new MultiEffect(new RestoreEffect(8,0.25), new PrayerEffect(8, 0.25), new SummoningEffect(8, 0.25), new HealingEffect(6)))),
ENERGY_MIX(new BarbarianMix(new int[] {11453, 11455}, new MultiEffect(new EnergyEffect(10), new HealingEffect(6)))), ENERGY_MIX(new BarbarianMix(new int[] {11453, 11455}, new MultiEffect(new EnergyEffect(10), new HealingEffect(3)))),
DEF_MIX(new BarbarianMix(new int[] {11457, 11459}, new MultiEffect(new SkillEffect(Skills.DEFENCE, 3, 0.1), new HealingEffect(6)))), DEF_MIX(new BarbarianMix(new int[] {11457, 11459}, new MultiEffect(new SkillEffect(Skills.DEFENCE, 3, 0.1), new HealingEffect(6)))),
AGIL_MIX(new BarbarianMix(new int[] {11461, 11463}, new MultiEffect(new SkillEffect(Skills.AGILITY, 3, 0), new HealingEffect(6)))), AGIL_MIX(new BarbarianMix(new int[] {11461, 11463}, new MultiEffect(new SkillEffect(Skills.AGILITY, 3, 0), new HealingEffect(6)))),
COMBAT_MIX(new BarbarianMix(new int[] {11445, 11447}, new MultiEffect(new SkillEffect(Skills.ATTACK, 3, 0.1), new SkillEffect(Skills.STRENGTH, 3, 0.1), new HealingEffect(6)))), COMBAT_MIX(new BarbarianMix(new int[] {11445, 11447}, new MultiEffect(new SkillEffect(Skills.ATTACK, 3, 0.1), new SkillEffect(Skills.STRENGTH, 3, 0.1), new HealingEffect(6)))),
@ -364,6 +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 HealingEffect(6)))),
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 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

@ -0,0 +1,21 @@
package content.data.consumables.effects
import core.api.*
import core.game.consumable.ConsumableEffect
import core.game.node.entity.player.Player
import core.game.system.timer.impl.Disease
class CureDiseaseEffect () : ConsumableEffect() {
override fun activate (p: Player) {
val existingTimer = getTimer<Disease>(p)
if (existingTimer != null) {
existingTimer.hitsLeft -= 9
if (existingTimer.hitsLeft <= 0) {
sendMessage(p, "The disease has been cured.")
removeTimer<Disease>(p)
}else{
sendMessage(p,"You feel slightly better.")
}
}
}
}

View file

@ -6,21 +6,37 @@ import core.game.node.entity.skill.Skills;
public class RestoreEffect extends ConsumableEffect { public class RestoreEffect extends ConsumableEffect {
double base,bonus; double base,bonus;
boolean all_skills; // Except for hitpoints
public RestoreEffect(double base, double bonus){ public RestoreEffect(double base, double bonus){
this.base = base; this.base = base;
this.bonus = bonus; this.bonus = bonus;
this.all_skills = false;
}
public RestoreEffect(double base, double bonus, boolean all_skills){
this.base = base;
this.bonus = bonus;
this.all_skills = all_skills;
} }
final int[] SKILLS = new int[] { Skills.DEFENCE, Skills.ATTACK, Skills.STRENGTH, Skills.MAGIC, Skills.RANGE }; final int[] SKILLS = new int[] { Skills.DEFENCE, Skills.ATTACK, Skills.STRENGTH, Skills.MAGIC, Skills.RANGE };
final int[] ALL_SKILLS = new int[]{
Skills.ATTACK,Skills.DEFENCE, Skills.STRENGTH,Skills.RANGE,Skills.PRAYER,Skills.MAGIC, Skills.COOKING,
Skills.WOODCUTTING,Skills.FLETCHING,Skills.FISHING,Skills.FIREMAKING,Skills.CRAFTING,Skills.SMITHING,
Skills.MINING,Skills.HERBLORE,Skills.AGILITY,Skills.THIEVING,Skills.SLAYER,Skills.FARMING,
Skills.RUNECRAFTING,Skills.HUNTER,Skills.CONSTRUCTION,Skills.SUMMONING };
@Override @Override
public void activate(Player p) { public void activate(Player p) {
Skills sk = p.getSkills(); Skills sk = p.getSkills();
for(int skill : SKILLS){ int[] skills = this.all_skills ? ALL_SKILLS : SKILLS;
for(int skill : skills){
int statL = sk.getStaticLevel(skill); int statL = sk.getStaticLevel(skill);
int boost = (int) (base + (statL * bonus));
int curL = sk.getLevel(skill); int curL = sk.getLevel(skill);
if(curL < statL){ if(curL < statL){
int boost = (int) (base + (statL * bonus));
p.getSkills().updateLevel(skill, boost, statL); p.getSkills().updateLevel(skill, boost, statL);
} }
if (skill == Skills.PRAYER)
p.getSkills().incrementPrayerPoints(boost);
} }
} }
} }

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,28 +93,28 @@ 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"
) )
private val PORTCULLIS = Scenery.PORTCULLIS_10553 private val PORTCULLIS = Scenery.PORTCULLIS_10553
private val LADDER = Scenery.LADDER_10554
private val CHAMPION_STATUE_CLOSED = Scenery.CHAMPION_STATUE_10556 private val CHAMPION_STATUE_CLOSED = Scenery.CHAMPION_STATUE_10556
private val CHAMPION_STATUE_OPEN = Scenery.CHAMPION_STATUE_10557 private val CHAMPION_STATUE_OPEN = Scenery.CHAMPION_STATUE_10557
private val TRAPDOOR_CLOSED = Scenery.TRAPDOOR_10558 private val TRAPDOOR_CLOSED = Scenery.TRAPDOOR_10558
@ -124,6 +124,13 @@ class ChampionChallengeListener : InteractionListener, MapArea {
private val ARENA_ZONE = 12696 private val ARENA_ZONE = 12696
override fun defineListeners() { override fun defineListeners() {
// Champion's Guild Basement Ladder to Main Floor
addClimbDest(Location(3190, 9758, 0), Location(3190, 3356, 0))
// Champion Statue Ladder to Arena
addClimbDest(Location(3184, 9758, 0), Location(3182, 9758, 0))
// Arena Ladder to Champion's Guild Basement
addClimbDest(Location(3183, 9758, 0), Location(3185, 9758, 0))
on(LARXUS, IntType.NPC, "talk-to") { player, _ -> on(LARXUS, IntType.NPC, "talk-to") { player, _ ->
openDialogue(player, LarxusDialogue(false)) openDialogue(player, LarxusDialogue(false))
return@on true return@on true
@ -134,18 +141,18 @@ class ChampionChallengeListener : InteractionListener, MapArea {
return@on true return@on true
} }
on(TRAPDOOR_CLOSED, IntType.SCENERY, "open") { _, node ->
replaceScenery(node.asScenery(), TRAPDOOR_OPEN, 100, node.location)
return@on true
}
onUseWith(IntType.NPC, ChampionScrollsDropHandler.SCROLLS, NPCs.LARXUS_3050) { player, _, _ -> onUseWith(IntType.NPC, ChampionScrollsDropHandler.SCROLLS, NPCs.LARXUS_3050) { player, _, _ ->
openDialogue(player, LarxusDialogue(true)) openDialogue(player, LarxusDialogue(true))
return@onUseWith true return@onUseWith true
} }
on(TRAPDOOR_CLOSED, IntType.SCENERY, "open") { _, node ->
replaceScenery(node.asScenery(), TRAPDOOR_OPEN, 100, node.location)
return@on true
}
on(TRAPDOOR_OPEN, IntType.SCENERY, "close") { _, node -> on(TRAPDOOR_OPEN, IntType.SCENERY, "close") { _, node ->
replaceScenery(node.asScenery(), TRAPDOOR_CLOSED, 100, node.location) replaceScenery(node.asScenery(), TRAPDOOR_CLOSED, -1, node.location)
return@on true return@on true
} }
@ -154,15 +161,6 @@ class ChampionChallengeListener : InteractionListener, MapArea {
return@on true return@on true
} }
on(LADDER, IntType.SCENERY, "climb-up") { player, _ ->
teleport(player, Location.create(3185, 9758, 0))
return@on true
}
on(CHAMPION_STATUE_OPEN, IntType.SCENERY, "climb-down") { player, _ ->
teleport(player, Location.create(3182, 9758, 0))
return@on true
}
on(PORTCULLIS, IntType.SCENERY, "open") { player, node -> on(PORTCULLIS, IntType.SCENERY, "open") { player, node ->
if (player.getAttribute("championsarena:start", false) == false) { if (player.getAttribute("championsarena:start", false) == false) {
sendNPCDialogue(player, NPCs.LARXUS_3050, "You need to arrange a challenge with me before you enter the arena.") sendNPCDialogue(player, NPCs.LARXUS_3050, "You need to arrange a challenge with me before you enter the arena.")
@ -229,4 +227,4 @@ class ChampionChallengeListener : InteractionListener, MapArea {
ZoneRestriction.RANDOM_EVENTS ZoneRestriction.RANDOM_EVENTS
) )
} }
} }

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

@ -11,12 +11,13 @@ import core.ServerStore.Companion.getString
import content.global.bots.ShootingStarBot import content.global.bots.ShootingStarBot
import core.game.world.repository.Repository import core.game.world.repository.Repository
import core.tools.RandomFunction
/** /**
* Represents a shooting star object (Only ever initialized once) (ideally) * Represents a shooting star object (Only ever initialized once) (ideally)
* @author Ceikry * @author Ceikry
*/ */
class ShootingStar(var level: ShootingStarType = ShootingStarType.values().random()){ class ShootingStar(var level: ShootingStarType = ShootingStarType.values().random()) {
val crash_locations = mapOf( val crash_locations = mapOf(
"East of Dark Wizards' Tower" to Location.create(2925, 3339, 0), // East of Dark Wizards' Tower "East of Dark Wizards' Tower" to Location.create(2925, 3339, 0), // East of Dark Wizards' Tower
"Crafting Guild" to Location.create(2940, 3280, 0), // Crafting Guild Mine "Crafting Guild" to Location.create(2940, 3280, 0), // Crafting Guild Mine
@ -26,12 +27,12 @@ class ShootingStar(var level: ShootingStarType = ShootingStarType.values().rando
"Brimhaven mining site" to Location.create(2743, 3143, 0), // Brimhaven mining site "Brimhaven mining site" to Location.create(2743, 3143, 0), // Brimhaven mining site
"South Crandor mining site" to Location.create(2822, 3239, 0), // South Crandor mining site (requires Dragon Slayer) "South Crandor mining site" to Location.create(2822, 3239, 0), // South Crandor mining site (requires Dragon Slayer)
"Karamja mining site" to Location.create(2854, 3032, 0), // Karamja mining site "Karamja mining site" to Location.create(2854, 3032, 0), // Karamja mining site
"Shilo Village mining site" to Location.create(2826, 2997, 0), // Shilo Village mining site/Gem rocks "Shilo Village mining site" to Location.create(2826, 2997, 0), // Shilo Village mining site/Gem rocks (requires Shilo Village prereqs)
"Relleka mining site" to Location.create(2682, 3700, 0), // Rellekka mining site "Relleka mining site" to Location.create(2682, 3700, 0), // Rellekka mining site
"Jatizso mine" to Location.create(2393, 3815, 0), //Jatiszo mining site (requires Fremennik Trials) "Jatizso mine" to Location.create(2393, 3815, 0), //Jatiszo mining site (requires Fremennik Isles prereqs)
//"Lunar Isle mine" to Location.create(2140, 3939, 0), // Lunar Isle mine (requires Lunar Diplomacy?) "Lunar Isle mine" to Location.create(2140, 3939, 0), // Lunar Isle mine (requires Lunar Diplomacy prereqs)
//"Miscellania coal mine" to Location.create(2529, 3887, 0), // Miscellania coal mine (requires Fremennik Trials) "Miscellania coal mine" to Location.create(2529, 3887, 0), // Miscellania coal mine (requires The Fremennik Trials)
//"Neitiznot runite mine" to Location.create(2376, 3835, 0), // Near the Neitiznot runite mine (requires Fremennik Trials) currently inaccessible as bridge does not work //"Neitiznot runite mine" to Location.create(2376, 3835, 0), // Near the Neitiznot runite mine (requires Fremennik Isles prereqs) currently inaccessible as bridge does not work
"Ardougne mining site" to Location.create(2600, 3232, 0), // Ardougne mining site (Monastery) "Ardougne mining site" to Location.create(2600, 3232, 0), // Ardougne mining site (Monastery)
"Ardougne eastern mine" to Location.create(2706, 3334, 0), // Ardougne mining site (Legends Guild) "Ardougne eastern mine" to Location.create(2706, 3334, 0), // Ardougne mining site (Legends Guild)
"Kandarin Coal trucks" to Location.create(2589, 3485, 0), // Kandarin Coal trucks "Kandarin Coal trucks" to Location.create(2589, 3485, 0), // Kandarin Coal trucks
@ -48,11 +49,11 @@ class ShootingStar(var level: ShootingStarType = ShootingStarType.values().rando
"South-west Varrock mine" to Location.create(3176, 3362, 0), // South-west Varrock mine / Champion's Guild mine "South-west Varrock mine" to Location.create(3176, 3362, 0), // South-west Varrock mine / Champion's Guild mine
"Varrock east bank" to Location.create(3259, 3407, 0), // Varrock east bank / Rune shop "Varrock east bank" to Location.create(3259, 3407, 0), // Varrock east bank / Rune shop
"Lumbridge Swamp south-east mine" to Location.create(3227, 3150, 0), // Lumbridge Swamp south-east mine "Lumbridge Swamp south-east mine" to Location.create(3227, 3150, 0), // Lumbridge Swamp south-east mine
//"Burgh de Rott bank" to Location.create(3500, 3219, 0), // Burgh de Rott bank (requires Quest to enter) //"Burgh de Rott bank" to Location.create(3500, 3219, 0), // Burgh de Rott bank (requires quest to enter)
"Canifis Bank" to Location.create(3504, 3487, 0), // Canifis bank "Canifis Bank" to Location.create(3504, 3487, 0), // Canifis bank
"Mos Le'Harmless bank" to Location.create(3687, 2969, 0), // Mos Le'Harmless bank (requires Quest to enter but is currently accessible for Slayer) "Mos Le'Harmless bank" to Location.create(3687, 2969, 0), // Mos Le'Harmless bank (requires quest to enter but is currently accessible for Slayer)
"Gnome stronghold Bank" to Location.create(2460, 3432, 0), // Gnome stronghold bank "Gnome stronghold Bank" to Location.create(2460, 3432, 0), // Gnome stronghold bank
"Lletya bank" to Location.create(2329, 3163, 0), // Lletya bank (requires Roving Elves?) "Lletya bank" to Location.create(2329, 3163, 0), // Lletya bank (requires MEP1 prereqs)
"Piscatoris mining site" to Location.create(2336, 3636, 0), // Piscatoris mining site "Piscatoris mining site" to Location.create(2336, 3636, 0), // Piscatoris mining site
"North Edgeville mining site" to Location.create(3101, 3569, 0), // Wilderness Steel mine / Zamorak mage mine "North Edgeville mining site" to Location.create(3101, 3569, 0), // Wilderness Steel mine / Zamorak mage mine
"Southern wilderness mine" to Location.create(3025, 3591, 0), // Wilderness skeleton mine "Southern wilderness mine" to Location.create(3025, 3591, 0), // Wilderness skeleton mine
@ -79,22 +80,15 @@ class ShootingStar(var level: ShootingStarType = ShootingStarType.values().rando
* Degrades a ShootingStar (or removes the starObject and spawns a Star Sprite if it's the last star) * Degrades a ShootingStar (or removes the starObject and spawns a Star Sprite if it's the last star)
*/ */
fun degrade() { fun degrade() {
if(level.ordinal == 0){ if(level.ordinal == 0) {
selfBots.filter { it.isMining() }.forEach { it.sleep() } spawnSprite()
SceneryBuilder.remove(starObject)
isSpawned = false
starSprite.location = starObject.location
starSprite.init()
spriteSpawned = true
ShootingStarPlugin.getStoreFile().clear()
return return
} }
level = getNextType() level = getNextType()
maxDust = level.totalStardust maxDust = level.totalStardust
dustLeft = level.totalStardust dustLeft = level.totalStardust
ShootingStarPlugin.getStoreFile()["level"] = level.ordinal ShootingStarPlugin.getStoreFile()["level"] = level.ordinal
ShootingStarPlugin.getStoreFile()["isDiscovered"] = isDiscovered ShootingStarPlugin.getStoreFile()["dustLeft"] = dustLeft
val newStar = Scenery(level.objectId, starObject.location) val newStar = Scenery(level.objectId, starObject.location)
SceneryBuilder.replace(starObject, newStar) SceneryBuilder.replace(starObject, newStar)
@ -110,7 +104,6 @@ class ShootingStar(var level: ShootingStarType = ShootingStarType.values().rando
*/ */
fun fire() { fun fire() {
SceneryBuilder.remove(starObject) SceneryBuilder.remove(starObject)
rebuildVars()
clearSprite() clearSprite()
SceneryBuilder.add(starObject) SceneryBuilder.add(starObject)
if(!isSpawned) { if(!isSpawned) {
@ -122,38 +115,55 @@ class ShootingStar(var level: ShootingStarType = ShootingStarType.values().rando
selfBots.filter { it.isIdle() }.forEach { it.activate(true) } selfBots.filter { it.isIdle() }.forEach { it.activate(true) }
} }
isSpawned = true isSpawned = true
Repository.sendNews("A shooting star level ${level.ordinal + 1} just crashed near ${location.toLowerCase()}!") Repository.sendNews("A shooting star level ${level.ordinal + 1} just crashed near ${location}!")
ShootingStarPlugin.getStoreFile()["level"] = level.ordinal
ShootingStarPlugin.getStoreFile()["location"] = location
ShootingStarPlugin.getStoreFile()["isDiscovered"] = isDiscovered
ShootingStarPlugin.getStoreFile()["dustLeft"] = dustLeft
} }
/** /**
* Rebuilds some of the variables with new information. * Rebuilds some of the variables with new information.
*/ */
fun rebuildVars(){ fun rebuildVars(){
if(firstStar && ShootingStarPlugin.getStoreFile().isNotEmpty()){ // Defaults
level = ShootingStarType.values()[ShootingStarPlugin.getStoreFile().getInt("level")] var levelOrd = RandomFunction.random(9)
location = ShootingStarPlugin.getStoreFile().getString("location") level = ShootingStarType.values()[levelOrd]
isDiscovered = ShootingStarPlugin.getStoreFile().getBoolean("isDiscovered") location = crash_locations.entries.random().key
} else { isDiscovered = false
level = ShootingStarType.values().random() dustLeft = level.totalStardust
location = crash_locations.entries.random().key ticks = 0
isDiscovered = false spriteSpawned = false
if (firstStar && ShootingStarPlugin.getStoreFile().isNotEmpty()) {
// Replace default with stored values, if any
levelOrd = ShootingStarPlugin.getStoreFile().getInt("level", levelOrd)
level = ShootingStarType.values()[levelOrd]
location = ShootingStarPlugin.getStoreFile().getString("location", location)
isDiscovered = ShootingStarPlugin.getStoreFile().getBoolean("isDiscovered", false)
dustLeft = ShootingStarPlugin.getStoreFile().getInt("dustLeft", dustLeft)
ticks = ShootingStarPlugin.getStoreFile().getInt("ticks", ticks)
spriteSpawned = ShootingStarPlugin.getStoreFile().getBoolean("spriteSpawned", false)
} }
maxDust = level.totalStardust maxDust = level.totalStardust
dustLeft = level.totalStardust
starObject = Scenery(level.objectId, crash_locations.get(location)) starObject = Scenery(level.objectId, crash_locations.get(location))
}
ShootingStarPlugin.getStoreFile()["level"] = level.ordinal fun spawnSprite() {
ShootingStarPlugin.getStoreFile()["location"] = location selfBots.filter { it.isMining() }.forEach { it.sleep() }
ShootingStarPlugin.getStoreFile()["isDiscovered"] = false SceneryBuilder.remove(starObject)
isSpawned = false
ticks = 0 starSprite.location = starObject.location
firstStar = false starSprite.init()
spriteSpawned = true
ShootingStarPlugin.getStoreFile()["spriteSpawned"] = spriteSpawned
} }
fun clearSprite() { fun clearSprite() {
starSprite.clear() starSprite.clear()
spriteSpawned = false spriteSpawned = false
ShootingStarPlugin.getStoreFile()["spriteSpawned"] = spriteSpawned
} }
/** /**
@ -161,6 +171,7 @@ class ShootingStar(var level: ShootingStarType = ShootingStarType.values().rando
*/ */
fun decDust() { fun decDust() {
if(--dustLeft <= 0) degrade() if(--dustLeft <= 0) degrade()
ShootingStarPlugin.getStoreFile()["dustLeft"] = dustLeft
} }
/** /**
@ -220,4 +231,4 @@ enum class ShootingStarType(val objectId: Int, val exp: Int, val totalStardust:
LEVEL_7(38662, 114, 40, 0.80), LEVEL_7(38662, 114, 40, 0.80),
LEVEL_8(38661, 145, 25, 0.85), LEVEL_8(38661, 145, 25, 0.85),
LEVEL_9(38660, 210, 15, 0.95); LEVEL_9(38660, 210, 15, 0.95);
} }

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,14 +50,14 @@ 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.experienceMutiplier * 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
return player.skills.getLevel(Skills.MINING) >= star.miningLevel return player.skills.getLevel(Skills.MINING) >= star.miningLevel
} }
if (player.skills.getLevel(Skills.MINING) < star.miningLevel) { if (player.skills.getLevel(Skills.MINING) < star.miningLevel) {
player.dialogueInterpreter.sendDialogue("You need a Mining level of at least " + star.miningLevel + " in order to mine this layer.") player.dialogueInterpreter.sendDialogue("You need a Mining level of at least " + star.miningLevel + " in order to mine this layer.")
return false return false
@ -87,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
@ -99,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)
} }
@ -129,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

@ -12,11 +12,11 @@ import core.ServerStore.Companion.getBoolean
import core.game.dialogue.DialogueFile import core.game.dialogue.DialogueFile
import core.game.interaction.InteractionListener import core.game.interaction.InteractionListener
import core.game.interaction.IntType import core.game.interaction.IntType
import core.tools.SystemLogger
import core.game.system.command.Privilege import core.game.system.command.Privilege
import core.game.world.GameWorld import core.game.world.GameWorld
import core.tools.Log import core.tools.Log
import core.tools.secondsToTicks import core.tools.secondsToTicks
import content.data.Quests
class ShootingStarPlugin : LoginListener, InteractionListener, TickListener, Commands, StartupListener { class ShootingStarPlugin : LoginListener, InteractionListener, TickListener, Commands, StartupListener {
override fun login(player: Player) { override fun login(player: Player) {
@ -27,14 +27,30 @@ class ShootingStarPlugin : LoginListener, InteractionListener, TickListener, Com
override fun tick() { override fun tick() {
++star.ticks ++star.ticks
// Check if the current star sprite should expire
val maxDelay = tickDelay + (tickDelay / 3) val maxDelay = tickDelay + (tickDelay / 3)
if(star.ticks > maxDelay && star.spriteSpawned){ if(star.ticks > maxDelay && star.spriteSpawned){
star.clearSprite() star.clearSprite()
} }
if ((star.ticks >= tickDelay && !star.spriteSpawned) || (!star.isSpawned && !star.spriteSpawned)) { if (star.firstStar && !star.isSpawned && !star.spriteSpawned) {
// Apparently, the server has only just booted
star.rebuildVars()
if (star.spriteSpawned) {
star.spawnSprite()
} else {
star.fire()
}
star.firstStar = false
}
// Check if it's time to fire a new one
if (star.ticks >= tickDelay && !star.spriteSpawned) {
star.rebuildVars()
star.fire() star.fire()
} }
getStoreFile()["ticks"] = star.ticks
} }
override fun defineListeners() { override fun defineListeners() {
@ -66,35 +82,52 @@ class ShootingStarPlugin : LoginListener, InteractionListener, TickListener, Com
return@on true return@on true
} }
val condition: (Player) -> Boolean = when(star.location.toLowerCase()){ class RingDialogue(val star: ShootingStar) : DialogueFile() {
"canifis bank" -> { p -> hasRequirement(p, "Priest in Peril") } val shouldWarn = when (star.location) {
//"Burgh de Rott bank" -> { p -> p.questRepository.isComplete("Priest in Peril")} // for now, require this as it is in Morytania. remove when appropriate quests added - Crash "North Edgeville mining site",
"crafting guild" -> {p -> hasLevelStat(p, Skills.CRAFTING, 40) } "Southern wilderness mine",
"lletya bank" -> {p -> hasRequirement(p, "Mourning's End Part I") } "Wilderness hobgoblin mine",
"jatizso mine" -> {p -> hasRequirement(player, "Fremennik Trials") } "Pirates' Hideout mine",
"south crandor mining site" -> {p -> hasRequirement(p, "Dragon Slayer") } "Lava Maze mining site",
"shilo village mining site" -> {p -> hasRequirement(p, "Shilo Village") } "Mage Arena bank" -> true
"mos le'harmless bank" -> {p -> hasRequirement(p, "Cabin Fever") } else -> false
else -> {_ -> true} }
override fun handle(componentID: Int, buttonID: Int) {
fun teleportToStar(player: Player) {
val condition: (p: Player) -> Boolean = when (star.location.toLowerCase()) {
"canifis bank" -> {p -> requireQuest(p, Quests.PRIEST_IN_PERIL, "to access this.")}
//"burgh de rott bank" -> {p -> hasRequirement(p, Quests.IN_AID_OF_THE_MYREQUE)} //disabled: crash
"crafting guild" -> {p -> hasLevelStat(p, Skills.CRAFTING, 40)}
"lletya bank" -> {p -> hasRequirement(p, Quests.MOURNINGS_END_PART_I)}
"jatizso mine" -> {p -> hasRequirement(p, Quests.THE_FREMENNIK_ISLES)}
"south crandor mining site" -> {p -> hasRequirement(p, Quests.DRAGON_SLAYER)}
"shilo village mining site" -> {p -> hasRequirement(p, Quests.SHILO_VILLAGE)}
"mos le'harmless bank" -> {p -> hasRequirement(p, Quests.CABIN_FEVER)} //needs to be updated to check for completion when the quest releases; https://runescape.wiki/w/Mos_Le%27Harmless?oldid=913025
"lunar isle mine" -> {p -> hasRequirement(p, Quests.LUNAR_DIPLOMACY)}
"miscellania coal mine" -> {p -> requireQuest(p, Quests.THE_FREMENNIK_TRIALS, "to access this.")}
//"neitiznot runite mine" -> {p -> hasRequirement(p, Quests.THE_FREMENNIK_ISLES)} //disabled: currently not reachable
else -> {_ -> true}
}
if (!condition.invoke(player)) {
sendDialogue(player,"Magical forces prevent your teleportation.")
} else if (teleport(player, star.crash_locations[star.location]!!.transform(0, -1, 0), TeleportManager.TeleportType.MINIGAME)) {
getRingStoreFile()[player.username.toLowerCase()] = true
}
}
when (stage) {
0 -> dialogue(if (star.spriteSpawned) "The star sprite has already been freed." else "The star sprite is still trapped.").also { if (shouldWarn) stage++ else stage += 2 }
1 -> dialogue("WARNING: The star is located in the wilderness.").also { stage++ }
2 -> player.dialogueInterpreter.sendOptions("Teleport to the star?", "Yes", "No").also { stage++ }
3 -> when (buttonID) {
1 -> end().also { teleportToStar(player) }
2 -> end()
}
}
}
} }
if(!condition.invoke(player)){ openDialogue(player, RingDialogue(star))
sendDialogue(player, "Magical forces prevent your teleportation.")
return@on true
}
val shouldWarn = when(star.location){
"North Edgeville mining site",
"Southern wilderness mine",
"Wilderness hobgoblin mine",
"Pirates' Hideout mine",
"Lava Maze mining site",
"Mage Arena bank" -> true
else -> false
}
openDialogue(player, RingDialogue(shouldWarn, star))
return@on true return@on true
} }
} }
@ -105,6 +138,7 @@ class ShootingStarPlugin : LoginListener, InteractionListener, TickListener, Com
} }
define("submit", Privilege.ADMIN) { _, _ -> define("submit", Privilege.ADMIN) { _, _ ->
star.rebuildVars()
star.fire() star.fire()
} }
@ -119,26 +153,6 @@ class ShootingStarPlugin : LoginListener, InteractionListener, TickListener, Com
private data class ScoreboardEntry(val player: String, val time: Int) private data class ScoreboardEntry(val player: String, val time: Int)
private class RingDialogue(val shouldWarn: Boolean, val star: ShootingStar) : DialogueFile(){
override fun handle(componentID: Int, buttonID: Int) {
when (stage) {
0 -> dialogue(if (star.spriteSpawned) "The star sprite has already been freed." else "The star sprite is still trapped.").also { if (shouldWarn) stage++ else stage += 2 }
1 -> dialogue("WARNING: The star is located in the wilderness.").also { stage++ }
2 -> player!!.dialogueInterpreter.sendOptions("Teleport to the star?", "Yes", "No").also { stage++ }
3 -> when (buttonID) {
1 -> teleport(player!!, star).also { end() }
2 -> end()
}
}
}
fun teleport(player: Player, star: ShootingStar){
if (teleport(player, star.crash_locations[star.location]!!.transform(0, -1, 0), TeleportManager.TeleportType.MINIGAME)) {
getRingStoreFile()[player.username.toLowerCase()] = true
}
}
}
companion object { companion object {
private val star = ShootingStar() private val star = ShootingStar()
private val tickDelay = if(GameWorld.settings?.isDevMode == true) 200 else 25000 private val tickDelay = if(GameWorld.settings?.isDevMode == true) 200 else 25000

View file

@ -82,7 +82,7 @@ class StarSpriteDialogue(player: Player? = null) : core.game.dialogue.DialoguePl
override fun handle(interfaceId: Int, buttonId: Int): Boolean { override fun handle(interfaceId: Int, buttonId: Int): Boolean {
when (stage) { when (stage) {
0 -> { 0 -> {
npc("I'm a star sprite! I Was in my star in the sky, when it", "lost control and crashed into the ground. With half my", "star sticking into the ground, I became stuck.", "Fortunately, I was mined out by the kind creatures of") npc("I'm a star sprite! I was in my star in the sky, when it", "lost control and crashed into the ground. With half my", "star sticking into the ground, I became stuck.", "Fortunately, I was mined out by the kind creatures of")
stage++ stage++
} }
1 -> { 1 -> {

View file

@ -0,0 +1,58 @@
package content.global.ame
import core.ServerConstants
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.link.TeleportManager.TeleportType
import core.game.world.map.Location
import core.game.world.update.flag.context.Graphics
import org.rs09.consts.Sounds
fun kidnapPlayer(npc: NPC, player: Player, dest: Location, playerLine: String? = null, callback: (player: Player, npc: NPC) -> Unit) {
val lockDuration = if (playerLine != null) 4 else 6
lock(player, lockDuration)
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)
}
}
}
fun returnPlayer(player: Player) {
player.locks.unlockTeleport()
val destination = getAttribute(player, "/save:original-loc", ServerConstants.HOME_LOCATION)
teleport(player, destination!!)
unlock(player)
removeAttributes(player, "/save:original-loc", "kidnapped-by-random")
}

View file

@ -1,11 +1,18 @@
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.setAttribute
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.combat.CombatStyle
import core.game.node.entity.impl.PulseType import core.game.node.entity.impl.PulseType
import core.game.node.entity.npc.NPC import core.game.node.entity.npc.NPC
import core.game.node.entity.npc.agg.AggressiveBehavior
import core.game.node.entity.npc.agg.AggressiveHandler
import core.game.node.entity.player.Player import core.game.node.entity.player.Player
import core.game.node.item.Item import core.game.node.item.Item
import core.game.world.map.Location import core.game.world.map.Location
@ -13,10 +20,13 @@ 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.api.utils.WeightBasedTable 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.min
import kotlin.random.Random import kotlin.random.Random
import kotlin.reflect.full.createInstance import kotlin.reflect.full.createInstance
@ -36,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
} }
@ -66,7 +77,6 @@ abstract class RandomEventNPC(id: Int) : NPC(id) {
if (!player.getAttribute("random:pause", false)) { if (!player.getAttribute("random:pause", false)) {
ticksLeft-- ticksLeft--
} }
if (!pulseManager.hasPulseRunning() && !finalized) { if (!pulseManager.hasPulseRunning() && !finalized) {
follow() follow()
} }
@ -87,10 +97,14 @@ abstract class RandomEventNPC(id: Int) : NPC(id) {
location = spawnLocation location = spawnLocation
player.setAttribute("re-npc", this) player.setAttribute("re-npc", this)
super.init() super.init()
super.aggressiveHandler = AggressiveHandler(this, object : AggressiveBehavior() {
override fun canSelectTarget(entity: Entity, target: Entity): Boolean {
return target == player
}
})
} }
open fun onTimeUp() { open fun onTimeUp() {
noteAndTeleport()
terminate() terminate()
} }
@ -118,4 +132,38 @@ abstract class RandomEventNPC(id: Int) : NPC(id) {
} }
abstract fun talkTo(npc: NPC) abstract fun talkTo(npc: NPC)
}
override fun isAttackable(entity: Entity, style: CombatStyle, message: Boolean): Boolean {
if (entity != player) {
if (entity is Player) {
sendMessage(entity, "It isn't interested in fighting you.") //TODO authentic message
}
return false
}
return super.isAttackable(entity, style, message)
}
fun idForCombatLevel(ids: List<Int>, player: Player): Int {
val index = min(ids.size, ceil(player.properties.currentCombatLevel / 20.0).toInt()) - 1
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,19 +1,28 @@
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.SeargentDamienNPC import content.global.ame.events.drilldemon.SergeantDamienNPC
import content.global.ame.events.drunkendwarf.DrunkenDwarfNPC
import content.global.ame.events.evilbob.EvilBobNPC import content.global.ame.events.evilbob.EvilBobNPC
import content.global.ame.events.evilchicken.EvilChickenNPC 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.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.rickturpentine.RickTurpentineNPC
import content.global.ame.events.rivertroll.RiverTrollRENPC import content.global.ame.events.rivertroll.RiverTrollRENPC
import content.global.ame.events.rockgolem.RockGolemRENPC import content.global.ame.events.rockgolem.RockGolemRENPC
import content.global.ame.events.quizmaster.QuizMasterNPC
import content.global.ame.events.sandwichlady.SandwichLadyRENPC import content.global.ame.events.sandwichlady.SandwichLadyRENPC
import content.global.ame.events.shade.ShadeRENPC import content.global.ame.events.shade.ShadeRENPC
import content.global.ame.events.strangeplant.StrangePlantNPC
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
@ -22,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),
@ -39,12 +49,19 @@ enum class RandomEvents(val npc: RandomEventNPC, val loot: WeightBasedTable? = n
WeightedItem(Items.TOOTH_HALF_OF_A_KEY_985,1,1,0.1), WeightedItem(Items.TOOTH_HALF_OF_A_KEY_985,1,1,0.1),
WeightedItem(Items.LOOP_HALF_OF_A_KEY_987,1,1,0.1) WeightedItem(Items.LOOP_HALF_OF_A_KEY_987,1,1,0.1)
)), )),
DRILL_DEMON(npc = SeargentDamienNPC()), MAZE(npc = MazeNPC()),
DRILL_DEMON(npc = SergeantDamienNPC()),
EVIL_CHICKEN(npc = EvilChickenNPC()), EVIL_CHICKEN(npc = EvilChickenNPC()),
STRANGE_PLANT(npc = StrangePlantNPC()),
SWARM(npc = SwarmNPC()),
EVIL_BOB(npc = EvilBobNPC(), skillIds = intArrayOf(Skills.FISHING, Skills.MAGIC)), EVIL_BOB(npc = EvilBobNPC(), skillIds = intArrayOf(Skills.FISHING, Skills.MAGIC)),
DRUNKEN_DWARF(npc = DrunkenDwarfNPC()),
RICK_TURPENTINE(npc = RickTurpentineNPC(), loot = CERTER.loot),
SURPRISE_EXAM(npc = MysteriousOldManNPC(), type = "sexam"), SURPRISE_EXAM(npc = MysteriousOldManNPC(), type = "sexam"),
FREAKY_FORESTER(npc = FreakyForesterNPC(), skillIds = intArrayOf(Skills.WOODCUTTING)), FREAKY_FORESTER(npc = FreakyForesterNPC(), skillIds = intArrayOf(Skills.WOODCUTTING)),
PILLORY(npc = PilloryNPC(), skillIds = intArrayOf(Skills.THIEVING)),
TREE_SPIRIT(npc = TreeSpiritRENPC(), skillIds = intArrayOf(Skills.WOODCUTTING)), TREE_SPIRIT(npc = TreeSpiritRENPC(), skillIds = intArrayOf(Skills.WOODCUTTING)),
QUIZ_MASTER(npc = QuizMasterNPC()),
RIVER_TROLL(RiverTrollRENPC(), skillIds = intArrayOf(Skills.FISHING)), RIVER_TROLL(RiverTrollRENPC(), skillIds = intArrayOf(Skills.FISHING)),
ROCK_GOLEM(RockGolemRENPC(), skillIds = intArrayOf(Skills.MINING)), ROCK_GOLEM(RockGolemRENPC(), skillIds = intArrayOf(Skills.MINING)),
SHADE(ShadeRENPC(), skillIds = intArrayOf(Skills.PRAYER)), SHADE(ShadeRENPC(), skillIds = intArrayOf(Skills.PRAYER)),
@ -68,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)
@ -77,5 +97,4 @@ enum class RandomEvents(val npc: RandomEventNPC, val loot: WeightBasedTable? = n
} }
} }
} }
} }

View file

@ -0,0 +1,20 @@
package content.global.ame.events
import core.api.getAttribute
import core.game.node.entity.Entity
import core.game.node.entity.npc.NPC
import core.game.node.entity.npc.NPCBehavior
import org.rs09.consts.NPCs
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.RIVER_TROLL_391, NPCs.RIVER_TROLL_392, NPCs.RIVER_TROLL_393, NPCs.RIVER_TROLL_394, NPCs.RIVER_TROLL_395, NPCs.RIVER_TROLL_396,
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.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 {
val xprate = super.getXpMultiplier(self, attacker)
return if (getAttribute(self, "spawned-by-ame", false)) xprate / 16.0 else xprate
}
}

View file

@ -1,41 +0,0 @@
package content.global.ame.events
import core.game.node.entity.player.Player
import content.global.ame.events.supriseexam.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 +0,0 @@
package content.global.ame.events
import content.global.ame.RandomEventNPC
import core.game.node.entity.npc.NPC
import core.tools.RandomFunction
import org.rs09.consts.NPCs
import core.api.utils.WeightBasedTable
class MysteriousOldManNPC(var type: String = "", override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.MYSTERIOUS_OLD_MAN_410) {
override fun init() {
super.init()
sayLine()
}
override fun tick() {
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) {
when(type){
"sexam" -> player.dialogueInterpreter.open(MysteriousOldManDialogue("sexam"),this.asNpc())
}
}
}

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

@ -79,7 +79,7 @@ class DrillDemonListeners : InteractionListener, MapArea {
} }
override fun getRestrictions(): Array<ZoneRestriction> { override fun getRestrictions(): Array<ZoneRestriction> {
return arrayOf(ZoneRestriction.RANDOM_EVENTS, ZoneRestriction.CANNON, ZoneRestriction.FOLLOWERS) return arrayOf(ZoneRestriction.RANDOM_EVENTS, ZoneRestriction.CANNON, ZoneRestriction.FOLLOWERS, ZoneRestriction.OFF_MAP)
} }
override fun areaEnter(entity: Entity) { override fun areaEnter(entity: Entity) {
@ -90,4 +90,4 @@ class DrillDemonListeners : InteractionListener, MapArea {
setComponentVisibility(entity.asPlayer(), 746, 12, true) setComponentVisibility(entity.asPlayer(), 746, 12, true)
} }
} }
} }

View file

@ -1,8 +1,9 @@
package content.global.ame.events.drilldemon package content.global.ame.events.drilldemon
import content.global.ame.returnPlayer
import core.api.* import core.api.*
import core.game.interaction.QueueStrength
import core.game.node.entity.player.Player import core.game.node.entity.player.Player
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
@ -10,7 +11,6 @@ import org.rs09.consts.NPCs
object DrillDemonUtils { object DrillDemonUtils {
val DD_KEY_TASK = "/save:drilldemon:task" val DD_KEY_TASK = "/save:drilldemon:task"
val DD_KEY_RETURN_LOC = "/save:drilldemon:original-loc"
val DD_SIGN_VARP = 531 val DD_SIGN_VARP = 531
val DD_SIGN_JOG = 0 val DD_SIGN_JOG = 0
val DD_SIGN_SITUP = 1 val DD_SIGN_SITUP = 1
@ -18,26 +18,18 @@ object DrillDemonUtils {
val DD_SIGN_JUMP = 3 val DD_SIGN_JUMP = 3
val DD_CORRECT_OFFSET = "/save:drilldemon:offset" val DD_CORRECT_OFFSET = "/save:drilldemon:offset"
val DD_CORRECT_COUNTER = "/save:drilldemon:numcorrect" val DD_CORRECT_COUNTER = "/save:drilldemon:numcorrect"
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){ fun changeSignsAndAssignTask(player: Player) {
setAttribute(player, DD_KEY_RETURN_LOC,player.location)
teleport(player, Location.create(3163, 4819, 0))
player.interfaceManager.closeDefaultTabs()
setComponentVisibility(player, 548, 69, true)
setComponentVisibility(player, 746, 12, true)
}
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()
val tempOffsetList = arrayListOf(1335, 1336, 1337, 1338).shuffled().toMutableList() val tempOffsetList = arrayListOf(1335, 1336, 1337, 1338).shuffled().toMutableList()
val task = tempList.random() val task = tempList.random()
val taskOffset = tempOffsetList.random() val taskOffset = tempOffsetList.random()
setAttribute(player, DD_KEY_TASK,task) setAttribute(player, DD_KEY_TASK, task)
setAttribute(player, DD_CORRECT_OFFSET,taskOffset) setAttribute(player, DD_CORRECT_OFFSET, taskOffset)
tempList.remove(task) tempList.remove(task)
tempOffsetList.remove(taskOffset) tempOffsetList.remove(taskOffset)
@ -47,7 +39,7 @@ object DrillDemonUtils {
} }
} }
fun getVarbitForId(id: Int): Int{ fun getVarbitForId(id: Int): Int {
return when (id) { return when (id) {
10076 -> 1335 10076 -> 1335
10077 -> 1336 10077 -> 1336
@ -57,18 +49,13 @@ object DrillDemonUtils {
} }
} }
fun getMatTask(id: Int, player: Player): Int{ fun getMatTask(id: Int, player: Player): Int {
return getVarbit(player, getVarbitForId(id)) return getVarbit(player, getVarbitForId(id))
} }
fun cleanup(player: Player) { fun cleanup(player: Player) {
player.locks.unlockTeleport() returnPlayer(player)
unlock(player) removeAttributes(player, DD_KEY_TASK, DD_CORRECT_OFFSET, DD_CORRECT_COUNTER)
teleport(player, getAttribute(player, DD_KEY_RETURN_LOC, Location.create(3222, 3218, 0)))
removeAttribute(player, DD_KEY_RETURN_LOC)
removeAttribute(player, DD_KEY_TASK)
removeAttribute(player, DD_CORRECT_OFFSET)
removeAttribute(player, DD_CORRECT_COUNTER)
player.interfaceManager.openDefaultTabs() player.interfaceManager.openDefaultTabs()
setComponentVisibility(player, 548, 69, false) setComponentVisibility(player, 548, 69, false)
setComponentVisibility(player, 746, 12, false) setComponentVisibility(player, 746, 12, false)
@ -85,14 +72,17 @@ object DrillDemonUtils {
} }
fun reward(player: Player) { fun reward(player: Player) {
val hasHat = hasAnItem(player, Items.CAMO_HELMET_6656).container != null queueScript(player, 2, QueueStrength.SOFT) {
val hasShirt = hasAnItem(player, Items.CAMO_TOP_6654).container != null val hasHat = hasAnItem(player, Items.CAMO_HELMET_6656).container != null
val hasPants = hasAnItem(player, Items.CAMO_BOTTOMS_6655).container != null val hasShirt = hasAnItem(player, Items.CAMO_TOP_6654).container != null
when { val hasPants = hasAnItem(player, Items.CAMO_BOTTOMS_6655).container != null
!hasHat -> addItemOrDrop(player, Items.CAMO_HELMET_6656) when {
!hasShirt -> addItemOrDrop(player, Items.CAMO_TOP_6654) !hasHat -> addItemOrDrop(player, Items.CAMO_HELMET_6656)
!hasPants -> addItemOrDrop(player, Items.CAMO_BOTTOMS_6655) !hasShirt -> addItemOrDrop(player, Items.CAMO_TOP_6654)
else -> addItemOrDrop(player, Items.COINS_995, 500) !hasPants -> addItemOrDrop(player, Items.CAMO_BOTTOMS_6655)
else -> addItemOrDrop(player, Items.COINS_995, 500)
}
return@queueScript stopExecuting(player)
} }
} }
} }

View file

@ -1,10 +1,11 @@
package content.global.ame.events.drilldemon package content.global.ame.events.drilldemon
import core.api.* import core.api.getAttribute
import core.api.sendItemDialogue
import core.api.unlock
import core.game.dialogue.DialogueFile import core.game.dialogue.DialogueFile
import core.game.dialogue.FacialExpression import core.game.dialogue.FacialExpression
import core.game.node.entity.npc.NPC import core.game.node.entity.npc.NPC
import core.tools.END_DIALOGUE import core.tools.END_DIALOGUE
import org.rs09.consts.Items import org.rs09.consts.Items
import org.rs09.consts.NPCs import org.rs09.consts.NPCs

View file

@ -1,38 +0,0 @@
package content.global.ame.events.drilldemon
import core.game.node.entity.npc.NPC
import org.rs09.consts.NPCs
import content.global.ame.RandomEventNPC
import core.api.*
import core.api.utils.WeightBasedTable
import core.game.interaction.QueueStrength
import core.game.system.timer.impl.AntiMacro
import core.tools.secondsToTicks
class SeargentDamienNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.SERGEANT_DAMIEN_2790) {
override fun init() {
super.init()
sendChat(player.username.capitalize() + "! Drop and give me 20!")
queueScript(player, 4, QueueStrength.SOFT) { stage: Int ->
when (stage) {
0 -> {
lock(player, secondsToTicks(30))
DrillDemonUtils.teleport(player)
AntiMacro.terminateEventNpc(player)
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)
}
}
}
override fun talkTo(npc: NPC) {
openDialogue(player, SeargentDamienDialogue(), npc)
}
}

View file

@ -0,0 +1,28 @@
package content.global.ame.events.drilldemon
import core.game.node.entity.npc.NPC
import org.rs09.consts.NPCs
import content.global.ame.RandomEventNPC
import content.global.ame.kidnapPlayer
import core.api.*
import core.api.utils.WeightBasedTable
import core.game.world.map.Location
class SergeantDamienNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.SERGEANT_DAMIEN_2790) {
override fun init() {
super.init()
sendChat("${player.username}! Drop and give me 20!")
face(player)
kidnapPlayer(this, player, Location(3163, 4819, 0)) { player, _ ->
player.interfaceManager.closeDefaultTabs()
setComponentVisibility(player, 548, 69, true)
setComponentVisibility(player, 746, 12, true)
openDialogue(player, SeargentDamienDialogue(isCorrect = true, eventStart = true), NPCs.SERGEANT_DAMIEN_2790)
}
}
override fun talkTo(npc: NPC) {
openDialogue(player, SeargentDamienDialogue(), npc)
}
}

View file

@ -0,0 +1,14 @@
package content.global.ame.events.drunkendwarf
import core.game.node.entity.Entity
import core.game.node.entity.combat.BattleState
import core.game.node.entity.npc.NPC
import core.game.node.entity.npc.NPCBehavior
import core.tools.RandomFunction
import org.rs09.consts.NPCs
class DrunkenDwarfBehavior : NPCBehavior(NPCs.DRUNKEN_DWARF_956) {
override fun beforeAttackFinalized(self: NPC, victim: Entity, state: BattleState) {
state.estimatedHit = RandomFunction.getRandom(3)
}
}

View file

@ -0,0 +1,21 @@
package content.global.ame.events.drunkendwarf
import core.api.addItemOrDrop
import core.game.dialogue.DialogueFile
import core.game.dialogue.FacialExpression
import core.game.system.timer.impl.AntiMacro
import org.rs09.consts.Items
class DrunkenDwarfDialogue : DialogueFile() {
override fun handle(componentID: Int, buttonID: Int) {
when (stage) {
0 -> npcl(FacialExpression.OLD_DRUNK_RIGHT, "I 'new it were you matey! 'Ere, have some ob the good stuff!").also { stage++ }
1 -> {
addItemOrDrop(player!!, Items.BEER_1917)
addItemOrDrop(player!!, Items.KEBAB_1971)
AntiMacro.terminateEventNpc(player!!)
end()
}
}
}
}

View file

@ -0,0 +1,48 @@
package content.global.ame.events.drunkendwarf
import content.global.ame.RandomEventNPC
import core.api.*
import core.api.utils.WeightBasedTable
import core.game.node.entity.npc.NPC
import core.tools.RandomFunction
import org.rs09.consts.NPCs
import org.rs09.consts.Sounds
class DrunkenDwarfNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.DRUNKEN_DWARF_956) {
lateinit var phrases: Array<String>
private var attackDelay = 0
override fun init() {
super.init()
phrases = arrayOf(
"'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() {
sayLine(this, phrases, true, true)
if (ticksLeft <= 10) {
ticksLeft = 10
if (attackDelay <= getWorldTicks()) {
this.attack(player)
}
}
super.tick()
}
override fun talkTo(npc: NPC) {
attackDelay = getWorldTicks() + 10
this.pulseManager.clear()
openDialogue(player, DrunkenDwarfDialogue(), this.asNpc())
}
override fun onTimeUp() {
if (attackDelay <= getWorldTicks()) {
this.attack(player)
}
}
}

View file

@ -22,10 +22,8 @@ class EvilBobDialogue(val rewardDialogue: Boolean = false, val rewardXpSkill: In
} else if (getAttribute(player!!, EvilBobUtils.eventComplete, false)) { } else if (getAttribute(player!!, EvilBobUtils.eventComplete, false)) {
sendDialogue(player!!, "Evil Bob appears to be sleeping, best not to wake him up.").also { stage = END_DIALOGUE } sendDialogue(player!!, "Evil Bob appears to be sleeping, best not to wake him up.").also { stage = END_DIALOGUE }
} else if (removeItem(player!!, Items.RAW_FISHLIKE_THING_6200)) { } else if (removeItem(player!!, Items.RAW_FISHLIKE_THING_6200)) {
setAttribute(player!!, EvilBobUtils.fishCaught, false)
playerl(FacialExpression.NEUTRAL, "Here, I've brought you some fish.").also { stage = 500 } playerl(FacialExpression.NEUTRAL, "Here, I've brought you some fish.").also { stage = 500 }
} else if (removeItem(player!!, Items.RAW_FISHLIKE_THING_6204)) { } else if (removeItem(player!!, Items.RAW_FISHLIKE_THING_6204)) {
setAttribute(player!!, EvilBobUtils.fishCaught, false)
setAttribute(player!!, EvilBobUtils.attentive, true) setAttribute(player!!, EvilBobUtils.attentive, true)
setAttribute(player!!, EvilBobUtils.attentiveNewSpot, true) setAttribute(player!!, EvilBobUtils.attentiveNewSpot, true)
playerl(FacialExpression.NEUTRAL, "Here, I've brought you some fish.").also { stage = 600 } playerl(FacialExpression.NEUTRAL, "Here, I've brought you some fish.").also { stage = 600 }

View file

@ -1,5 +1,7 @@
package content.global.ame.events.evilbob package content.global.ame.events.evilbob
import content.global.ame.returnPlayer
import core.ServerConstants
import core.api.* import core.api.*
import core.game.dialogue.FacialExpression import core.game.dialogue.FacialExpression
import core.game.interaction.IntType import core.game.interaction.IntType
@ -7,8 +9,6 @@ import core.game.interaction.InteractionListener
import core.game.interaction.QueueStrength import core.game.interaction.QueueStrength
import core.game.node.entity.Entity import core.game.node.entity.Entity
import core.game.node.entity.player.link.emote.Emotes import core.game.node.entity.player.link.emote.Emotes
import core.game.node.entity.skill.Skills
import core.game.system.task.Pulse
import core.game.world.map.Location import core.game.world.map.Location
import core.game.world.map.zone.ZoneBorders import core.game.world.map.zone.ZoneBorders
import core.game.world.map.zone.ZoneRestriction import core.game.world.map.zone.ZoneRestriction
@ -36,7 +36,8 @@ class EvilBobListeners : InteractionListener, MapArea {
sendNPCDialogue(player, NPCs.SERVANT_2481, "You'll need a fishing net. There are plenty scattered around the beach.", FacialExpression.SAD) sendNPCDialogue(player, NPCs.SERVANT_2481, "You'll need a fishing net. There are plenty scattered around the beach.", FacialExpression.SAD)
} else if (freeSlots(player) == 0) { } else if (freeSlots(player) == 0) {
sendDialogue(player, "You don't have enough space in your inventory.") sendDialogue(player, "You don't have enough space in your inventory.")
} else if (getAttribute(player, EvilBobUtils.fishCaught, false)) { } else if (inInventory(player, Items.FISHLIKE_THING_6202) || inInventory(player, Items.FISHLIKE_THING_6206) ||
inInventory(player, Items.RAW_FISHLIKE_THING_6200) || inInventory(player, Items.RAW_FISHLIKE_THING_6204)) {
sendNPCDialogue(player, NPCs.SERVANT_2481, "You've already got a fish. Come over here to uncook it, then serve it to Evil Bob.", FacialExpression.SAD) sendNPCDialogue(player, NPCs.SERVANT_2481, "You've already got a fish. Come over here to uncook it, then serve it to Evil Bob.", FacialExpression.SAD)
} else { } else {
lock(player, 6) lock(player, 6)
@ -67,7 +68,6 @@ class EvilBobListeners : InteractionListener, MapArea {
} }
sendItemDialogue(player, Items.FISHLIKE_THING_6202, "You catch a... what is this?? Is this a fish?? And it's cooked already??") sendItemDialogue(player, Items.FISHLIKE_THING_6202, "You catch a... what is this?? Is this a fish?? And it's cooked already??")
resetAnimator(player) resetAnimator(player)
setAttribute(player, EvilBobUtils.fishCaught, true)
} }
} }
return@on true return@on true
@ -119,8 +119,8 @@ class EvilBobListeners : InteractionListener, MapArea {
return@queueScript delayScript(player, 2) return@queueScript delayScript(player, 2)
} }
3 -> { 3 -> {
sendMessage(player, "Welcome back to 2009Scape.") sendMessage(player, "Welcome back to ${ServerConstants.SERVER_NAME}.")
teleport(player, getAttribute(player, EvilBobUtils.prevLocation, Location.create(3222, 3219, 0))) returnPlayer(player)
EvilBobUtils.reward(player) EvilBobUtils.reward(player)
EvilBobUtils.cleanup(player) EvilBobUtils.cleanup(player)
resetAnimator(player) resetAnimator(player)
@ -138,11 +138,11 @@ class EvilBobListeners : InteractionListener, MapArea {
} }
override fun getRestrictions(): Array<ZoneRestriction> { override fun getRestrictions(): Array<ZoneRestriction> {
return arrayOf(ZoneRestriction.RANDOM_EVENTS, ZoneRestriction.CANNON, ZoneRestriction.FOLLOWERS) return arrayOf(ZoneRestriction.RANDOM_EVENTS, ZoneRestriction.CANNON, ZoneRestriction.FOLLOWERS, ZoneRestriction.OFF_MAP)
} }
override fun areaEnter(entity: Entity) { override fun areaEnter(entity: Entity) {
entity.locks.lockTeleport(1000000) entity.locks.lockTeleport(1000000)
} }
} }

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

@ -3,7 +3,6 @@ package content.global.ame.events.evilbob
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.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
@ -13,10 +12,8 @@ import org.rs09.consts.NPCs
import org.rs09.consts.Scenery import org.rs09.consts.Scenery
object EvilBobUtils { object EvilBobUtils {
const val prevLocation = "/save:evilbob:prevlocation"
const val eventComplete = "/save:evilbob:eventcomplete" const val eventComplete = "/save:evilbob:eventcomplete"
const val assignedFishingZone = "/save:evilbob:fishingzone" const val assignedFishingZone = "/save:evilbob:fishingzone"
const val fishCaught = "evilbob:fishcaught"
const val attentive = "/save:evilbob:attentive" const val attentive = "/save:evilbob:attentive"
const val servantHelpDialogueSeen = "/save:evilbob:servantdialogeseen" const val servantHelpDialogueSeen = "/save:evilbob:servantdialogeseen"
const val attentiveNewSpot = "/save:evilbob:attentivenewspot" const val attentiveNewSpot = "/save:evilbob:attentivenewspot"
@ -52,15 +49,8 @@ object EvilBobUtils {
} }
} }
fun teleport(player: Player) {
setAttribute(player, prevLocation, player.location)
player.properties.teleportLocation = Location.create(3419, 4776, 0)
}
fun cleanup(player: Player) { fun cleanup(player: Player) {
player.locks.unlockTeleport() removeAttributes(player, assignedFishingZone, eventComplete, attentive, servantHelpDialogueSeen, attentiveNewSpot, startingDialogueSeen)
player.properties.teleportLocation = getAttribute(player, prevLocation, null)
removeAttributes(player, assignedFishingZone, eventComplete, prevLocation, attentive, servantHelpDialogueSeen, attentiveNewSpot, startingDialogueSeen)
removeAll(player, Items.FISHLIKE_THING_6202) removeAll(player, Items.FISHLIKE_THING_6202)
removeAll(player, Items.FISHLIKE_THING_6202, Container.BANK) removeAll(player, Items.FISHLIKE_THING_6202, Container.BANK)
removeAll(player, Items.FISHLIKE_THING_6206) removeAll(player, Items.FISHLIKE_THING_6206)

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,5 +1,6 @@
package content.global.ame.events.evilbob package content.global.ame.events.evilbob
import core.ServerConstants
import core.api.getAttribute import core.api.getAttribute
import core.api.setAttribute import core.api.setAttribute
import core.game.dialogue.DialogueFile import core.game.dialogue.DialogueFile
@ -34,7 +35,7 @@ class ServantDialogue : DialogueFile() {
} }
} }
2 -> npcl(FacialExpression.SAD, "Come? Come where?").also { stage++ } 2 -> npcl(FacialExpression.SAD, "Come? Come where?").also { stage++ }
3 -> playerl(FacialExpression.FRIENDLY, "Away from this place! To 2009Scape proper!").also { stage++ } 3 -> playerl(FacialExpression.FRIENDLY, "Away from this place! To ${ServerConstants.SERVER_NAME} proper!").also { stage++ }
4 -> npcl(FacialExpression.SAD, "You go, ${player!!.username}, I don't belong there... I belong here, in Scape2009. This is the only place I can ever go...").also { stage++ } 4 -> npcl(FacialExpression.SAD, "You go, ${player!!.username}, I don't belong there... I belong here, in Scape2009. This is the only place I can ever go...").also { stage++ }
5 -> options("But I love you!", "Oh alright then.").also { stage++ } 5 -> options("But I love you!", "Oh alright then.").also { stage++ }
6 -> when(buttonID) { 6 -> when(buttonID) {
@ -54,4 +55,4 @@ class ServantDialogue : DialogueFile() {
} }
} }
} }
} }

View file

@ -9,9 +9,8 @@ import core.tools.RandomFunction
import org.rs09.consts.Items import org.rs09.consts.Items
import content.global.ame.RandomEventNPC import content.global.ame.RandomEventNPC
import core.api.utils.WeightBasedTable import core.api.utils.WeightBasedTable
import java.lang.Integer.max
val ids = 2463..2468 val ids = (2463..2468).toList()
class EvilChickenNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(2463) { class EvilChickenNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(2463) {
val phrases = arrayOf("Bwuk","Bwuk bwuk bwuk","Flee from me, @name!","Begone, @name!","Bwaaaauuuk bwuk bwuk","MUAHAHAHAHAAA!") val phrases = arrayOf("Bwuk","Bwuk bwuk bwuk","Flee from me, @name!","Begone, @name!","Bwaaaauuuk bwuk bwuk","MUAHAHAHAHAAA!")
@ -19,8 +18,7 @@ class EvilChickenNPC(override var loot: WeightBasedTable? = null) : RandomEventN
override fun init() { override fun init() {
super.init() super.init()
val index = max(0, (player.properties.combatLevel / 20) - 1) val id = idForCombatLevel(ids, player)
val id = ids.toList()[index]
this.transform(id) this.transform(id)
this.attack(player) this.attack(player)
sendChat(phrases.random().replace("@name",player.username.capitalize())) sendChat(phrases.random().replace("@name",player.username.capitalize()))

View file

@ -57,10 +57,10 @@ class FreakListeners : InteractionListener, MapArea {
} }
override fun getRestrictions(): Array<ZoneRestriction> { override fun getRestrictions(): Array<ZoneRestriction> {
return arrayOf(ZoneRestriction.RANDOM_EVENTS, ZoneRestriction.CANNON, ZoneRestriction.FOLLOWERS) return arrayOf(ZoneRestriction.RANDOM_EVENTS, ZoneRestriction.CANNON, ZoneRestriction.FOLLOWERS, ZoneRestriction.OFF_MAP)
} }
override fun areaEnter(entity: Entity) { override fun areaEnter(entity: Entity) {
entity.locks.lockTeleport(1000000) entity.locks.lockTeleport(1000000)
} }
} }

View file

@ -1,16 +1,15 @@
package content.global.ame.events.freakyforester package content.global.ame.events.freakyforester
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.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
object FreakUtils{ object FreakUtils{
const val freakNpc = NPCs.FREAKY_FORESTER_2458 const val freakNpc = NPCs.FREAKY_FORESTER_2458
const val freakPreviousLoc = "/save:freakyf:location"
const val freakTask = "/save:freakyf:task" const val freakTask = "/save:freakyf:task"
const val freakComplete = "/save:freakyf:complete" const val freakComplete = "/save:freakyf:complete"
const val pheasantKilled = "freakyf:killed" const val pheasantKilled = "freakyf:killed"
@ -26,15 +25,9 @@ object FreakUtils{
player.dialogueInterpreter.open(FreakyForesterDialogue(), freakNpc) player.dialogueInterpreter.open(FreakyForesterDialogue(), freakNpc)
} }
fun teleport(player: Player) {
setAttribute(player, freakPreviousLoc, player.location)
teleport(player, Location.create(2599, 4777 ,0))
}
fun cleanup(player: Player) { fun cleanup(player: Player) {
player.locks.unlockTeleport() returnPlayer(player)
player.properties.teleportLocation = getAttribute(player,freakPreviousLoc,null) removeAttributes(player, freakTask, freakComplete, pheasantKilled)
removeAttributes(player, freakPreviousLoc, freakTask, freakComplete, pheasantKilled)
removeAll(player, Items.RAW_PHEASANT_6178) removeAll(player, Items.RAW_PHEASANT_6178)
removeAll(player, Items.RAW_PHEASANT_6178, Container.BANK) removeAll(player, Items.RAW_PHEASANT_6178, Container.BANK)
removeAll(player, Items.RAW_PHEASANT_6179) removeAll(player, Items.RAW_PHEASANT_6179)

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

@ -0,0 +1,276 @@
package content.global.ame.events.maze
import content.global.ame.returnPlayer
import core.api.*
import core.api.utils.WeightBasedTable
import core.api.utils.WeightedItem
import core.game.event.EventHook
import core.game.event.TickEvent
import core.game.global.action.DoorActionHandler
import core.game.interaction.IntType
import core.game.interaction.InteractionListener
import core.game.interaction.QueueStrength
import core.game.node.entity.Entity
import core.game.node.entity.player.Player
import core.game.system.task.Pulse
import core.game.world.GameWorld.Pulser
import core.game.world.map.Location
import core.game.world.map.zone.ZoneBorders
import core.game.world.map.zone.ZoneRestriction
import core.game.world.update.flag.context.Graphics
import org.rs09.consts.*
class MazeInterface : InteractionListener, EventHook<TickEvent>, MapArea {
companion object {
const val MAZE_TIMER_INTERFACE = Components.MAZETIMER_209
const val MAZE_TIMER_VARP = 531 // Interface 209 child 2 config: [531, 0]
const val MAZE_ATTRIBUTE_TICKS_LEFT = "maze:percent-ticks-left"
const val MAZE_ATTRIBUTE_CHESTS_OPEN = "/save:maze:chests-opened"
val STARTING_POINTS = arrayOf(
Location(2928, 4553, 0),
Location(2917, 4553, 0),
Location(2908, 4555, 0),
Location(2891, 4589, 0),
Location(2891, 4595, 0),
Location(2891, 4595, 0),
Location(2926, 4597, 0),
Location(2931, 4597, 0),
// There's 2 more, but there isn't a door for them...
)
val REWARD_ITEM = intArrayOf(
Items.COINS_995,
Items.FEATHER_314,
Items.IRON_ARROW_884,
Items.CHAOS_RUNE_562,
Items.STEEL_ARROW_886,
Items.DEATH_RUNE_560,
Items.COAL_454,
Items.NATURE_RUNE_561,
Items.MITHRIL_ORE_448
)
val ITEM_DIVISOR = arrayOf(
1.0,
2.0,
3.0,
9.0,
12.0,
18.0,
45.0,
162.0,
180.0,
)
val CHEST_REWARDS = WeightBasedTable.create(
WeightedItem(Items.AIR_RUNE_556,15,15,1.0),
WeightedItem(Items.WATER_RUNE_555,10,10,1.0),
WeightedItem(Items.EARTH_RUNE_557,10,10,1.0),
WeightedItem(Items.FIRE_RUNE_554,10,10,1.0),
WeightedItem(Items.BRONZE_ARROW_882,20,20,1.0),
WeightedItem(Items.BRONZE_BOLTS_877,10,10,1.0),
WeightedItem(Items.IRON_ARROW_884,15,15,1.0),
WeightedItem(Items.ATTACK_POTION2_123,1,1,1.0),
WeightedItem(Items.STRENGTH_POTION2_117,1,1,1.0),
WeightedItem(Items.DEFENCE_POTION2_135,1,1,1.0),
)
fun initMaze(player: Player) {
setAttribute(player, MAZE_ATTRIBUTE_TICKS_LEFT, 300)
setVarp(player, MAZE_TIMER_VARP, (getAttribute<Int>(player, MAZE_ATTRIBUTE_TICKS_LEFT, 0) / 3),false)
openOverlay(player, MAZE_TIMER_INTERFACE)
sendMessage(player, "You need to reach the maze center, then you'll be returned to where you were.")
sendNPCDialogue(player, NPCs.MYSTERIOUS_OLD_MAN_410, "You need to reach the maze center, then you'll be returned to where you were.")
}
fun calculateLoot(player: Player) {
val randomNumber = (0..8).random()
val totalLevel = player.getSkills().totalLevel.toDouble()
val rewardPotential = getAttribute(player, MAZE_ATTRIBUTE_TICKS_LEFT, 0).toDouble() / 300.0
val itemDivisor = ITEM_DIVISOR[randomNumber]
val itemQuantity = (totalLevel * rewardPotential * 3.33) / itemDivisor
// sendMessage(player, "Maze reward calculation: $totalLevel * $rewardPotential * 3.33 / $itemDivisor = $itemQuantity")
if (itemQuantity.toInt() > 0) {
addItemOrDrop(player, REWARD_ITEM[randomNumber], itemQuantity.toInt())
}
}
/**
* Chest Location to rotation mapping.
* This is needed as it is impossible to obtain the underlying chest scenery for the rotation.
* 0: Facing North, 1: Facing East, 2: Facing South, 3: Facing West
*/
val chestLocationRotationMap = mapOf(
Location(2930, 4595, 0).toString() to 2,
Location(2924, 4572, 0).toString() to 2,
Location(2925, 4573, 0).toString() to 0,
Location(2900, 4578, 0).toString() to 2,
Location(2901, 4560, 0).toString() to 1,
Location(2890, 4599, 0).toString() to 2,
Location(2896, 4591, 0).toString() to 2,
Location(2895, 4592, 0).toString() to 1,
Location(2901, 4560, 0).toString() to 3,
Location(2918, 4590, 0).toString() to 1,
Location(2917, 4590, 0).toString() to 3,
)
/**
* Chest Interaction workaround
*
* The issue here is that the walls(3626) of the Maze are overlapping some(not all) chest sceneries.
*
* The types for the wallScenery:
* Type 0 - flat panel |
* Type 2 - right angle panel with rotation 0:r 1:7 2:> 3:L
* Type 3 - corner post . for angle edges of walls
*/
fun overrideScenery(wallScenery: core.game.node.scenery.Scenery, chestSceneryId: Int): core.game.node.scenery.Scenery {
if (wallScenery.id == chestSceneryId) {
replaceScenery(wallScenery, Scenery.CHEST_3636, 30)
wallScenery.isActive = true
return wallScenery // Return the chest scenery as the wallScenery isn't there.
}
addScenery(Scenery.CHEST_3636, wallScenery.location, chestLocationRotationMap[wallScenery.location.toString()] ?: 0, 10)
addScenery(wallScenery)
// replaceScenery(newChestScenery, Scenery.CHEST_3636, 3) // didn't work for an underlying scenery
// I did a world pulse since everyone will get to see the chest open.
Pulser.submit(object : Pulse(30) {
override fun pulse(): Boolean {
addScenery(Scenery.CHEST_3635, wallScenery.location, chestLocationRotationMap[wallScenery.location.toString()] ?: 0, 10)
addScenery(wallScenery)
return true
}
})
// Return the chest scenery to replace PacketProcessor so that MISMATCH will not happen.
return core.game.node.scenery.Scenery(
chestSceneryId,
wallScenery.location,
chestLocationRotationMap[wallScenery.location.toString()] ?: 0
)
}
}
override fun defineListeners() {
// This somehow doesn't trigger as the scenery.id != objId (3626 != 3635)
on(Scenery.CHEST_3635, IntType.SCENERY, "open") { player, node ->
if (getAttribute(player, MAZE_ATTRIBUTE_TICKS_LEFT, 0) > 0 && getAttribute(player, MAZE_ATTRIBUTE_CHESTS_OPEN, 0) < 10) {
animate(player, 536)
// val actualScenery = RegionManager.getObject(node.location.z, node.location.x, node.location.y, 3626)
val tableRoll = CHEST_REWARDS.roll()
addItemOrBank(player, tableRoll[0].id, tableRoll[0].amount)
when (tableRoll[0].id){
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.EARTH_RUNE_557 -> sendItemDialogue(player, Items.EARTH_RUNE_557, "You've found some earth runes!")
Items.FIRE_RUNE_554 -> sendItemDialogue(player, Items.FIRE_RUNE_554, "You've found some fire runes!")
Items.BRONZE_ARROW_882 -> sendItemDialogue(player, Items.BRONZE_ARROW_882, "You've found some bronze arrows!")
Items.BRONZE_BOLTS_877 -> sendItemDialogue(player, Items.BRONZE_BOLTS_877, "You've found some bronze bolts!")
Items.IRON_ARROW_884 -> sendItemDialogue(player, Items.IRON_ARROW_884, "You've found some iron arrows!")
Items.ATTACK_POTION2_123 -> sendItemDialogue(player, Items.ATTACK_POTION2_123, "You've found an attack potion!")
Items.STRENGTH_POTION2_117 -> sendItemDialogue(player, Items.STRENGTH_POTION2_117, "You've found a strength potion!")
Items.DEFENCE_POTION2_135 -> sendItemDialogue(player, Items.DEFENCE_POTION2_135, "You've found a defence potion!")
}
setAttribute(player, MAZE_ATTRIBUTE_CHESTS_OPEN, getAttribute(player, MAZE_ATTRIBUTE_CHESTS_OPEN, 0))
} else {
sendMessage(player,"You find nothing of interest.")
}
return@on true
}
on(Scenery.CHEST_3636, SCENERY, "search") { player, node ->
sendMessage(player,"You find nothing of interest.")
return@on true
}
on(Scenery.WALL_3626, IntType.SCENERY, "open") { player, node ->
sendMessage(player, "That bit doesn't open.") // 0xBrLo9woIY
return@on true
}
on(Scenery.WALL_3628, IntType.SCENERY, "open") { player, node ->
// Door opening workaround
// Ignore 3629(WALL_3629) and 3630(WALL_3630) in handleAutowalkDoor ignoreSecondDoor
DoorActionHandler.handleAutowalkDoor(player, node as core.game.node.scenery.Scenery)
return@on true
}
on(Scenery.STRANGE_SHRINE_3634, IntType.SCENERY, "touch") { player, node ->
player.unhook(this)
lock(player, 12)
closeOverlay(player)
queueScript(player, 0, QueueStrength.SOFT) { stage: Int ->
when (stage) {
0 -> {
sendGraphics(Graphics(86, 0, 3), player.location)
animate(player,862)
return@queueScript delayScript(player, 6)
}
1 -> {
sendGraphics(Graphics(1576, 0, 0), player.location)
animate(player,8939)
playAudio(player, Sounds.TELEPORT_ALL_200)
return@queueScript delayScript(player, 3)
}
2 -> {
returnPlayer(player)
sendGraphics(Graphics(1577, 0, 0), player.location)
animate(player,8941)
closeOverlay(player)
return@queueScript delayScript(player, 1)
}
3 -> {
calculateLoot(player)
removeAttribute(player, MAZE_ATTRIBUTE_TICKS_LEFT)
removeAttribute(player, MAZE_ATTRIBUTE_CHESTS_OPEN)
return@queueScript stopExecuting(player)
}
else -> return@queueScript stopExecuting(player)
}
}
return@on true
}
}
override fun process(entity: Entity, event: TickEvent) {
if (entity is Player) {
if (getAttribute(entity, MAZE_ATTRIBUTE_TICKS_LEFT, 0) > 0) {
setAttribute(entity, MAZE_ATTRIBUTE_TICKS_LEFT, getAttribute(entity, MAZE_ATTRIBUTE_TICKS_LEFT, 0) - 1)
}
setVarp(entity, MAZE_TIMER_VARP, (getAttribute(entity, MAZE_ATTRIBUTE_TICKS_LEFT, 0) / 3), false)
}
}
override fun defineAreaBorders(): Array<ZoneBorders> {
return arrayOf(getRegionBorders(11591))
}
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) {
sendMessage(entity, "Head for the center of the maze.")
entity.interfaceManager.removeTabs(0, 1, 2, 3, 4, 5, 6, 12)
openOverlay(entity, MAZE_TIMER_INTERFACE)
}
}
override fun areaLeave(entity: Entity, logout: Boolean) {
if (entity is Player) {
entity.interfaceManager.restoreTabs()
closeOverlay(entity)
entity.unhook(this)
}
}
override fun entityStep(entity: Entity, location: Location, lastLocation: Location) {
if (entity is Player) {
entity.hook(Event.Tick, this)
}
}
}

View file

@ -0,0 +1,32 @@
package content.global.ame.events.maze
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 org.rs09.consts.NPCs
class MazeNPC(var type: String = "", override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.MYSTERIOUS_OLD_MAN_410) {
override fun init() {
super.init()
sendChat("Aha, you'll do ${player.username}!")
face(player)
// 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(this, player, MazeInterface.STARTING_POINTS.random()) { player, _ ->
MazeInterface.initMaze(player)
removeAttribute(player, MazeInterface.MAZE_ATTRIBUTE_CHESTS_OPEN)
}
}
override fun talkTo(npc: NPC) {
sendMessage(player, "He isn't interested in talking to you.")
}
}

View file

@ -0,0 +1,219 @@
package content.global.ame.events.pillory
import content.global.ame.RandomEvents
import content.global.ame.returnPlayer
import core.api.*
import core.game.dialogue.FacialExpression
import core.game.interaction.IntType
import core.game.interaction.InteractionListener
import core.game.node.entity.player.Player
import core.game.interaction.InterfaceListener
import core.game.interaction.QueueStrength
import core.game.node.entity.Entity
import core.game.world.map.Location
import core.game.world.map.zone.ZoneBorders
import core.game.world.map.zone.ZoneRestriction
import core.game.world.update.flag.context.Graphics
import org.rs09.consts.NPCs
import org.rs09.consts.Scenery
import org.rs09.consts.Sounds
/**
* Pillory Unlocking Interface PILLORY_189
*
* https://www.youtube.com/watch?v=caWn7pE2mkE
* https://www.youtube.com/watch?v=TMVR5cZZwZ0
* https://www.youtube.com/watch?v=Ym9LCDP-Q74
* https://www.youtube.com/watch?v=_vn0QZTtI6U (Failure)
* https://www.youtube.com/watch?v=zmXDikQIua4
*
* Child IDs
* 4 - Rotating Lock Model
* 5 6 7 - Swinging Keys Models
* 8 9 10 - Buttons for the Swinging Keys Models
* 11 12 13 14 15 16 - Padlocks at the Top
* 17 18 19 20 21 22 - Padlocks stars? Model 15272, Anim 4135
*
* Model IDs
* Using the amazeballs ::listifmodels
* 9749, 9750, 9751, 9752 - Swinging Keys Models
* 9753, 9754, 9755, 9756 - Rotating Lock Models
* 9757 9758 locked unlock
*/
class PilloryInterface : InterfaceListener, InteractionListener, MapArea {
companion object {
const val PILLORY_LOCK_INTERFACE = 189
const val PILLORY_ATTRIBUTE_EVENT_KEYS = "pillory:event-keys"
const val PILLORY_ATTRIBUTE_EVENT_LOCK = "pillory:event-lock"
const val PILLORY_ATTRIBUTE_NEEDED_TO_GET_CORRECT = "/save:pillory:target-correct"
const val PILLORY_ATTRIBUTE_CORRECT_COUNTER = "/save:pillory:num-correct"
val LOCATIONS = arrayOf(
// Varrock Cages
Location(3226, 3407, 0),
Location(3228, 3407, 0),
Location(3230, 3407, 0),
// Seers Village Cages
Location(2681, 3489, 0),
Location(2683, 3489, 0),
Location(2685, 3489, 0),
// Yannile Cages
Location(2604, 3105, 0),
Location(2606, 3105, 0),
Location(2608, 3105, 0),
)
fun initPillory(player: Player) {
setAttribute(player, PILLORY_ATTRIBUTE_NEEDED_TO_GET_CORRECT, 3)
setAttribute(player, PILLORY_ATTRIBUTE_CORRECT_COUNTER, 0)
player.dialogueInterpreter.sendPlainMessage(true, "", "Solve the pillory puzzle to be returned to where you came from.")
}
fun randomPillory(player: Player) {
// Shuffle all 4 kinds of keys in, pick 3 for the keys, pick 1 from the 3 as the lock.
val keys = (0..3).toIntArray().let{ keys -> keys.shuffle(); return@let keys }
val lock = intArrayOf(keys[1], keys[2], keys[3]).random() // Last 3 as there are 4 keys. key[0] is fallback.
setAttribute(player, PILLORY_ATTRIBUTE_EVENT_KEYS, keys)
setAttribute(player, PILLORY_ATTRIBUTE_EVENT_LOCK, lock)
player.packetDispatch.sendModelOnInterface(9753 + lock, PILLORY_LOCK_INTERFACE, 4, 0)
player.packetDispatch.sendModelOnInterface(9749 + keys[1], PILLORY_LOCK_INTERFACE, 5, 0)
player.packetDispatch.sendModelOnInterface(9749 + keys[2], PILLORY_LOCK_INTERFACE, 6, 0)
player.packetDispatch.sendModelOnInterface(9749 + keys[3], PILLORY_LOCK_INTERFACE, 7, 0)
val numberToGetCorrect = getAttribute(player, PILLORY_ATTRIBUTE_NEEDED_TO_GET_CORRECT, 3)
val correctCount = getAttribute(player, PILLORY_ATTRIBUTE_CORRECT_COUNTER, 0)
for (i in 1.. 6) {
// Set if lock is red or green.
if (i <= correctCount) {
player.packetDispatch.sendModelOnInterface(9758, PILLORY_LOCK_INTERFACE, 10 + i, 0)
} else {
player.packetDispatch.sendModelOnInterface(9757, PILLORY_LOCK_INTERFACE, 10 + i, 0)
}
// Set if hide or show lock.
player.packetDispatch.sendInterfaceConfig(PILLORY_LOCK_INTERFACE, 10 + i, i > numberToGetCorrect)
}
}
fun selectedKey(player: Player, buttonID: Int) {
val keys = getAttribute(player, PILLORY_ATTRIBUTE_EVENT_KEYS, intArrayOf(0, 0, 0))
val lock = getAttribute(player, PILLORY_ATTRIBUTE_EVENT_LOCK, -1)
if (keys[buttonID] == lock) {
// CORRECT ANSWER
setAttribute(player, PILLORY_ATTRIBUTE_CORRECT_COUNTER, getAttribute(player, PILLORY_ATTRIBUTE_CORRECT_COUNTER, 0) + 1)
if (getAttribute(player, PILLORY_ATTRIBUTE_NEEDED_TO_GET_CORRECT, 3) <= getAttribute(player, PILLORY_ATTRIBUTE_CORRECT_COUNTER, -1)) {
player.dialogueInterpreter.sendPlainMessage(true, "", "You've escaped!")
sendMessage(player, "You've escaped!")
removeAttribute(player, PILLORY_ATTRIBUTE_NEEDED_TO_GET_CORRECT)
removeAttribute(player, PILLORY_ATTRIBUTE_CORRECT_COUNTER)
closeInterface(player)
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 -> {
val loot = RandomEvents.CERTER.loot!!.roll(player)[0]
addItemOrDrop(player, loot.id, loot.amount)
returnPlayer(player)
sendGraphics(Graphics(1577, 0, 0), player.location)
animate(player,8941)
closeInterface(player)
return@queueScript stopExecuting(player)
}
else -> return@queueScript stopExecuting(player)
}
}
return
}
randomPillory(player)
player.dialogueInterpreter.sendPlainMessage(
true,
"",
"Correct!",
"" + getAttribute(player, PILLORY_ATTRIBUTE_CORRECT_COUNTER, 0) + " down, " +
(getAttribute(player, PILLORY_ATTRIBUTE_NEEDED_TO_GET_CORRECT, 3) - getAttribute(player, PILLORY_ATTRIBUTE_CORRECT_COUNTER, 0)) + " to go!")
// Animation for the star, but it doesn't work.
player.packetDispatch.sendInterfaceConfig(PILLORY_LOCK_INTERFACE, 16 + getAttribute(player, PILLORY_ATTRIBUTE_CORRECT_COUNTER, 1), false)
sendAnimationOnInterface(player, 4135, PILLORY_LOCK_INTERFACE, 16 + getAttribute(player, PILLORY_ATTRIBUTE_CORRECT_COUNTER, 1))
} else {
// WRONG ANSWER
player.dialogueInterpreter.close()
player.dialogueInterpreter.sendDialogues(NPCs.TRAMP_2794 , FacialExpression.OLD_ANGRY1, "Bah, that's not right.","Use the key that matches the hole", "in the spinning lock.")
if (getAttribute(player, PILLORY_ATTRIBUTE_NEEDED_TO_GET_CORRECT, 0) < 6) {
setAttribute(player, PILLORY_ATTRIBUTE_NEEDED_TO_GET_CORRECT, getAttribute(player, PILLORY_ATTRIBUTE_NEEDED_TO_GET_CORRECT, 0) + 1)
}
setAttribute(player, PILLORY_ATTRIBUTE_CORRECT_COUNTER, 0)
closeInterface(player)
}
}
}
override fun defineInterfaceListeners() {
on(PILLORY_LOCK_INTERFACE){ player, component, opcode, buttonID, slot, itemID ->
when (buttonID) {
8 -> selectedKey(player, 1)
9 -> selectedKey(player, 2)
10 -> selectedKey(player, 3)
}
return@on true
}
onOpen(PILLORY_LOCK_INTERFACE){ player, component ->
return@onOpen true
}
}
override fun defineListeners() {
on(Scenery.CAGE_6836, IntType.SCENERY, "unlock") { player, node ->
if (player.location in LOCATIONS) { // When you aren't inside.
randomPillory(player)
openInterface(player, PILLORY_LOCK_INTERFACE)
player.dialogueInterpreter.sendPlainMessage(true, "", "Pick the <col=8A0808>swinging key</col> that matches the", "hole in the <col=8A0808>spinning lock</col>.")
} else {
sendMessage(player, "You can't unlock the pillory, you'll let all the prisoners out!")
}
return@on true
}
}
override fun defineAreaBorders(): Array<ZoneBorders> {
return arrayOf(
// Varrock Cages
ZoneBorders(3226, 3407, 3226, 3407),
ZoneBorders(3228, 3407, 3228, 3407),
ZoneBorders(3230, 3407, 3230, 3407),
// Seers Village Cages
ZoneBorders(2681, 3489, 2681, 3489),
ZoneBorders(2683, 3489, 2683, 3489),
ZoneBorders(2685, 3489, 2685, 3489),
// Yannile Cages
ZoneBorders(2604, 3105, 2604, 3105),
ZoneBorders(2606, 3105, 2606, 3105),
ZoneBorders(2608, 3105, 2608, 3105),
)
}
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) {
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,25 @@
package content.global.ame.events.pillory
import content.global.ame.RandomEventNPC
import content.global.ame.kidnapPlayer
import core.api.*
import core.api.utils.WeightBasedTable
import core.game.component.Component.setUnclosable
import core.game.node.entity.npc.NPC
import org.rs09.consts.NPCs
class PilloryNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.PILLORY_GUARD_2791) {
override fun init() {
super.init()
sendChat("${player.username}, you're under arrest!")
face(player)
kidnapPlayer(this, player, PilloryInterface.LOCATIONS.random()) { player, _ ->
PilloryInterface.initPillory(player)
setUnclosable(player, player.dialogueInterpreter.sendPlainMessage(true, "", "Solve the pillory puzzle to be returned to where you came from."))
}
}
override fun talkTo(npc: NPC) {
sendMessage(player, "He isn't interested in talking to you.")
}
}

View file

@ -0,0 +1,37 @@
package content.global.ame.events.quizmaster
import core.api.*
import core.game.node.entity.Entity
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.game.world.map.Location
import core.game.world.map.zone.ZoneBorders
import core.game.world.map.zone.ZoneRestriction
import org.rs09.consts.NPCs
class QuizMasterBorders : MapArea {
override fun defineAreaBorders(): Array<ZoneBorders> {
return arrayOf(getRegionBorders(7754))
}
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) {
entity.interfaceManager.removeTabs(0, 1, 2, 3, 4, 5, 6, 12)
face(entity, Location(1952, 4768, 1))
animate(entity,2378)
openDialogue(entity, QuizMasterDialogueFile(), NPC(NPCs.QUIZ_MASTER_2477))
}
}
override fun areaLeave(entity: Entity, logout: Boolean) {
if (entity is Player) {
entity.interfaceManager.restoreTabs()
//closeOverlay(entity)
}
}
}

View file

@ -0,0 +1,152 @@
package content.global.ame.events.quizmaster
import content.global.ame.returnPlayer
import core.ServerConstants
import core.api.*
import core.api.utils.WeightBasedTable
import core.api.utils.WeightedItem
import core.game.component.Component
import core.game.dialogue.DialogueLabeller
import core.game.dialogue.DialogueOption
import core.game.dialogue.FacialExpression
import core.game.interaction.QueueStrength
import core.game.node.entity.player.Player
import org.rs09.consts.Components
import org.rs09.consts.Items
import org.rs09.consts.NPCs
class QuizMasterDialogueFile : DialogueLabeller() {
companion object {
const val QUIZMASTER_INTERFACE = Components.MACRO_QUIZSHOW_191
const val QUIZMASTER_ATTRIBUTE_QUESTIONS_CORRECT = "/save:quizmaster:questions-correct"
const val QUIZMASTER_ATTRIBUTE_RANDOM_ANSWER = "quizmaster:random-answer"
/*
// Golden Models:
8828 ADAMANT_BATTLEAXE_1371
8829 SALMON_329
8830 TROUT_333
8831 NECKLACE
8832 WOODEN_SHIELD_1171
8833 BRONZE_MED_HELM_1139
8834 RING
8835 SECATEURS_5329
8836 BRONZE_SWORD_1277
8837 GARDENING_TROWEL_5325
*/
val sets = arrayOf(
intArrayOf(8828, 8829, 8829),
intArrayOf(8831, 8837, 8835),
intArrayOf(8830, 8832, 8833),
intArrayOf(8835, 8834, 8831),
intArrayOf(8837, 8836, 8828),
)
fun randomQuestion(player: Player): Int {
val randomSet = intArrayOf(*sets.random())
val answer = intArrayOf(*randomSet)[0]
randomSet.shuffle()
val correctButton = randomSet.indexOf(answer) + 2 // buttons are 3,4,5
player.packetDispatch.sendModelOnInterface(randomSet[0], QUIZMASTER_INTERFACE, 6, 512)
player.packetDispatch.sendModelOnInterface(randomSet[1], QUIZMASTER_INTERFACE, 7, 512)
player.packetDispatch.sendModelOnInterface(randomSet[2], QUIZMASTER_INTERFACE, 8, 512)
player.packetDispatch.sendAngleOnInterface(QUIZMASTER_INTERFACE, 6, 512,0,0)
player.packetDispatch.sendAngleOnInterface(QUIZMASTER_INTERFACE, 7, 512,0,0)
player.packetDispatch.sendAngleOnInterface(QUIZMASTER_INTERFACE, 8, 512,0,0)
return correctButton
}
// Random Item should be "Mystery Box", but the current MYSTERY_BOX_6199 is already inauthentically used by Giftmas.
val tableRoll = WeightBasedTable.create(
WeightedItem(Items.LAMP_2528, 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.BUCKET_1925, 1, 1, 1.0, false),
WeightedItem(Items.FLIER_956, 1, 1, 1.0, false),
WeightedItem(Items.OLD_BOOT_685, 1, 1, 1.0, false),
WeightedItem(Items.BODY_RUNE_559, 1, 1, 1.0, false),
WeightedItem(Items.ONION_1957, 1, 1, 1.0, false),
WeightedItem(Items.MITHRIL_SCIMITAR_1329, 1, 1, 1.0, false),
WeightedItem(Items.CASKET_405, 1, 1, 1.0, false),
WeightedItem(Items.STEEL_PLATEBODY_1119, 1, 1, 1.0, false),
WeightedItem(Items.NATURE_RUNE_561, 20, 20, 1.0, false),
)
}
override fun addConversation() {
assignToIds(NPCs.QUIZ_MASTER_2477)
afterClose { player ->
loadLabel(player, "question")
}
npc(FacialExpression.FRIENDLY,"WELCOME to the GREATEST QUIZ SHOW in the", "whole of ${ServerConstants.SERVER_NAME}:", "<col=8A0808>O D D</col> <col=8A088A>O N E</col> <col=08088A>O U T</col>", unclosable = true)
player(FacialExpression.THINKING, "I'm sure I didn't ask to take part in a quiz show...", unclosable = true)
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")
label("question")
manual(unclosable = true) { player, _ ->
setAttribute(player, QUIZMASTER_ATTRIBUTE_RANDOM_ANSWER, randomQuestion(player))
val comp = Component(QUIZMASTER_INTERFACE)
player.interfaceManager.openChatbox(comp)
return@manual comp
}
exec { player, _ ->
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 {
goto("right")
}
} else {
goto("wrong")
}
}
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

@ -0,0 +1,39 @@
package content.global.ame.events.quizmaster
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
/**
* Quiz Master NPC:
*
* https://www.youtube.com/watch?v=EFAWSiPTfcM
* https://www.youtube.com/watch?v=caWn7pE2mkE
* https://www.youtube.com/watch?v=Bc1gAov2o4w
* https://www.youtube.com/watch?v=oHU8-MUarxE
* https://www.youtube.com/watch?v=wvjYiF4v9tI
* https://www.youtube.com/watch?v=dC6rlSnXEfw
*/
class QuizMasterNPC(var type: String = "", override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.QUIZ_MASTER_2477) {
override fun init() {
super.init()
sendChat("Hey ${player.username}! It's your lucky day!")
face(player)
kidnapPlayer(this, player, Location(1952, 4764, 0)) { player, _ ->
setAttribute(player, QuizMasterDialogueFile.QUIZMASTER_ATTRIBUTE_QUESTIONS_CORRECT, 0)
sendMessage(player, "Answer four questions correctly in a row to be teleported back where you came from.")
sendMessage(player, "You will need to relog in if you lose the quiz dialog.") // Inauthentic, but there to notify the player in case.
face(player, Location(1952, 4768, 1))
animate(player,2378)
// Quiz dialogue gets opened automatically on zone entry.
}
}
override fun talkTo(npc: NPC) {
openDialogue(player, QuizMasterDialogueFile(), this.asNpc())
}
}

View file

@ -0,0 +1,14 @@
package content.global.ame.events.rickturpentine
import core.game.node.entity.Entity
import core.game.node.entity.combat.BattleState
import core.game.node.entity.npc.NPC
import core.game.node.entity.npc.NPCBehavior
import core.tools.RandomFunction
import org.rs09.consts.NPCs
class RickTurpentineBehavior : NPCBehavior(NPCs.RICK_TURPENTINE_2476) {
override fun beforeAttackFinalized(self: NPC, victim: Entity, state: BattleState) {
state.estimatedHit = RandomFunction.getRandom(3)
}
}

View file

@ -0,0 +1,19 @@
package content.global.ame.events.rickturpentine
import core.api.addItemOrDrop
import core.game.dialogue.DialogueFile
import core.game.dialogue.FacialExpression
import core.game.system.timer.impl.AntiMacro
class RickTurpentineDialogue : DialogueFile() {
override fun handle(componentID: Int, buttonID: Int) {
when (stage) {
0 -> npcl(FacialExpression.NEUTRAL, "Today is your lucky day, " + (if (player!!.isMale) "sirrah!" else "madam!") + " I am donating to the victims of crime to atone for my past actions!").also { stage++ }
1 -> {
AntiMacro.rollEventLoot(player!!).forEach { addItemOrDrop(player!!, it.id, it.amount) }
AntiMacro.terminateEventNpc(player!!)
end()
}
}
}
}

View file

@ -0,0 +1,31 @@
package content.global.ame.events.rickturpentine
import content.global.ame.RandomEventNPC
import core.api.*
import core.api.utils.WeightBasedTable
import core.game.node.entity.npc.NPC
import org.rs09.consts.NPCs
class RickTurpentineNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.RICK_TURPENTINE_2476) {
private var attackDelay = 0
override fun init() {
super.init()
sendChat("Good day to you, " + (if(player.isMale) "milord " else "milady ") + player.username.capitalize() + ".")
}
override fun tick() {
if (ticksLeft <= 10) {
ticksLeft = 10
if (attackDelay <= getWorldTicks())
this.attack(player)
}
super.tick()
}
override fun talkTo(npc: NPC) {
attackDelay = getWorldTicks() + 10
this.pulseManager.clear()
openDialogue(player, RickTurpentineDialogue(), this.asNpc())
}
}

View file

@ -4,17 +4,14 @@ import core.game.node.entity.Entity
import core.game.node.entity.npc.NPC import core.game.node.entity.npc.NPC
import content.global.ame.RandomEventNPC import content.global.ame.RandomEventNPC
import core.api.utils.WeightBasedTable import core.api.utils.WeightBasedTable
import java.lang.Integer.max
val ids = (391..396).toList()
val ids = 391..396
class RiverTrollRENPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(391){ class RiverTrollRENPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(391){
override fun talkTo(npc: NPC) {} override fun talkTo(npc: NPC) {}
override fun init() { override fun init() {
super.init() super.init()
val index = max(0, (player.properties.combatLevel / 20) - 1) val id = idForCombatLevel(ids, player)
val id = ids.toList()[index]
this.transform(id) this.transform(id)
this.attack(player) this.attack(player)
sendChat("Fishies be mine, leave dem fishies!") sendChat("Fishies be mine, leave dem fishies!")

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

@ -4,17 +4,14 @@ import core.game.node.entity.Entity
import core.game.node.entity.npc.NPC import core.game.node.entity.npc.NPC
import content.global.ame.RandomEventNPC import content.global.ame.RandomEventNPC
import core.api.utils.WeightBasedTable import core.api.utils.WeightBasedTable
import kotlin.math.max
val ids = (413..418).toList()
val ids = 413..418
class RockGolemRENPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(413){ class RockGolemRENPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(413){
override fun talkTo(npc: NPC) {} override fun talkTo(npc: NPC) {}
override fun init() { override fun init() {
super.init() super.init()
val index = max(0,(player.properties.combatLevel / 20) - 1) val id = idForCombatLevel(ids, player)
val id = ids.toList()[index]
this.transform(id) this.transform(id)
this.attack(player) this.attack(player)
sendChat("Raarrrgghh! Flee human!") sendChat("Raarrrgghh! Flee human!")

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

@ -4,15 +4,13 @@ import core.game.node.entity.Entity
import core.game.node.entity.npc.NPC import core.game.node.entity.npc.NPC
import content.global.ame.RandomEventNPC import content.global.ame.RandomEventNPC
import core.api.utils.WeightBasedTable import core.api.utils.WeightBasedTable
import kotlin.math.*
class ShadeRENPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(425){ class ShadeRENPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(425){
val ids = (425..430).toList() val ids = (425..430).toList()
override fun talkTo(npc: NPC) {} override fun talkTo(npc: NPC) {}
override fun init() { override fun init() {
super.init() super.init()
val index = max(0, min(ids.size, (player.properties.combatLevel / 20) - 1)) val id = idForCombatLevel(ids, player)
val id = ids[index]
this.transform(id) this.transform(id)
this.attack(player) this.attack(player)
sendChat("Leave this place!") sendChat("Leave this place!")

View file

@ -0,0 +1,39 @@
package content.global.ame.events.strangeplant
import core.api.applyPoison
import core.game.node.entity.Entity
import core.game.node.entity.combat.BattleState
import core.game.node.entity.combat.CombatStyle
import core.game.node.entity.npc.NPC
import core.game.node.entity.npc.NPCBehavior
import core.game.node.entity.player.Player
import core.game.system.timer.impl.AntiMacro
import core.tools.RandomFunction
import org.rs09.consts.NPCs
class StrangePlantBehavior() : NPCBehavior(NPCs.STRANGE_PLANT_408) {
override fun canBeAttackedBy(self: NPC, attacker: Entity, style: CombatStyle, shouldSendMessage: Boolean): Boolean {
return !(attacker !is Player || AntiMacro.getEventNpc(attacker.asPlayer()) != self)
}
override fun beforeAttackFinalized(self: NPC, victim: Entity, state: BattleState) {
state.estimatedHit = RandomFunction.getRandom(3)
if (RandomFunction.roll(10))
applyPoison(victim, self, 10)
}
override fun beforeDamageReceived(self: NPC, attacker: Entity, state: BattleState) {
if (state.estimatedHit > 3)
state.estimatedHit = RandomFunction.getRandom(3)
if (state.secondaryHit > 3)
state.secondaryHit = RandomFunction.getRandom(3)
}
override fun onDeathStarted(self: NPC, killer: Entity) {
AntiMacro.terminateEventNpc(killer.asPlayer())
}
override fun getXpMultiplier(self: NPC, attacker: Entity): Double {
return super.getXpMultiplier(self, attacker) / 16.0
}
}

View file

@ -0,0 +1,33 @@
package content.global.ame.events.strangeplant
import core.api.addItemOrDrop
import core.api.getAttribute
import core.api.sendMessage
import core.api.setAttribute
import core.game.interaction.IntType
import core.game.interaction.InteractionListener
import core.game.system.timer.impl.AntiMacro
import org.rs09.consts.Items
import org.rs09.consts.NPCs
class StrangePlantListener : InteractionListener {
override fun defineListeners() {
on(NPCs.STRANGE_PLANT_407, IntType.NPC, "pick") { player, node ->
if (AntiMacro.getEventNpc(player) != node) {
sendMessage(player, "This isn't your strange plant.")
return@on true
}
if (!getAttribute(node.asNpc(), "fruit-grown", false)) {
sendMessage(player, "The fruit isn't ready to be picked.")
return@on true
}
if (!getAttribute(node.asNpc(), "fruit-picked", false)) {
setAttribute(node.asNpc(), "fruit-picked", true)
addItemOrDrop(player, Items.STRANGE_FRUIT_464)
}
return@on true
}
}
}

View file

@ -0,0 +1,85 @@
package content.global.ame.events.strangeplant
import content.global.ame.RandomEventNPC
import core.api.*
import core.api.utils.WeightBasedTable
import core.game.interaction.QueueStrength
import core.game.node.entity.npc.NPC
import core.game.world.update.flag.context.Animation
import core.tools.minutesToTicks
import core.tools.secondsToTicks
import org.rs09.consts.NPCs
class StrangePlantNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.STRANGE_PLANT_407) {
private val strangePlantGrowAnim = Animation(348)
private val strangePlantTransformAnim = Animation(351)
private val strangePlantPickedAnim = Animation(350)
private var fruitPicked = false
private var transformed = false
private var attacking = false
override fun init() {
spawnLocation = getPathableCardinal(player, player.location)
super.init()
ticksLeft = minutesToTicks(1)
animate(this, strangePlantGrowAnim)
queueScript(this, strangePlantGrowAnim.duration + 2, QueueStrength.SOFT) {
setAttribute(this, "fruit-grown", true)
return@queueScript stopExecuting(this)
}
}
override fun tick() {
super.tick()
if (getAttribute(this, "fruit-picked", false) && !fruitPicked) {
fruitPicked = true
ticksLeft = secondsToTicks(60)
queueScript(this, 1, QueueStrength.SOFT) { stage: Int ->
when (stage) {
0 -> {
this.animate(strangePlantPickedAnim)
return@queueScript delayScript(this, strangePlantPickedAnim.duration - 1)
}
1 -> {
this.isInvisible = true
terminate()
return@queueScript stopExecuting(this)
}
else -> return@queueScript stopExecuting(this)
}
}
}
if (ticksLeft <= secondsToTicks(10)) {
ticksLeft = secondsToTicks(10)
if (!attacking) {
attacking = true
queueScript(this, 1, QueueStrength.SOFT) { stage: Int ->
when (stage) {
0 -> {
animate(this, strangePlantTransformAnim)
return@queueScript delayScript(this, strangePlantTransformAnim.duration)
}
1 -> {
this.transform(NPCs.STRANGE_PLANT_408)
this.behavior = StrangePlantBehavior()
this.attack(player)
transformed = true
return@queueScript stopExecuting(this)
}
else -> return@queueScript stopExecuting(this)
}
}
}
if (transformed && !this.inCombat())
this.attack(player)
}
}
override fun follow() {
if (transformed)
super.follow()
}
override fun talkTo(npc: NPC) {
}
}

View file

@ -1,4 +1,4 @@
package content.global.ame.events.supriseexam package content.global.ame.events.surpriseexam
import core.game.component.Component import core.game.component.Component
import core.game.dialogue.FacialExpression import core.game.dialogue.FacialExpression

View file

@ -0,0 +1,24 @@
package content.global.ame.events.surpriseexam
import content.global.ame.RandomEventNPC
import content.global.ame.kidnapPlayer
import core.api.*
import org.rs09.consts.NPCs
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) {
override fun init() {
super.init()
sendChat("Surprise exam, ${player.username}!")
face(player)
kidnapPlayer(this, player, Location(1886, 5025, 0)) { _, _ ->
/* nothing needed */
}
}
override fun talkTo(npc: NPC) {
sendMessage(player, "He isn't interested in talking to you.")
}
}

View file

@ -1,4 +1,4 @@
package content.global.ame.events.supriseexam package content.global.ame.events.surpriseexam
import core.game.dialogue.DialogueFile import core.game.dialogue.DialogueFile
import core.tools.END_DIALOGUE import core.tools.END_DIALOGUE

View file

@ -1,4 +1,4 @@
package content.global.ame.events.supriseexam package content.global.ame.events.surpriseexam
import core.game.node.entity.npc.NPC import core.game.node.entity.npc.NPC
import org.rs09.consts.Components import org.rs09.consts.Components

View file

@ -1,28 +1,29 @@
package content.global.ame.events.supriseexam 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
import core.game.interaction.InteractionListener import core.game.interaction.InteractionListener
import core.game.interaction.IntType import core.game.interaction.IntType
import content.global.handlers.iface.ExperienceInterface import content.global.handlers.iface.ExperienceInterface
import core.api.MapArea
import core.api.removeItem
import core.game.world.map.zone.ZoneBorders
import core.game.world.map.zone.ZoneRestriction
class SupriseExamListeners : InteractionListener { class SupriseExamListeners : InteractionListener, MapArea {
val MORDAUT = NPCs.MR_MORDAUT_6117
val BOOK_OF_KNOWLEDGE = Items.BOOK_OF_KNOWLEDGE_11640
override fun defineListeners() { override fun defineListeners() {
on(MORDAUT, IntType.NPC, "talk-to"){ player, node -> on(NPCs.MR_MORDAUT_6117, IntType.NPC, "talk-to") { player, node ->
player.faceLocation(Location.create(1886, 5024, 0)) player.faceLocation(Location.create(1886, 5024, 0))
val examComplete = player.getAttribute(SurpriseExamUtils.SE_KEY_CORRECT,0) == 3 val examComplete = player.getAttribute(SurpriseExamUtils.SE_KEY_CORRECT, 0) == 3
player.dialogueInterpreter.open(MordautDialogue(examComplete),node.asNpc()) player.dialogueInterpreter.open(MordautDialogue(examComplete), node.asNpc())
return@on true return@on true
} }
on(SurpriseExamUtils.SE_DOORS, IntType.SCENERY, "open"){ player, node -> on(SurpriseExamUtils.SE_DOORS, IntType.SCENERY, "open") { player, node ->
val correctDoor = player.getAttribute(SurpriseExamUtils.SE_DOOR_KEY,-1) val correctDoor = player.getAttribute(SurpriseExamUtils.SE_DOOR_KEY,-1)
if(correctDoor == -1){ if(correctDoor == -1){
@ -39,9 +40,9 @@ class SupriseExamListeners : InteractionListener {
return@on true return@on true
} }
on(BOOK_OF_KNOWLEDGE, IntType.ITEM, "read"){ player, _ -> on(Items.BOOK_OF_KNOWLEDGE_11640, IntType.ITEM, "read") { player, _ ->
player.setAttribute("caller"){skill: Int,p: Player -> player.setAttribute("caller") { skill: Int, p: Player ->
if(p.inventory.remove(Item(BOOK_OF_KNOWLEDGE))) { if (removeItem(p, Items.BOOK_OF_KNOWLEDGE_11640)) {
val level = p.skills.getStaticLevel(skill) val level = p.skills.getStaticLevel(skill)
val experience = level * 15.0 val experience = level * 15.0
p.skills.addExperience(skill, experience) p.skills.addExperience(skill, experience)
@ -54,8 +55,16 @@ class SupriseExamListeners : InteractionListener {
} }
override fun defineDestinationOverrides() { override fun defineDestinationOverrides() {
setDest(IntType.NPC,MORDAUT){ _, _ -> setDest(IntType.NPC, NPCs.MR_MORDAUT_6117) { _, _ ->
return@setDest Location.create(1886, 5025, 0) return@setDest Location.create(1886, 5025, 0)
} }
} }
}
override fun defineAreaBorders(): Array<ZoneBorders> {
return arrayOf(ZoneBorders.forRegion(7502))
}
override fun getRestrictions(): Array<ZoneRestriction> {
return arrayOf(ZoneRestriction.RANDOM_EVENTS, ZoneRestriction.CANNON, ZoneRestriction.FOLLOWERS, ZoneRestriction.TELEPORT, ZoneRestriction.OFF_MAP)
}
}

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